Отключете силата на GraphQL федерацията със слепване на схеми. Научете как да изградите унифициран GraphQL API от множество услуги, подобрявайки мащабируемостта и поддръжката.
GraphQL федерация: Слепване на схеми (Schema Stitching) - изчерпателно ръководство
В постоянно развиващия се свят на модерната разработка на приложения, нуждата от мащабируеми и лесни за поддръжка архитектури стана от първостепенно значение. Микроуслугите, с тяхната присъща модулност и независима възможност за внедряване, се превърнаха в популярно решение. Управлението на множество микроуслуги обаче може да доведе до усложнения, особено когато става въпрос за предоставяне на унифициран API към клиентските приложения. Точно тук се намесва GraphQL федерацията и по-конкретно слепването на схеми (Schema Stitching).
Какво е GraphQL федерация?
GraphQL федерацията е мощна архитектура, която ви позволява да изградите единен, унифициран GraphQL API от множество базови GraphQL услуги (често представляващи микроуслуги). Тя дава възможност на разработчиците да изпращат заявки за данни от различни услуги, сякаш те са част от единен граф, което опростява клиентското изживяване и намалява нуждата от сложна логика за оркестрация от страна на клиента.
Съществуват два основни подхода към GraphQL федерацията:
- Слепване на схеми (Schema Stitching): Това включва комбиниране на множество GraphQL схеми в една единна, унифицирана схема на ниво шлюз (gateway). Това е по-ранен подход и разчита на библиотеки за управление на комбинирането на схемите и делегирането на заявките.
- Apollo Federation: Това е по-нов и по-стабилен подход, който използва декларативен език за схеми и специализиран планировчик на заявки (query planner) за управление на процеса на федерация. Той предлага разширени функции като разширения на типове (type extensions), ключови директиви (key directives) и разпределено проследяване (distributed tracing).
Тази статия се фокусира върху слепването на схеми (Schema Stitching), като изследва неговите концепции, предимства, ограничения и практическо приложение.
Разбиране на слепването на схеми (Schema Stitching)
Слепването на схеми е процес на обединяване на множество GraphQL схеми в една единна, съгласувана схема. Тази унифицирана схема действа като фасада, скривайки сложността на базовите услуги от клиента. Когато клиент направи заявка към слепената схема, шлюзът интелигентно насочва заявката към съответната базова услуга(и), извлича данните и комбинира резултатите, преди да ги върне на клиента.
Представете си го така: имате няколко ресторанта (услуги), всеки от които е специализиран в различни кухни. Слепването на схеми е като универсално меню, което комбинира всички ястия от всеки ресторант. Когато клиент (client) поръча от универсалното меню, поръчката се насочва интелигентно към кухните на съответните ресторанти, храната се приготвя и след това се комбинира в една доставка за клиента.
Ключови концепции в слепването на схеми
- Отдалечени схеми (Remote Schemas): Това са индивидуалните GraphQL схеми на всяка базова услуга. Всяка услуга предоставя своя собствена схема, която дефинира данните и операциите, които предоставя.
- Шлюз (Gateway): Шлюзът е централният компонент, отговорен за слепването на отдалечените схеми и предоставянето на унифицираната схема на клиента. Той получава клиентски заявки, насочва ги към съответните услуги и комбинира резултатите.
- Обединяване на схеми (Schema Merging): Това е процесът на комбиниране на отдалечените схеми в една единна схема. Това често включва преименуване на типове и полета, за да се избегнат конфликти, и дефиниране на връзки между типове от различни схеми.
- Делегиране на заявки (Query Delegation): Когато клиент направи заявка към слепената схема, шлюзът трябва да делегира заявката на съответната(ите) базова(и) услуга(и), за да извлече данните. Това включва превод на клиентската заявка в заявка, която може да бъде разбрана от отдалечената услуга.
- Агрегиране на резултати (Result Aggregation): След като шлюзът е извлякъл данни от базовите услуги, той трябва да комбинира резултатите в единен отговор, който може да бъде върнат на клиента. Това често включва трансформиране на данните, за да съответстват на структурата на слепената схема.
Предимства на слепването на схеми
Слепването на схеми предлага няколко убедителни предимства за организации, които възприемат архитектура на микроуслуги:
- Унифициран API: Предоставя единен, последователен API за клиенти, опростявайки достъпа до данни и намалявайки необходимостта клиентите да взаимодействат директно с множество услуги. Това води до по-чисто и по-интуитивно изживяване за разработчиците.
- Намалена сложност за клиента: Клиентите трябва да взаимодействат само с унифицираната схема, което ги предпазва от сложностите на базовата архитектура на микроуслуги. Това опростява разработката от страна на клиента и намалява количеството код, необходимо за клиента.
- Повишена мащабируемост: Позволява ви да мащабирате отделни услуги независимо една от друга въз основа на техните специфични нужди. Това подобрява общата мащабируемост и устойчивост на системата. Например, услуга за потребители, която изпитва голямо натоварване, може да бъде мащабирана, без да засяга други услуги като продуктовия каталог.
- Подобрена поддръжка: Насърчава модулността и разделянето на отговорностите, което улеснява поддръжката и развитието на отделни услуги. Промените в една услуга е по-малко вероятно да повлияят на други услуги.
- Постепенно внедряване: Може да се внедрява постепенно, което ви позволява плавно да мигрирате от монолитна архитектура към архитектура на микроуслуги. Можете да започнете със слепване на съществуващи API-та и след това постепенно да разграждате монолита на по-малки услуги.
Ограничения на слепването на схеми
Въпреки че слепването на схеми предлага многобройни предимства, е важно да сте наясно с неговите ограничения:
- Сложност: Внедряването и управлението на слепването на схеми може да бъде сложно, особено в големи и сложни системи. Необходимо е внимателно планиране и проектиране.
- Натоварване на производителността: Шлюзът въвежда известно натоварване върху производителността поради допълнителния слой на индирекция и необходимостта от делегиране на заявки и агрегиране на резултати. Внимателната оптимизация е от решаващо значение за минимизиране на това натоварване.
- Конфликти в схемите: Могат да възникнат конфликти при обединяване на схеми от различни услуги, особено ако те използват едни и същи имена на типове или полета. Това изисква внимателно проектиране на схемите и потенциално преименуване на типове и полета.
- Ограничени разширени функции: В сравнение с Apollo Federation, на слепването на схеми му липсват някои разширени функции като разширения на типове и ключови директиви, което може да направи управлението на връзките между типове от различни схеми по-трудно.
- Зрялост на инструментите: Инструментите и екосистемата около слепването на схеми не са толкова зрели, колкото тези около Apollo Federation. Това може да направи отстраняването на грешки и проблеми по-трудно.
Практическо внедряване на слепване на схеми
Нека разгледаме опростен пример за това как да внедрим слепване на схеми с помощта на Node.js и библиотеката graphql-tools
(популярен избор за слепване на схеми). Този пример включва две микроуслуги: услуга за потребители (User Service) и услуга за продукти (Product Service).
1. Дефиниране на отдалечените схеми
Първо, дефинирайте GraphQL схемите за всяка от отдалечените услуги.
Услуга за потребители (user-service.js
):
const { buildSchema } = require('graphql');
const userSchema = buildSchema(`
type User {
id: ID!
name: String
email: String
}
type Query {
user(id: ID!): User
}
`);
const users = [
{ id: '1', name: 'Alice Smith', email: 'alice@example.com' },
{ id: '2', name: 'Bob Johnson', email: 'bob@example.com' },
];
const userRoot = {
user: (args) => users.find(user => user.id === args.id),
};
module.exports = {
schema: userSchema,
rootValue: userRoot,
};
Услуга за продукти (product-service.js
):
const { buildSchema } = require('graphql');
const productSchema = buildSchema(`
type Product {
id: ID!
name: String
price: Float
userId: ID! # Foreign key to User Service
}
type Query {
product(id: ID!): Product
}
`);
const products = [
{ id: '101', name: 'Laptop', price: 1200, userId: '1' },
{ id: '102', name: 'Smartphone', price: 800, userId: '2' },
];
const productRoot = {
product: (args) => products.find(product => product.id === args.id),
};
module.exports = {
schema: productSchema,
rootValue: productRoot,
};
2. Създаване на услугата-шлюз (Gateway Service)
Сега създайте услугата-шлюз, която ще слепи двете схеми заедно.
Услуга-шлюз (gateway.js
):
const { stitchSchemas } = require('@graphql-tools/stitch');
const { makeRemoteExecutableSchema } = require('@graphql-tools/wrap');
const { graphqlHTTP } = require('express-graphql');
const express = require('express');
const { introspectSchema } = require('@graphql-tools/wrap');
const { printSchema } = require('graphql');
const fetch = require('node-fetch');
async function createRemoteSchema(uri) {
const fetcher = async (params) => {
const response = await fetch(uri, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(params),
});
return response.json();
};
const schema = await introspectSchema(fetcher);
return makeRemoteExecutableSchema({
schema,
fetcher,
});
}
async function main() {
const userSchema = await createRemoteSchema('http://localhost:4001/graphql');
const productSchema = await createRemoteSchema('http://localhost:4002/graphql');
const stitchedSchema = stitchSchemas({
subschemas: [
{ schema: userSchema },
{ schema: productSchema },
],
typeDefs: `
extend type Product {
user: User
}
`,
resolvers: {
Product: {
user: {
selectionSet: `{ userId }`,
resolve(product, args, context, info) {
return info.mergeInfo.delegateToSchema({
schema: userSchema,
operation: 'query',
fieldName: 'user',
args: {
id: product.userId,
},
context,
info,
});
},
},
},
},
});
const app = express();
app.use('/graphql', graphqlHTTP({
schema: stitchedSchema,
graphiql: true,
}));
app.listen(4000, () => console.log('Gateway server running on http://localhost:4000/graphql'));
}
main().catch(console.error);
3. Стартиране на услугите
Ще трябва да стартирате услугата за потребители и услугата за продукти на различни портове. Например:
Услуга за потребители (порт 4001):
const express = require('express');
const { graphqlHTTP } = require('express-graphql');
const { schema, rootValue } = require('./user-service');
const app = express();
app.use('/graphql', graphqlHTTP({
schema: schema,
rootValue: rootValue,
graphiql: true,
}));
app.listen(4001, () => console.log('User service running on http://localhost:4001/graphql'));
Услуга за продукти (порт 4002):
const express = require('express');
const { graphqlHTTP } = require('express-graphql');
const { schema, rootValue } = require('./product-service');
const app = express();
app.use('/graphql', graphqlHTTP({
schema: schema,
rootValue: rootValue,
graphiql: true,
}));
app.listen(4002, () => console.log('Product service running on http://localhost:4002/graphql'));
4. Изпращане на заявка към слепената схема
Сега можете да изпратите заявка към слепената схема през шлюза (работещ на порт 4000). Можете да изпълните заявка като тази:
query {
product(id: "101") {
id
name
price
user {
id
name
email
}
}
}
Тази заявка извлича продукта с ID "101" и също така извлича свързания потребител от услугата за потребители, демонстрирайки как слепването на схеми ви позволява да изисквате данни от множество услуги в една единствена заявка.
Разширени техники за слепване на схеми
Освен основния пример, ето някои разширени техники, които могат да се използват за подобряване на вашата имплементация на слепване на схеми:
- Делегиране на схеми (Schema Delegation): Това ви позволява да делегирате части от заявка към различни услуги въз основа на изискваните данни. Например, може да делегирате резолвирането на тип `User` на услугата за потребители и резолвирането на тип `Product` на услугата за продукти.
- Трансформация на схеми (Schema Transformation): Това включва модифициране на схемата на отдалечена услуга, преди тя да бъде слепена в унифицираната схема. Това може да бъде полезно за преименуване на типове и полета, добавяне на нови полета или премахване на съществуващи.
- Персонализирани ризолвъри (Custom Resolvers): Можете да дефинирате персонализирани ризолвъри в шлюза, за да обработвате сложни трансформации на данни или да извличате данни от множество услуги и да ги комбинирате в един резултат.
- Споделяне на контекст (Context Sharing): Често е необходимо да се споделя контекстна информация между шлюза и отдалечените услуги, като например токени за удостоверяване или потребителски ID-та. Това може да се постигне чрез предаване на контекстна информация като част от процеса на делегиране на заявки.
- Обработка на грешки (Error Handling): Внедрете стабилна обработка на грешки, за да се справяте елегантно с грешки, възникнали в отдалечените услуги. Това може да включва регистриране на грешки, връщане на лесни за разбиране съобщения за грешки или повторно опитване на неуспешни заявки.
Избор между слепване на схеми и Apollo Federation
Въпреки че слепването на схеми е жизнеспособен вариант за GraphQL федерация, Apollo Federation се превърна в по-популярния избор поради своите разширени функции и подобрено изживяване за разработчиците. Ето сравнение на двата подхода:
Функция | Слепване на схеми (Schema Stitching) | Apollo Federation |
---|---|---|
Дефиниция на схема | Използва съществуващия език за GraphQL схеми | Използва декларативен език за схеми с директиви |
Планиране на заявки | Изисква ръчно делегиране на заявки | Автоматично планиране на заявки от Apollo Gateway |
Разширения на типове | Ограничена поддръжка | Вградена поддръжка за разширения на типове |
Ключови директиви | Не се поддържа | Използва директива @key за идентифициране на същности |
Разпределено проследяване | Изисква ръчно внедряване | Вградена поддръжка за разпределено проследяване |
Инструменти и екосистема | По-малко зрели инструменти | По-зрели инструменти и голяма общност |
Сложност | Може да бъде сложно за управление в големи системи | Проектиран за големи и сложни системи |
Кога да изберем слепване на схеми:
- Имате съществуващи GraphQL услуги и искате бързо да ги комбинирате.
- Нуждаете се от просто решение за федерация и не изисквате разширени функции.
- Имате ограничени ресурси и искате да избегнете допълнителните разходи за настройка на Apollo Federation.
Кога да изберем Apollo Federation:
- Изграждате голяма и сложна система с множество екипи и услуги.
- Нуждаете се от разширени функции като разширения на типове, ключови директиви и разпределено проследяване.
- Искате по-стабилно и мащабируемо решение за федерация.
- Предпочитате по-декларативен и автоматизиран подход към федерацията.
Примери от реалния свят и случаи на употреба
Ето някои примери от реалния свят за това как може да се използва GraphQL федерацията, включително слепването на схеми:
- Платформа за електронна търговия: Платформа за електронна търговия може да използва GraphQL федерация, за да комбинира данни от множество услуги, като услуга за продуктов каталог, услуга за потребители, услуга за поръчки и услуга за плащания. Това позволява на клиентите лесно да извличат цялата информация, от която се нуждаят, за да показват подробности за продукти, потребителски профили, история на поръчките и информация за плащания.
- Платформа за социални медии: Платформа за социални медии може да използва GraphQL федерация, за да комбинира данни от услуги, които управляват потребителски профили, публикации, коментари и харесвания. Това позволява на клиентите ефективно да извличат цялата информация, необходима за показване на профила на потребителя, неговите публикации и коментарите и харесванията, свързани с тези публикации.
- Приложение за финансови услуги: Приложение за финансови услуги може да използва GraphQL федерация, за да комбинира данни от услуги, които управляват сметки, транзакции и инвестиции. Това позволява на клиентите лесно да извличат цялата информация, от която се нуждаят, за да показват салда по сметки, история на транзакциите и инвестиционни портфейли.
- Система за управление на съдържанието (CMS): CMS може да използва GraphQL федерация, за да интегрира данни от различни източници като статии, изображения, видеоклипове и съдържание, генерирано от потребители. Това позволява унифициран API за извличане на цялото съдържание, свързано с конкретна тема или автор.
- Приложение за здравеопазване: Интегриране на данни за пациенти от различни системи като електронни здравни досиета (EHR), лабораторни резултати и насрочване на прегледи. Това предлага на лекарите единна точка за достъп до изчерпателна информация за пациента.
Най-добри практики за слепване на схеми
За да осигурите успешно внедряване на слепване на схеми, следвайте тези най-добри практики:
- Планирайте схемата си внимателно: Преди да започнете да слепвате схеми, внимателно планирайте структурата на унифицираната схема. Това включва дефиниране на връзките между типове от различни схеми, преименуване на типове и полета, за да се избегнат конфликти, и отчитане на общите модели за достъп до данни.
- Използвайте последователни конвенции за именуване: Възприемете последователни конвенции за именуване на типове, полета и операции във всички услуги. Това ще помогне да се избегнат конфликти и ще улесни разбирането на унифицираната схема.
- Документирайте схемата си: Документирайте унифицираната схема подробно, включително описания на типове, полета и операции. Това ще улесни разработчиците да разбират и използват схемата.
- Наблюдавайте производителността: Наблюдавайте производителността на шлюза и отдалечените услуги, за да идентифицирате и отстраните всякакви тесни места в производителността. Използвайте инструменти като разпределено проследяване, за да проследявате заявките в множество услуги.
- Внедрете сигурност: Внедрете подходящи мерки за сигурност, за да защитите шлюза и отдалечените услуги от неоторизиран достъп. Това може да включва използване на механизми за удостоверяване и оторизация, както и валидиране на входа и кодиране на изхода.
- Версионирайте схемата си: Докато развивате своите схеми, ги версионирайте по подходящ начин, за да гарантирате, че клиентите могат да продължат да използват по-стари версии на схемата безпроблемно. Това ще помогне да се избегнат критични промени и да се осигури обратна съвместимост.
- Автоматизирайте внедряването: Автоматизирайте внедряването на шлюза и отдалечените услуги, за да гарантирате, че промените могат да бъдат внедрени бързо и надеждно. Това ще помогне да се намали рискът от грешки и да се подобри общата гъвкавост на системата.
Заключение
GraphQL федерацията със слепване на схеми предлага мощен подход за изграждане на унифицирани API-та от множество услуги в архитектура на микроуслуги. Като разбирате основните му концепции, предимства, ограничения и техники за внедряване, можете да използвате слепването на схеми, за да опростите достъпа до данни, да подобрите мащабируемостта и да улесните поддръжката. Въпреки че Apollo Federation се очерта като по-напреднало решение, слепването на схеми остава жизнеспособен вариант за по-прости сценарии или при интегриране на съществуващи GraphQL услуги. Внимателно обмислете вашите специфични нужди и изисквания, за да изберете най-добрия подход за вашата организация.