整体架构如下图所示,主要包括 DTS(Data Transmission Service) Source、DTS Core、DTS Sink 三大模块,具体功能如下:
-
DTS Source 接入不同 MQ 数据源,支持 Kafka、RocketMQ 等
-
DTS Sink 将数据输出到目标数据源,支持 HDFS、Hive 等
-
DTS Core 贯穿整个数据同步流程,通过 Source 读取源端数据,经过 DTS Framework 处理,最后通过 Sink 将数据输出到目标端。
-
DTS Framework 集成类型系统、文件切分、Exactly Once、任务信息采集、事件时间、脏数据收集等核心功能
-
支持 Yarn 部署模式,资源调度、管理比较弹性
DTS Dump架构图
Exactly Once
Flink 框架通过 Checkpoint 机制,能够提供 Exactly Once 或者 At Least Once 语义。为了实现 MQ-Hive 全链路支持 Exactly-once 语义,还需要 MQ Source、Hive Sink 端支持 Exactly Once 语义。本文通过 Checkpoint + 2PC 协议实现,具体过程如下:
-
数据写入时,Source 端从上游 MQ 拉取数据并发送到 Sink 端;Sink 端将数据写入到临时目录中
-
Checkpoint Snapshot 阶段,Source 端将 MQ Offset 保存到 State 中;Sink 端关闭写入的文件句柄,并保存当前 Checkpoint ID 到 State 中;
-
Checkpoint Complete 阶段,Source 端 Commit MQ Offset;Sink 端将临时目录中的数据移动到正式目录下
-
Checkpoint Recover 阶段,加载最新一次成功的 Checkpoint 目录并恢复 State 信息,其中 Source 端将 State 中保存的 MQ Offset 作为起始位置;Sink 端恢复最新一次成功的 Checkpoint ID,并将临时目录的数据移动到正式目录下
实现优化
在实际使用场景中,特别是大并发场景下,HDFS 写入延迟容易有毛刺,因为个别 Task Snapshot 超时或者失败,导致整个 Checkpoint 失败的问题会比较明显。因此针对 Checkpoint 失败,提高系统的容错性以及稳定性就比较重要。
这里充分利用 Checkpoint ID 严格单调递增的特性,每一次做 Checkpoint 时,当前 Checkpoint ID 一定比以前大,因此在 Checkpoint Complete 阶段,可以提交小于等于当前 Checkpoint ID 的临时数据。具体优化策略如下:
-
Sink 端临时目录为{dump_path}/{next_cp_id},这里 next_cp_id 的定义是当前最新的 cp_id + 1
-
Checkpoint Snapshot 阶段,Sink 端保存当前最新 cp_id 到 State,同时更新 next_cp_id 为 cp_id + 1
-
Checkpoint Complete 阶段,Sink 端将临时目录中所有小于等于当前 cp_id 的数据移动到正式目录下
-
Checkpoint Recover 阶段,Sink 端恢复最新一次成功的 cp_id,并将临时目录中小于等于当前 cp_id 的数据移动到正式目录下
类型系统
由于不同数据源支持的数据类型不一样,为了解决不同数据源间的数据同步以及不同类型转换兼容的问题,我们支持了 DTS 类型系统,DTS 类型可细化为基础类型和复合类型,其中复合类型支持类型嵌套,具体转换流程如下:
-
在 Source 端,将源数据类型,统一转成系