1-Netflix 基于 DataMesh 的数据管道
Netflix 的内容工程 让许多的服务变为了 GraphQL 平台.
- 每个内容服务都有自己独立的
DGS: Domain Graph Services. - 为所有的
DGS建立一个联合的网关, 统一的抽象层 - 基于
DataMesh的架构来 构建一个统一的Index Pipeline
用如下的业务作为例子

领域模型如下:
Movie: 代表一个电影 ;Production: 代表一个制作, 每个电影都和一个工作室有关联, 一个制作对象跟踪制作电影所需要的一切, 包括拍摄地点,供应商等等 ;Talent: 在电影中工作的人被称为 “人才”, 包括演员, 导演等等 ;
GraphQL 如下

Netflix 的 DataMesh 架构

-
每个独立的应用会 负责生成 一个结构化的数据 到 数据中心
Kafka- 例如可以用
Kafka原作者 后面开源的 Confluent Schema Registry 作为统一的 事件中心 ;
- 例如可以用
-
收集
Application事件的方式有2种, 要符合上面定义的Schema Event, 我个人习惯用ProtoBuf来定义Netflix用的自研的统一CDC Connector: 这种技术是Event中会携带数据. 例如可以用如下开源方案平替:- Maxwell Binlog Producer : 收集
MysqlBinlog的Cdc - MongoDb Change Stream : MongoDb 的 Change Stream
- 任何如今现在的数据库都会成熟的
CDC方案 - 甚至是成熟的平台 Debezium
- Maxwell Binlog Producer : 收集
- 应用当然也可以直接发送
Schema
-
Data Mesh的消费端NetFlix选择了 Apache Flink 作为消费手段, 这个是非常不错的选择. 个人观点 , 当前场景下是比Spark更合适的选择:Flink有成熟的Snapshot机制 来实现高可用 和Exactly Once的语义- 有成熟的
Union Processors机制来实现多流合并 - 有成熟的
ElasticSearch Sink,Es的Dynamic Template还是比较好用的, 个人感觉也比较适合GraphQL的玩法,OpenSearch作为ElaticSearch的平替也可以, 不确定 ManicoreSearcg 对GraphQL的友好程度, 看了下很友好… 😄, 甚至包含了部分CDC的功能, 很卷 - …
-
看上面的图,也就是
2a→2b的地方是 收到了数据的变化之后要 回去fetch这个DataMesh配置的字段 反向去走Studio EDGE中获取到需要的数据, 再把这个数据写入到 一个新的Kafka Topic, 最终索引到ElasticSearch
Tips
上面的架构 个人认为有非常的
Variance,CDC Connector收集的数据往往是 有序而且 包含了Current Data的, 因此 最后一个Studio Edge应该是Optional的.
- 但是如果走
CDC本身的数据,例如Production最后到Es就会有一个Partial Update的问题 , 虽然Es支持,但是也增加了Version Conflict的风险.
Tips
上面的
DataMesh架构不仅仅可以用来构建 图网关的 index,也可以是 任何 Application Service 中的 Index
Reverse Lookups
Netflix这里想说的是反向 更新机制, 如果 被关联的子对象中的内容发生了变化- 例如上面的
Production变化了,需要反向查找包含了Production.id的Movie, 然后更新这些主实体的索引信息.
Tips
反向更新策略 消耗是比较大的,假设是 1对1 的关系还好,如果是 多对1, 1的更新意味着多个
Movie都要因为这一次 子更新而全部更新, 这种写压力太大,要在DataMesh中权衡
Netflix在向各个业务方推进 自动化的时候碰见了如下 4个主要问题:
- 需要一种方式 ,我个人认为
DSL语法都比较合适 来让 用户定制 管道的输入配置 Netflix的 Schema 是Avro,GraphQL的响应是多层嵌套的结构字段,手动编写这些复杂的模式非常容易出错- 同样,
ElasticSearch的模版窗创建也应该自动化 - 自动创建
Data Mesh的管理
为了解决上面的问题, Netflix 使用了如下的配置文件来抽象一个 Data Mesh Pipeline 的配置.

- 这个是一个最外层的
GraphQL配置 - 要把这个配置抽象为一个
json可以用 graphql-java 然后基于这个进行自动化
DataMesh中的挑战
Backfill: 新索引或者老索引添加字段, 会有突发的负载, 尤其高峰期Reverse LookUp: 实现比较方便, 但是不友好, 十项一个Index中如果包含了 8个Domain, 每个子Domain都会造成Reverse Lookup的问题Index Consistency: 这种自动化的 一致性问题特别难以排查, 因为是老的设计方案, 消息 → 提取消息的各种Id, 然后回查Fetch, 这个回查的引入 必然会有一致性问题(分布式环境中,例如 缓存,从库延迟等等)
2-Studio Edge Search
这里是如何根据一个 Index 的配置, 然后去查询各自的服务.
为了从
ElasticSearch复杂的交互中解脱出来了,Netflix封装了一套自己的DSL.
类似 SQL. 有如下的语法.

使用的库是:
- antlr4: 一个 文本
Processor, 非常适合DSL这样的构建任务, 他可以解析文本生成一个Visitor模式的Tree, 只要实现 一个自定义的Visitor, 就可以 使用Elasticsearch的QueryBuilder实现一个这样的功能 ;
Tips
ElasticSearch 的 Query DSL 有点复杂,而且他客户端的完全不兼容是很痛苦的, 例如
Es2->Es5->Es8, 尤其是 包含了 Nested Query 的时候更痛苦 .
使用这套语法配合 之前的
GraphQL规则
Netflix做到了从GraphQL中提取出 需要的 语法是:actor.role == 'actor'
Tips
会注意到 上面的语法支持的 偏
Filter的功能,没有表达到Es的Text Match能力, 这个可以单独做,建议不要和Filter搞到一起,这2个都挺麻烦的,建议分开.
基于规则还直接一套做了通用的
DGSAPI.

Refer
- How Netflix Content Engineering makes a federated graph searchable
- How Netflix Content Engineering makes a federated graph searchable2
- Domain Graph Service : 使用
SpringBoot实现的GraphQL - Federated gateway : 联合网关
- Data Mesh :
Data Mesh Pipeline一个完整的数据管线 - Netflix DBLog :
Netflix统一的标准的CDC Connector组件 - Netflix DGS spring boot :
Netflix的DGSSpringBoot框架