How Netflix Scales its API with GraphQL Federation (Part 1)
https://netflixtechblog.com/how-netflix-scales-its-api-with-graphql-federation-part-1-ae3557c187e2
unfederated graphql
cons: 微服务的独立开发的好处被削弱了,统一的 graphql 层成了单点依赖,不方便快速迭代。且由一个统一的小团队来维护是有难度的。
转向 federated
- 首先是 federated type. 可以在一处定义,多处被 extend. 此时 resolve 这个 type 的 field 就被 gateway delegate 到其对应的 owning domain service.
核心架构组件
- gateway team
- graphql gateway
- 给 consumer 提供 query 服务。它接受一个 query, 拆解成 sub queries, 形成 query plan, 然后通过把调用 proxy 到下游的 DGS 的方式执行 query plan.
- schema registry
- 暴露 schemas 的 CRUD api,给到开发者工具,以及 CI/CD pipelines.
- 负责每个 DGS 的 schema 以及合并的 schema 的校验
- 组合一个统一的 schema,提供给 gateway
- graphql gateway
- domain team(s)
- DGS (domain graph service). 包含 resolver
- microservice
主要技术细节
- schema 的组合
当 DGS 提交新的 schema 时,schema registry 会检查:
- 新 schema 是否为 valid 的 graphql schema (合法性)
- 新 schema 是否能和已有的其他 schemas 无缝组合,形成一个 valid 的新 schema (兼容性)
- 新 schema 是否向前兼容
- query planning and execution
composed schema + client query = query plan.
在创建 query plan 时,会首先判断每个 field 是由哪个 DGS own 的,从而生成对应的 sub query.
然后,还会根据依赖关系,判断出哪些 sub query 可以并发执行,哪些有先后顺序。
- Entity resolver
- 所有定义或扩展了 Movie 类型的 DGS 都要就一个或多个主键 fields 达成一致,如 movieId. 为此,Apollo 引入了 @key directive.
- DGSs 需要为一个通用的 query field
_entities实现 resolver. 该 field 返回当前 DGS 里所有的 federated types. Gateway 使用 movieID 在 _entities 中查找对应的 Movie.
Part 2
https://netflixtechblog.com/how-netflix-scales-its-api-with-graphql-federation-part-2-bbe71aaec44a
Netflix 用 Kotlin 实现了 graphql gateway 和 schema registry.
schema registry 中,储存 schema changes 使用了一个实现了 event sourcing 的,基于 Casandra 数据库的内部库。
schema registry 还和 ci/cd 系统做了集成,以便可以自动为 DSGs 配置云上的网络。
graphql 自己的学习曲线
- 复杂场景如 batching 和 look ahead 会比较 tricky.
一些其他的 graphql hot topics
- pagination
- error handling
- nullability
- naming convensions
DSG Frameworks and Developer Tools
基于 graphql java 以及 spring boot 创建了 DSG Framework. 其功能:
- 实现了所有为了在生产环境跑一个 graphql service 所必要的 cross cutting concerns
- 同时允许 developer 方便的实现 resolvers
- 实现了推送 schema 到 schema registry 的 robust tooling
- 自助的 UI,可以浏览不同 DSG 的 schemas.
Schema Governance
有一个 dedicated Data Architect. 专门聚焦 data modeling,并在各部门之间协调。
goal 是要构建一个反应 domain 的 schema, 而不是 db model.
那么 ui 开发就应该不需要构建自己的 BFF,而是要帮助构建适合他们需要的 schema.
弃用 field 可以使用 deprecated 功能. 并且可以跟踪 field 的使用情况。一旦某个 feild 不再被使用,就可以做一个向后不兼容的变更,将它从 schema 中去除。
使用了 schema-first approach 去设计,而不是从 gRPC API 的 Protobuf 对象直接生成。
这样可以得到更干净的设计。即使在有些场景需要 graphql resolver map 到 gRPC calls,这些多余的 boilerplate 相对于 graphql api 的长期灵活性来说,还是有必要的。
Observability
- alerting. 出现问题时及时报警
- discovery. 方便的发现是什么不工作了
- diagnosis. 诊断为什么不工作
metrics:
- mean time to resolution (MTTR)
- SLO/SLI (service level objectives and indicators)
集成了以下工具
- 内部工具 Edgar:基于 Zipkin 分布式追踪,集成了 Gateway 和 DGS 的架构组件
- TellTale: 应用监控工具
graphql 几乎每个请求的响应都是 200,而自定义错误在特定的 error 区块。
可以提取这些错误信息,发送到 metrics server Atlas.
关键点:
- 错误信息采集
- 分布式跟踪结果通过 timeline view 呈现
- correlated logs
Securing the Federated Graph
Authentication
限制 graphql gateway 的 access 为仅允许登录后的 caller 访问;
且 graph introspection 仅限内部开发人员。
Authorization
将此职责 delegate 给了每个 DSG owner.
DSG 开发可以选择自己合适的授权方案。简单的方法是在 resolver 上配置 @Secured annotation.
复杂一点可以在 resolver 或者下游的系统里去实现。
Architecture for Failure
federation gateway 是故障单点,所以需要考虑高可用。为了保证 gateway 层是 resilient 的,一些设计原则如下:
- single purpose. 减少 scope, 仅聚焦在解析 query, 构建和执行查询计划上。
- stateless service. 严格的执行无状态设计,这样,就可以同时跑多个 gateway 实例。任意一个 gateway 都可以执行任何一个请求。并且,在上生产之前严格的测试。
- demand controlled. rate limit, 并且做静态查询成本计算,拒绝特别耗资源的查询。
- multi-region. 将 gateway 部署到了世界各个 region 的 AWS 上,避免爆发性的流量,同时,出问题时也方便做 fail over 切换。
- shared by functionality. 布署 gateway 的多个不同功能的 shards. 比如:query 和 mutation 一般是短时间的操作;而 subscription 需要长时间占有连接。分片的话,就可以在 subscription 如果耗尽连接资源的时候,query 和 mutation 的可用性不受影响。

浙公网安备 33010602011771号