开心一刻
今天,表妹问我:哥,我男朋友过两天要生日了,你们男生一般喜欢什么,帮忙推荐个礼物呗
我:预算多少
表妹:预算300
我:20块买条黑丝,剩下280给自己买支口红,你男朋友生日那天你都给自己用上
表妹:秒啊,哥
我:必须的嘛,你要知道男人最懂男人!
前情回顾
关于异源数据同步工具 DataX,我已经写了好几篇文章
异构数据源同步之数据同步 → datax 改造,有点意思异构数据源同步之数据同步 → datax 再改造,开始触及源码异构数据源同步之数据同步 → DataX 使用细节异构数据源数据同步 → 从源码分析 DataX 敏感信息的加解密异源数据同步 → DataX 为什么要支持 kafka?
推荐大家去看看,可以对 DataX 有个基本的了解,掌握其基本使用;示例代码:qsl-datax
需求背景
假设我们基于 XXL-JOB
实现调度,qsl-datax-hook
作为 XXL-JOB 执行器的同时也充当 DataX
的拉起方,三者调用关系如下
离线同步的数据量往往会很大,少则上万,多则上亿,所以同步过程一般会持续很长时间,如何确认同步仍在进行中呢?我们可以看日志,也可以查目标表的记录数,但都不够直观,好的实现方式应该是有同步任务查看页面,通过该页面可以查看到正在同步中的任务,以及这些任务已同步的数据量,所以问题就来到
如何获取 DataX 已同步数据量?
已同步数据量
换做是你们,你们会如何实现?或者说有什么思路?我提供下我的方案,是不是也是你们所想
DataX 的 Writer 往目标源写数据的时候,一次写多少数据我们就记录多少,然后累加并持久化,是不是就可以实时查看当前的已同步数据量呢?
具体如何实现了,我们可以基于 DataX 的日志来实现;我们在讲 异构数据源同步之数据同步 → datax 再改造,开始触及源码 的时候,对日志进行了调整,qsl-datax-hook
能够获取 DataX 进程的日志输出,所以我们只需要在 DataX 往目标源写入数据完成后往日志中写入一条记录(写入了多少数量),qsl-datax-hook 就能够获取该记录,从而得到写入数据量,然后进行累加操作;我们以 mysqlwriter
为例,来看看通过代码到底如何实现
- writer 往日志中写
同步数据量
从哪里找切入点,我就不绕弯子了
跟进 startWriteWithConnection
,有如下代码
可以看到是批量写入的,继续跟进 doBatchInsert
分两种情况
正常情况,批量插入并 commit 成功
异常情况,先回滚批量插入,然后通过
doOneInsert
逐条插入
所以在哪里写 同步数据量
的日志是不是清楚了,有两个地方需要写
doBatchInsert
批量插入 commit 之后写日志doOneInsert
单条插入后写日志
DataX 就算改造好了,是不是很简单?
- qsl-datax-hook 读取 DataX 日志中的
同步数据量
并持久化com.qsl.hook.DataXManager#exec
适配改造下即可
做持久化的时候一定要采用
update table_name set sync_rows = sync_rows + syncRows;
的方式,利用数据库的锁来避免并发问题,而采用 set 具体的值
update table_name set sync_rows = totalSyncRows;
会有并发覆盖问题,比如第一次将总量更新成 50000,而第二次可能将总量更新成 48000
至此,需求就算基本完成了;其他类型的 DataX writer 可以采用类似的方式来实现,具体就不演示了,你们自行去实现
总结
如果目标源支持事务,那么 已同步数据量
可以实现的很准确,如果目标源不支持事务,那么 已同步数据量
实现的就不会很准确,或者说实现难度非常高;文中讲到的日志方式,只是实现方式之一,还有其他的实现方式,例如
- 定时读取目标源的数据量
- 改造DataX,直接持久化
已同步数据量
update table_name set sync_rows = sync_rows + syncRows;
各种方式都有其优势,也存在其弊端,需要结合业务选择合适的方式