DM 源码阅读系列文章(三)数据同步处理单元介绍
作者:lan
本文为 DM 源码阅读系列文章的第三篇,上篇文章 介绍了 DM 的整体架构,DM 组件 DM-master 和 DM-worker 的入口代码,以及两者之间的数据交互模型。本篇文章详细地介绍 DM 数据同步处理单元(DM-worker 内部用来同步数据的逻辑单元),包括数据同步处理单元实现了什么功能,数据同步流程、运行逻辑,以及数据同步处理单元的 interface 设计。
数据同步处理单元
从上图可以了解到目前 DM 包含 relay log、dump、load、binlog replication(sync) 4 个数据同步处理单元,涵盖了以下数据同步处理的功能:
处理单元 |
功能 |
---|---|
relay log |
持久化 MySQL/MariaDB Binlog 到磁盘 |
dump |
从 MySQL/MariaDB dump 全量数据 |
load |
加载全量数据到 TiDB cluster |
binlog replication(sync) |
复制 relay log 存储的 Binlog 到 TiDB cluster |
数据同步流程
Task 数据同步流程初始化操作步骤:
- DM-master 接收到 task,将 task 拆分成 subtask 后 分发给对应的各个 DM-worker;
- DM-worker 接收到 subtask 后 创建一个 subtask 对象,然后 初始化数据同步流程。
从 初始化数据同步流程 的代码中我们可以看到,根据 task 配置项 task-mode 的不同,DM-worker 会初始化不同的数据同步流程:
task-mode |
同步流程 |
需要的数据同步处理单元 |
---|---|---|
all |
全量同步 -> 增量数据同步 |
relay log、dump、load、binlog replication(sync) |
full |
全量同步 |
dump、load |
incremental |
增量同步 |
relay log,binlog replication(sync) |
运行逻辑
DM 数据同步处理单元 interface 定义在 dm/unit
,relay log、dump、load、binlog replication(sync)都实现了该 interface(golang interface 介绍)。
实际上 DM-worker 中的数据同步处理单元分为两类:
- 全局共享单例。dm-worker 启动的时候只初始化一次这类数据同步处理单元,所有的 subtask 都可以使用这类数据同步处理单元的服务;relay log 属于这种类型。
- subtask 独享。dm-worker 会为每个 subtask 初始化一系列的数据同步处理单元;dump、load、binlog replication(sync)属于这种类型。
两类数据同步处理单元的使用逻辑不同,这篇文档会着重讲一下 subtask 独享的数据同步处理单元的使用逻辑,不会囊括更多的 relay log 相关的内容,后面会有单独一篇文章详细介绍它。
relay log 相关使用代码在 dm/worker/relay.go
、具体功能实现代码在 relay/relay.go
,有兴趣的同学也可以先行阅读一下相关代码,relay log 的代码注释也是比较丰富,并且简单易懂。
subtask 独享数据同步处理单元使用逻辑相关代码在 dm/worker/subtask.go
。subtask 对象包含的主要属性有:
- units:初始化后要运行的数据同步处理单元。
- currUnit:当前正在运行的数据同步处理单元。
- prevUnit:上一个运行的数据同步处理单元。
- stage:subtask 的运行阶段状态, 包含
New
、Running
、Paused
,Stopped
,Finished
,具体定义的代码在dm/proto/dmworker.proto
。 - result:subtask 当前数据同步处理单元的运行结果,对应着 stage =
Paused/Stopped/Finished
的详细信息。
主要的逻辑有:
- 初始化 subtask 对象实例的时候会 编排数据同步处理单元的运行先后顺序。所有的数据同步处理单元都实现了
dm/unit
interface,所以接下来的运行中就不需要关心具体的数据同步处理单元的类型,可以按照统一的 interface 方法来运行数据同步处理单元,以及对其进行状态监控。 - 初始化各个数据同步处理单元。subtask 在运行前集中地初始化所有的数据同步处理单元,我们计划之后优化成在各个数据同步处理单元运行前再进行初始化,这样子减少资源的提前或者无效的占用。
-
数据同步处理单元运行状态监控。通过监控当前运行的数据同步处理单元的结果,将 subtask 的 stage 设置为
Paused/Stopped/Finished
。
* 如果 [当前的数据同步处理单元工作已经完成](https://github.com/pingcap/dm/blob/6855ea4e40bb5e3775709054a59a55c628a0922f/dm/worker/subtask.go#L190),则会根据 units 来 [选取下一个需要运行的数据同步处理单元](https://github.com/pingcap/dm/blob/6855ea4e40bb5e3775709054a59a55c628a0922f/dm/worker/subtask.go#L216),如果没有需要的数据同步处理单元,那么会将 subtask 的 stage 设置为 `Finished`。这里有个注意点,因为 binlog replication 单元永远不会结束,所以不会进入 `Finished` 的状态。
* 如果 [返回的 result 里面包含有错误信息](https://github.com/pingcap/dm/blob/6855ea4e40bb5e3775709054a59a55c628a0922f/dm/worker/subtask.go#L192),则会将 subtask 的 stage 设置为 `Paused`,并且打印具体的错误信息。
- 如果是用户手动暂停或者停止,则会将 subtask 的 stage 设置为
Paused/Stopped
。这里有个注意点,这个时候 stage=Paused
是没有错误信息的。 -
数据同步处理单元之间的运行交接处理逻辑。部分数据同步处理单元在开始工作的时候需要满足一些前置条件,例如 binlog replication(sync)的运行需要等待 relay log 处理单元已经储存下来其开始同步需要的 binlog 文件,否则 subtask 将处于 stage=
Paused
的暂停等待状态。
小结
本篇文章主要介绍了数据同步处理单元实现了什么功能,数据同步流程、运行逻辑,以及数据同步处理单元的 interface 设计。后续会分三篇文章详细地介绍数据同步处理单元的实现,包括:
- dump/load 全量同步实现
- binlog replication 增量同步实现
- relay log 实现
- 剖析Go编写的Socket服务器模块解耦及基础模块的设计
- hihocoder-平衡树·SBT
- mysql 查询数据库表结构
- Go语言基于Socket编写服务器端与客户端通信的实例
- 前端游戏编程基础-如何实现Canvas图像的拖拽、点击等操作
- 使用Go开发一个简单的服务器程序
- Golang URL解析
- golang实现基于redis和consul的可水平扩展的排行榜服务范例
- golang学习之旅:使用go语言操作mysql数据库
- golang微信支付服务端
- flume安装及配置介绍(二)
- Hbase关于Java常用API举例
- 【提问帖】GO中调用redis时,当并发量比较大时出现的问题。
- Redis学习笔记二
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Springboot+mybatis最简单的增删改查写法
- Head First设计模式——观察者模式
- spring security oauth2 资源服务/客户端无法正确获取权限
- EXTJS grid.column.renderer绑定失效
- Head First设计模式——装饰者模式
- spring security oauth2 资源服务器WebAsyncTask/DeferredResult接口调用报错InsufficientAuthenticationException
- Head First设计模式——简单工厂、工厂、抽象工厂
- Golang | 简介channel常见用法,完成goroutin通信
- Head First设计模式——单例模式
- 【日拱一卒】链表——两个有序的链表合并
- Head First设计模式——命令模式
- Flask表单之WTForms和flask-wtf
- Head First设计模式——适配器和外观模式
- 「2020最新」Spring最易学习教程 4—整合Mybatis 事务控制
- Head First设计模式——模板方法模式