数据接入与传输作为买通数据系统与业务零碎的一道桥梁,是数据系统与架构中不可或缺的一个重要局部。数据传输零碎稳定性和准确性,间接影响整个数据系统服务的 SLA 和品质。此外如何晋升零碎的易用性,保障监控服务并升高系统维护老本,优雅应答劫难等问题也非常重要。
本文介绍了汽车之家实时计算团队利用 Flink 和 Flink 实时平台构建数据传输 SDK 和传输平台并不断完善的实践经验与总结。内容包含:
- 背景与需要
- 技术选型与设计 —— Why Flink?
- 数据传输零碎的设计架构
- 基于 Flink 的 Binlog 接入 SDK
- 平台应用
- 总结与瞻望
一、背景与需要
汽车之家(下称之家)作为一家数据智能驱动的公司,人造存在着对数据的各种简单需要,之家的数据系统负责撑持这些业务需要的发展。数据传输零碎,作为其中一环,承当了各类数据导入散发的需要,反对用户订阅数据变更。随着撑持的业务扩增与需要的减少。原来的接入零碎暴露出了肯定的问题和有余:
- 不足无效的工作与信息管理机制,依赖人工进行工作的治理和运维,信息的统计
- 接入程序资源应用节约,不足弹性
- 针对 DDL 变更问题,不能很好的解决,必要时须要人工染指
- 传输零碎依赖的组件比拟多,比方 Zookeeper,Redis 等
- 代码的技术债累积,代码保护老本变高
针对上述问题,咱们决定开发一套新的数据传输和散发零碎,一举解决上述问题。
二、技术选型与设计 —— Why Flink?
在发展新零碎的开发工作之前,咱们剖析的可选的计划思路大体分三种:
- 齐全自研(相似于 otter)
- 复用市面上的开源组件 (Maxwell/Canal/Debezium) 进行二次开发和整合
- 基于 Flink 进行组件的开发
咱们规约出以下次要设计应用指标:
- 架构设计上要运维治理是敌对的,提供高可用以及 故障复原策略,反对异地多活
- 架构设计上要提供 强数据准确性,至多承诺 at-least-once 语义
- 架构设计上要对 扩缩容是敌对的,能够按需分配资源
- 功能设计上要全面的监控笼罩和欠缺的报警机制,反对元数据信息管理
- 功能设计上要对实时计算是敌对的(1)
- 功能设计上要能 齐全进攻 DDL 变更带来的问题
此外,在性能指标上,接入零碎的延时和吞吐至多要满足 所有业务惯例状态下的需要。
(1) 指与实时计算平台整合的能力
方案设计与比照
按照设计思路和指标,咱们整顿了计划次要性能的比照表格:
(1)Flink 自带高可用和故障复原,实时计算平台在此基础上提供更强的高可用服务
(2)良好的编码 + flink 机制即可实现 Exactly-Once
(3)实时计算平台自带工作部署治理能力
(4)实时计算平台自带齐备的监控和治理
通过探讨,大家统一决定基于 Flink 进行新的传输平台的开发:
- Flink DataStream 的编程模型和 API 在应答数据传输场景上,十分的天然与间接
- Flink 在框架层面提供了一致性保障和 HA/ 稳定性 / 流量控制措施,让咱们能够不用去解决这些开发上比拟艰难和简单的问题,背靠框架即可较为轻松地实现相干工作
- Flink 人造具备横向纵向扩容的能力,按需应用计算资源即可
- 齐全复用了之家 Flink 实时计算平台已有的组件和能力——齐备的监控报警 / 工作生命周期治理 / 异地多活 / 自助运维等性能
咱们的 MVP 版本开发实现大概只破费了不到 3 周的工夫,POC 的后果完全符合预期的性能要求和性能要求。
三、数据传输零碎的设计架构
从逻辑层面来看,之家的实时数据传输平台分为 3 局部:
- 数据传输程序
- 接入工作信息管理模块
- 工作执行 Runtime 模块
在实现上:
- 数据传输程序是由固定的 Flink Jar 和 Flink SQL Codegen Service 生成的 SQL Task 组成
- 治理模块作为一个微服务,负责与 Flink 平台组件通信,实现必要的工作治理和信息管理
- 执行层间接依赖 Flink 平台和 Flink 平台的集群
组件架构与交互逻辑
传输零碎波及到的组件和交互如图所示:
AutoDTS 即为传输零碎的工作信息管理模块,AutoStream Core 为 Flink 实时平台外围零碎,Jar Service 是 Flink 相干 SDK Jar 贮存治理服务,Metastore 为 Flink 平台的元数据管理系统,Flink Client 是咱们本人封装的 Submit Client,反对以 Restful 形式向 YARN/K8S 上提交作业。
AutoDTS 前端间接与用户进行交互,实现用户对工作信息的批改和工作生命周期的操作。AutoDTS 将工作信息处理后与 Flink 平台交互,每一个数据传输工作对应 Flink 平台惟一一个工作,同时,局部工作信息被 AutoDTS 解决,会间接在 Metastore 上实现对应流表的创立。用户间接申请并应用该 Flink 流表,进行 SQL 工作的开发。
针对不同的传输工作,AutoDTS 会委托 Core System 组织工作参数和 SQL 逻辑,并从 Jar Service 加载不同的 SDK Jar 提交到 Client 去执行,对于基于 SQL Codegen 的传输工作,Flink SQL Codegen Service 会将工作参数组织整合翻译成可执行的 Flink SQL 工作,通过 SQL 工作,咱们能够间接复用平台 SQL SDKs,执行 SQL 作业。
正如前文提到的,咱们最大限度复用已有组件和服务,大大降低了开发的周期。
传输工作类型与形成
之家的数据传输工作分为两种类型,接入工作与散发工作。
- 接入工作,负责从数据源实时接入 Changelog Stream 并解决成对立的格局写入 Kafka 中,每个表只会对用惟一个接入程序,作为公共数据资产,被上游程序进行应用和生产
- 散发工作,负责读取公共的 Kafka 数据,并将数据写入指定的存储中,用户依据本人的需要去应用,领有散发工作的所有权
如图所示,接入的数据源次要有 3 种,除了 Mysql 和 SqlServer,咱们还反对了 TiDB 的 Changelog(TiCDC)接入 Java Client 相干逻辑, 并将咱们的代码奉献到了 TiDB 社区 [1];对于分发端,通过解析用户的工作配置,从而进行 SQL codegen 生成 Flink SQL 代码执行。
四、基于 Flink 的 Binlog 接入 SDK
在这些接入和散发 SDK 中,Binlog 接入 SDK 是比拟有难度的一个,上面咱们以 Binlog 接入 SDK 为例,分析接入 SDK 的主体设计思路和开发过程。
Stage 拆解
按照 Flink 经典的 Source->Transformation->Sink,Binlog 接入工作也拆分为这三个 Stage:
Binlog Source
Binlog Source 的奢侈开发思路:创立一个 BinaryLogClient 并继续 fetchBinlogEvent 并进行简略的转换解决后发送到上游。在既定的设计指标中,以下问题须要认真思考:
- 保障 Source 端解决性能
- 保障 source 是可回溯的
- 保障 Mysql Transaction 的完整性
对于问题 1,思考到 Binlog Stream 的特殊性,咱们要求 Source 的并行度为且仅能为 1。且在绝大部分状况下,从 BinaryLogClient fetch BinlogEvent 不会是性能瓶颈。咱们只有保障 BinaryLogClient 与 BinlogSourceFunction 的生命周期统一,二者通过有界的阻塞队列链接,别离充当生产者和消费者,同时 BinlogSourceFunction 对 BinlogEvent 尽可能少的进行逻解决,让 BinlogSourceFunction 的累赘尽量加重,从而晋升 Source 阶段的性能即可。
而对于问题 2、3,则须要从 Binlog 的个性和格局来剖析。家喻户晓,BinlogEvent 携带了惟一的 BinlogPosition。BinlogPosition 是全序的,咱们能够在 trigger Checkpoint 的时候,对以后的 BinlogPosition 进行记录。然而仅仅是记录这个是不够的,如果记录了数据地位,那么下次从 Checkpoint 复原的时候,是从当条记录开始还是当条记录的下一条记录开始呢?另一方面,咱们心愿发送的依照一个残缺的 transaction 去发送数据给上游而非从事务两头截断发送。这里,咱们就要用到 BinlogEvent 的一种特定事件——TransactionEnd 事件。
咱们这里先来解决问题 2,咱们要求 BinlogSourceFunction 只应用 TransactionEnd 事件的 BinlogPosition 来更新位点保留到状态中,因为 TransactionEnd 事件不是 DML 事件,不会导致上游生成数据,所以就不须要思考之前提到的问题。
而问题 3 的解决须要和 Flink 的 Checkpoint 机制进行联动。咱们过后应用的 Flink 版本是 1.9.x。在 Source 端,须要通过 CheckpointLock 来让 Source 和 Checkpoint trigger 进行配合。尽管在了解和应用上有肯定的壁垒,然而 CheckppointLock 机制恰好帮忙咱们达成了问题 3 的指标。咱们保障了 Source 只有拿到 lock 才发送数据给上游,只有在实现一次 transaction 的数据发送后才 unlock,这样就保障了 2 个 checkpoint 之间必然是残缺的 𝒳(𝒳 ∈ N)次 transaction 的数据。另一方面,咱们减小了 checkpoint trigger 的距离(200ms~500ms),缩小了 checkpoint 间的数据 transaction 的数量,放慢数据 commit 的速度。
UnifiedFormatTransform
就如名字形容的,UnifiedFormatTransform 的作用是将数据转换为对立制订的数据格式。
相较于 Binlog Source 阶段,UnifiedFormatTransform 阶段不必太过放心性能问题,良好的编码和程度垂直扩容能力能够应酬绝大部分性能需求。然而有一个重要的问题亟待解决,就是后面提到的功能设计指标:齐全进攻 DDL 带来的问题。
DDL 问题在数据同步 / 传输中始终是一个比拟辣手的问题,带来的麻烦包含不限于,数据解析失败 / 谬误,程序失败 / 重启,且复原的老本往往很高。而其实解决这个问题的外围思路也很简略,就是在程序中就地解析 DDL 并解决 Schema 变动。为了实现这个性能,咱们须要实现以下几个步骤:
- 内嵌 Parser,用于解析 DDL SQL
- 解析呈现的所有 DDL,依据解析的 DDL 内容更新内置的 Schema,并更新到 Flink 状态中
- 生成 DDL 对应的数据发送到上游
咱们这实现上参考了 Maxwell [2] 的做法,内嵌了 Antlr4 的 Mysql 文法的 g4 文件,而后自定义 listener 来实现对 Schema 的更新和 DDL 数据的生成,而后 Schema 会在 Checkpoint 触发时被保留到状态中。
实现了就地解决 DDL 的性能后,不论是简略的 Alter Table,还是简单的 Online DDL,接入程序都能够顺利解决,利用状态从断点复原,也不会呈现 Schema 异样的问题。
Kafka Sink
Kafka Sink 阶段次要是将转换好的数据写入 Kafka 中。Flink 原生为 Kafka Sink 赋予了 Exactly-Once 的能力,而咱们也将这个性能利用起来,和 Source 一起,提供了开箱即用的端到端 Exactly-Once 解决方案。咱们保障了 Source 依照残缺的 Mysql Transaction 发送数据,同时 Sink 依照残缺的 Mysql Transaction 将数据写入 Kafka,对于 Transaction 敏感的场景,咱们能够开启 Transactional 生产模式,来实现强 transaction 语义(而非最终一致性)的数据处理。
其余优化
此外咱们还做了一些优化性能:
- gtid 反对与一键主从切换
- 程序运行信息定期备份到内部存储
- Binlog 同步工作相干的监控指标笼罩
五、平台应用
用户在传输平台,只须要实现必要配置的设定,即可实现传输工作的创立和数据的应用,比较简单。
接入工作
对于接入工作,正如咱们前文提到的, 接入工作产生的数据会被作为公共资产。所以用户只须要查问需要的表的数据是否曾经接入,如果曾经接入,则能够间接申请应用,否则发动一次表接入申请,审批通过后会由零碎主动进行操作。
散发工作
对于散发作业,须要用户进行创立,以 Iceberg 散发工作为例:
■ 字段筛选
抉择出散发作业应用的曾经接入到平台的数据源表字段
在抉择一些工作的运行配置(如资源,运行环境)后,就能够创立并运行一个散发工作,咱们能够看到对应惟一一个 Flink 平台工作 ID:
此外,咱们还提供了丰盛的监控查问,元数据信息查问等性能,充分利用了实时计算平台的已有组件,实现了传输零碎与实时计算零碎的紧密结合。
六、总结与瞻望
实践证明,咱们抉择基于 Flink 进行输入传输零碎的开发,是个理智且正确的决定。在最小的开发成本下,从性能和效率及可维护性上,齐全解决了之前遗留的问题,全面晋升了之家接入 / 散发 / 数据订阅的效率和用户体验,也晋升了咱们在数据传输方面的技术能力。
最近咱们在数据湖方向投入了较多的精力,传输零碎目前也曾经初步反对数据接入数据湖,将来心愿能够不断完善相干性能,大幅晋升数据湖数据接入的能力,反对用户一键入湖,增强整个数据体系的整合。
另一方面,咱们看到 Flink 新版本提供了许多新性能新工具。例如 FLIP-27 Source 和 OperatorCoordinator,咱们心愿能够借由这两个全新的机制和工具,持续优化咱们的代码,拓展相干性能。对于新推出 Upsert-Kafka,咱们曾经开始尝试在 Flink 计算平台上进行初步的开发和整合,心愿之后将 Upsert-Kafka 与传输零碎买通,持续扩大与丰盛实时计算和传输的业务场景!
参考资料:
[1] https://github.com/pingcap/ti…
[2] https://github.com/zendesk/ma…
作者介绍:
刘首维,本科毕业于大连理工大学,Apache Flink Contributor,Scala/Akka 重度爱好者,19 年退出汽车之家负责实时计算平台和数据传输平台数据的开发和保护。