GraphQL Federation Vocabulary: Apollo Federation and Supergraph Terms (англійською)
Підграф, суперграф, маршрутизатор, об’ єкт, директиви (@key/@external) і словник Apollo Federation для архітекторів GraphQL.
Якщо ви працюєте над розподіленими архітектурами GraphQL, ви майже напевно стикалися з густим нагромадженням технічних термінів, які на перший погляд можуть здатися вам нерозбірливими — підграф, суперграф, сутність, федерація. Ці слова мають певне значення у екосистемі Apollo, і правильний вибір їх означає, що ви розумієте, яким чином складаються і виконуються федеративні системи GraphQL. У цьому підручнику розгорнуто основний словник для федерації GraphQL, з реалістичними прикладами розмов розробників, які допоможуть вам зрозуміти кожен термін у контексті.
Основні терміни: федерація і графік
Федерація — архітектурний підхід, за якого декілька незалежних служб GraphQL (кожна з яких володіє частиною схеми) об’ єднуються в єдиний об’ єднаний API. Замість того, щоб підтримувати один монолітний сервер GraphQL, команди володіють окремими службами, які спільно утворюють послідовний графік.
“Ми відійшли від монолиту шість місяців тому. Тепер повна федерація — кожна команда домену володіє власним сервісом, і маршрутизатор з’єднує все це під час виконання.»
“Перед тим, як додати це поле, перевірте, який підграф повинен його мати. Федерація працює тільки тоді, коли межі власності є ясними»
** Суперграф ** — об’ єднана, складена схема, що утворюється у результаті поєднання всіх підграфів. З точки зору клієнта, суперграфік виглядає як один API GraphQL. Термін також відноситься до загальної системи: маршрутизатор, підграфи і конвеєр композиції разом.
«Клієнту не важливо, скільки підграфів існує — він просто запитує суперграф.»
“Наш суперграф наразі охоплює сім підграфів у трьох командах. Додавання нового вимагає перевірки композиції, перш ніж щось піде в виробництво»
** Subgraph ** — окрема служба GraphQL, яка надсилає частину схеми до суперграфа. Кожен підграф є автономною службою з власними розв’ язувачами, джерелами даних і циклом розгортання.
«
Productпідграф володіє всім, що стосується каталогу і цін. Якщо вам потрібно додати поле знижки, то PR йде до команди продуктів»
“Ми зберігаємо наші підграфи малими і фокусованими. Один підграф на обмежений контекст — він зберігає радіус вибуху зміни, що переривається, керованим»
** Складання схеми ** — процес об’ єднання декількох схем підграфів у одну коректну схему суперграфа. Композиція перевіряє сумісність схем, послідовність спільних типів і правильність застосування директив.
“Композиція знову зазнала невдачі. Схоже, що тип
Userв підграфі auth і підграфі accounts мають конфліктні визначення полів»
“Ми виконуємо композицію схеми в CI на кожному запиті pull. Потрапивши на помилки композиції до розгортання, ми зберегли багато болю»
Основна стаття: Граматика англійської мови
Директиви — це анотації, які вказують Apollo Router, як маршрутизувати запити, розв’ язувати посилання і спільно використовувати дані між межами підграфів. Зрозуміти їх дуже важливо для зневадження і проектування федеративних схем.
** @ key directive ** — позначає тип як ** об’ єкт ** і вказує, яке поле або поля унікальним чином ідентифікують екземпляр цього типу. Директива @key дозволяє посилатися на тип і розв’язувати його через межі підграфів.
«Вам потрібно додати
@key(fields: \"id\")до типуOrder, перш ніж підграф наповнення може розширити його»
«Ми використовуємо складний ключ на деяких об’єктах —
@key(fields: \"tenantId orderId\")— тому що жодне поле не є глобально унікальним»
** @ external directive ** — позначає поле типу, який визначено і належить іншому підграфу. Підграф використовує @external, щоб оголосити, що він знає, що поле існує, але не розв’язує його локально.
“Це поле
@externalв підграфі повідомлень — його розв’язує auth. Ми посилаємося на нього тільки тому, що ми можемо використовувати його в@requires. ”
“Не намагайтеся додати розв’язувач для поля
@external. Це декларація, а не претензія на власність»
** @ requires directive ** — вказує, що розв’ язувачу в одному підграфі потрібні поля з іншого підграфа (зазвичай, поля @external), перш ніж він зможе обчислити власне поле. Маршрутизатор Apollo спочатку отримає ці залежності, а потім викликає локальний розв’ язувач.
Поле
shippingCostвикористовує@requires(fields: \"weight dimensions\")— вони надходять з підграфа каталогу, і нам вони потрібні, перш ніж ми зможемо обчислити доставку
“Будь обережні з
@requiresна гарячих шляхах. Це додає додатковий підграф, що означає додаткову затримку»
** @ provide directive ** — повідомляє маршрутизатору, що певний шлях запиту може повертати певні поля об’ єктів локально, уникаючи додаткового отримання до підграфа власника. Це підказка щодо оптимізації.
“Ми додали
@provides(fields: \"name\")до типу рядка команди. Тепер підграф замовлення може повертати назву продукту в рядку без поїздки в обидві сторони до служби каталогу»
Не використовуйте
@provides— це означає, що ви дублюєте дані, і ви повинні зберігати їх в синхронізованому стані
Виконання і планування
** Сутність (крос-підграфовий тип) ** — тип з анотацією @key, який може бути посиланням і розв’язком через межі підграфів. Сутності є механізмом, за допомогою якого федеративні підграфи діляться і розширюють типи без щільного з’єднання.
“Тип
Customerє сутністю, визначеною в підграфі рахунків. Будь-який інший підграф може розширити його і додати поля, поки вони можуть розв’язати сутність за її ключем
“Якщо тип не є сутністю, на нього не можна посилатися з іншого підграфа. Ви повинні вирішити заздалегідь, які типи повинні перетинати кордони»
** Референсний розв’ язувач ** — спеціальний розв’ язувач (зазвичай __resolveReference у Apollo Server), який приймає посилання на сутність (об’ єкт, що містить лише поля @key) і повертає повний об’ єкт сутності. Його викликає маршрутизатор під час планування запиту, коли підграф повинен розв’ язати сутність, що належить іншому.
«Маршрутизатор викликає ваш посилальний резольвер тільки з
{ id: '123' }— вам потрібно пошукати повний об’єкт з вашої бази даних і повернути його»
“Результати посилання є клейкою основою федерації. Якщо ваш повільний або ненадійний, він буде каскадувати через будь-який запит, що перетинає межу підграфа»
** План запиту ** — структурований план виконання, створений Apollo Router, який описує, як розбити один запит клієнта на декілька отримань підграфів, у якому порядку, і як об’ єднати результати. Розробники можуть перевіряти плани запитів для зневадження і аналізу продуктивності.
«Витягніть план запиту для цього запиту — я хочу побачити, чи він робить послідовний запит або чи може він паралельно виконувати ці два виклики підграфів»
“План запиту показує чотири отримання для того, що клієнт вважає одним запитом. Вот почему задержка p99 такая высокая. Нам потрібно реструктуризувати власність суб’єкта»
Керування схемами та інструментами
** Реєстр схем ** — централізоване сховище, яке відстежує опубліковані схеми всіх підграфів і складеного суперграфа протягом певного часу. Реєстр є джерелом правди для історії схеми, перевірки змін і складання.
“Перед тим, як опублікувати зміну схеми, перевірте реєстр на наслідки для нижніх рівнів. Три інші підграфи посилаються на цей тип»
“Ми застосовуємо перевірки схем проти реєстру в CI. Жодна схема не змінює кораблі без перевірки складу і аналізу використання поля
** Apollo Studio ** — хмарна платформа Apollo для керування федеративними графіками. Studio надає реєстр схем, дослідник, метрику використання полів, перевірки операцій і інструменти спостереження для федеративних архітектур.
«Дані використання поля в Studio показують, що
legacyAccountCodeне мав запитів за 90 днів. Безпека для відмови»
«Перевірити Studio перед викликом інциденту — це показує, які операції вдаряють про неправильний підграф»
** Apollo Router ** — високопродуктивний, відкритий середовище виконання (написане на Rust), яке розташовується перед усіма підграфами і відповідає за планування запитів, розгортання підграфів, об’ єднання результатів і маршрутизацію трафіку. Замінює старіший Apollo Gateway для виробничих суперграфів.
“Ми перейшли з Gateway на Router в минулому кварталі. Відбиток процесора значно менший, а планування запитів швидше.»
«Рутератор підтримує нетипові плагіни через скрипти Rhai і ко-процесорні гачки. Ми використовуємо його для введення заголовків auth перед кожним запитом субграфа
** Схема контракту ** — фільтрована підмножина схеми суперграфа, опублікованої спеціально для певної аудиторії споживачів (наприклад, публічний API або інтеграція партнера). Договори виключають типи, поля або мітки, які не призначені для цієї аудиторії.
“Схема публічного контракту виключає всі внутрішні поля адміністратора. Партнери запитують проти контракту, а не повного суперграфа»
«Ми використовуємо директиви
@tag, щоб позначати, які поля належать до якого контракту. Таким чином, контракт завжди синхронізується зі схемою, а не підтримується окремо»
Як використовувати їх у розмові
** Перегляд архітектури: ** “Ми повинні вирішити, чи Subscription має бути своєю власною сутністю з @key на subscriptionId, або чи він залишається вкладеним типом під Customer. Якщо будь-який інший підграф коли-небудь повинен розширити його, ми повинні зробити його сутністю зараз»
** Зневадження повільного запиту: ** « План запиту виконує три послідовних отримання, оскільки ланцюг @requires є лінійним. Якщо ми пересунумо поле billingAddress до підграфу порядку і використаємо @provides, ми можемо згорнути його в одне завантаження і скоротити затримку приблизно наполовину»
** Приєднання до нової команди: ** “Ваша служба буде новим підграфом. Ви опублікуєте свою схему в реєстрі, визначите @key на будь-яких типах, якими ви володієте, на які можуть посилатися інші підграфи, і реалізуєте __resolveReference для кожної сутності. Маршрутизатор обробляє все інше»
** Обговорення управління схемою: ** « Перед тим, як ми покажемо це зовнішнім партнерам, ми повинні визначити схему контракту. Позначте внутрішні поля @tag(name: \"internal\") і налаштуйте контракт, який виключає цей тег. Таким чином, площа публічної поверхні є явною і стабільною»
Краткий справочник
| Term | Plain-English meaning |
|---|---|
| Federation | Architecture pattern: multiple GraphQL services composed into one unified API |
| Supergraph | The composed, unified schema and the overall system (router + subgraphs) |
| Subgraph | An individual GraphQL service contributing part of the schema |
| Schema composition | Merging subgraph schemas into a valid supergraph schema |
| Entity | A type with @key that can be referenced across subgraph boundaries |
| Reference resolver | Resolves a full entity from only its key fields; called by the router |
| Query plan | The router’s execution plan: which subgraphs to call, in what order |
| @key | Marks a type as an entity and defines its unique identifier |
| @requires | Declares that a field needs external fields resolved before it can compute |
| Schema registry | Centralised store of subgraph schemas and composed supergraph history |
| Apollo Router | Rust-based runtime that executes query plans across subgraphs |
| Contract schema | A filtered subset of the supergraph published for a specific audience |