持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第7天,点击查看活动详情
前言
由于业务的增长,目前 MySQL 对于千万级数据量的查询性能相对比较差,为了适应后续业务数据的增长,提高搜索速度;我们在技术选型上采用了 Elasticsearch 来存储,原始数据还是存 MySQL,那么如何将 MySQL 的数据实时同步到 ElasticSearch。我们选择了目前业界比较常用的增量同步工具Canal。
1、概述
1.1 canal是什么
canal是阿里巴巴旗下的一款开源项目。基于数据库增量日志
解析,提供增量数据订阅&消费,目前主要支持了MySQL。
1.1.1 数据库增量日志(binlog)
当我们对数据库进行数据操作(增删改)等操作时,mysql 如果开启 binlog ,会把当前的操作记录到 binlog 日志中,它就是相当于 mysql 的日志文件。
binlog有三种日志格式:
- STATEMENT: 只记录修改的 sql 语句 ,不记录数据。无法恢复数据。
- ROW : 不记录每一条SQL语句的上下文信息,仅需记录哪条数据被修改了,修改成了什么样子了
- MIXED: STATEMENT + ROW
要进行数据同步一般使用 ROW 模式。
mysql的配置:
[mysqld]
log-bin=mysql-bin # 开启 binlog
binlog-format=ROW # 选择 ROW 模式
server_id=1 # 配置 MySQL replaction 需要定义,不要和 canal 的 slaveId 重复
1.2 需求背景
- 当前数据存储在 ES 上,使用 Datax 每天凌晨进行全量同步,主要存在的问题是实时性不够。当业务中,比如有人之前受到“行政处罚”,那他来部门办理撤销后,想马上去办理其他业务的话,那么如果不及时同步这条数据信息,其他部门还查询得到他还未撤销该项数据,会导致数据不一致,业务延迟。所以,这个时候需要有个实时同步的工具及时同步更新数据。
2 canal的工作原理
2.1 mysql主从同步原理
- Master主库,启动Binlog机制,将变更数据写入Binlog文件;
- Slave(I/O thread),从Master主库拉取binlog日志,将它拷贝到Slave的中继日志(relay log)中;
- Slave(SQL thread),回放Binlog,更新从库数据;
其中 I/0 线程 接收binlog ,SQL 线程 执行变更
启用 binlog 注意点:
- Master主库一般会有多台Slave订阅,且Master主库要支持业务系统实时变更操作,服务器资源会有瓶颈;
- 需要同步的数据表一定要有主键;
2.2 canal工作原理
- canal 模拟 MySQL slave 的交互协议,伪装自己为 MySQL slave ,向 MySQL master 发送dump 协议
- MySQL master 收到 dump 请求,开始推送 binary log 给 slave (即 canal )
- canal 解析 binary log 对象(原始为 byte 流)
3 canal应用使用
目前使用 canal 有两个应用,1个 server 端,1个 client 端。使用版本最新版的 1.1.5, 当然 client 端也可以自己实现。
- canal.deployer-1.1.5-SNAPSHOT = server 端
- canal.adapter-1.1.5 client端
- canal.admin-1.1.5 :canal server 配置的界面化操作,(后续提供,方便实施配置) 端口(8089)
3.1 实践
以下展示实践过程中,canal 的使用方式。
- server 端连接 mysql,读取 binlog 日志,然后存储起来
- client 端 消费 server 端的 binlog
- 一个 server 配置了两个 canal 实例(instance),每个client 连接一个实例。
- 每个实例模拟为 mysql 的 slave ,saveid 配置要不相同,都会拉取 Mysql 主节点的binlog
注意
Canal server 上的 一个 instance 只能一个 client 消费
3.2 server 和 client 端的交互
server 和 client 端 是 c/s 模式通信 ,server (netty)client(NIO 非阻塞异步I/0)
- canal server 启动后,没有 client 端,server 不会 mysql 拉取数据
- client 会主动发去拉取请求,服务端 模拟成 slave 去主库拉取 binlog
- 通常Canal客户端是一个死循环,这样客户端一直调用get方法,服务端也就会一直拉取binlog。
3.2.1 增量订阅/消费设计
- subscribe:订阅需要哪些表或者库的binlog日志解析
- get :批量获取 服务端的解析好的binlog 对象
- rollback: 回滚上一次的get请求,重新获取数据。
- ack:确认消费成功,通知服务端进行删除
3.3 canal server
- Server 代表一个 canal 运行实例,对应于一个 jvm
- instance 对应于一个数据队列
instance模块:
- eventParser (数据源接入,模拟slave协议和master进行交互,协议解析)
- eventSink (Parser和Store链接器,进行数据过滤,加工,分发的工作)
- eventStore (数据存储)
- metaManager (增量订阅&消费信息管理器)
- Put : Sink模块进行数据存储的最后一次写入位置
- Get : 数据订阅获取的最后一次提取位置
- Ack : 数据消费成功的最后一次消费位置
4 canal的使用
目前 canal 在业务中使用场景,主要有两个,分别是进行数据同步,订阅数据变化,进行业务处理。
4.1 数据同步
- 数据同步流程
4.1.1 MySQL 到 es 同步
使用 canal adapter 进行数据同步时,需要配置 源表到目标表的配置,主要是个 yml 文件,内容如下:
放置在 adapter目录下 conf/es6 下
当配置放入后,client就可以进行数据同步了。
当新增配置后,只需把配置文件放入配置文件上,client 端 后自动加载配置文件。
4.2 监控 MySQL 数据变化进行数据处理
- 后端服务作为client监听数据库变更,然后将变更的数据写入MQ进行任务下发。
5 目前使用性能情况
这部分,主要是对目前使用 canal 进行大批量数据同步存在性能问题的情况,给大家做个输入。目前做的性能测试还是相当有限,后续如果要大范围使用,我个人认为还是得根据现场情况,进行更大数据量的同步测试。
5.1 增量同步测试
在目前,给予 canal 的地位就是进行增量同步,同步过程中,我们分为 MySQL 到 MySQL,MySQL 到 ES
5.1.1 mysql库到mysql库同步
数据量:65870
insert | update | delete | |
---|---|---|---|
mysql 从库 | 有点快, | 飞快 | 瞬间来不及看 |
canal 同步 | 4分钟 | 差不多3,4分钟之间 | 4分钟 |
5.1.2 mysql 到 ES 的同步
数据量:65870
insert | update | delete | |
---|---|---|---|
Canal 入库 | 10分钟以内 | 10分钟左右 | 5分钟 |
5.2 全量同步性能测试
canal 也提供了 全量同步的接口供外部调用,但是效率有待验证。目前我们还是维持全量同步使用 DataX
全量同步 语法
curl http://127.0.0.1:8081/etl/rdb/mytest_person2.yml -X POST -d "params=2018-10-21 00:00:00"
mysql 到 es
curl http://127.0.0.1:8081/etl/es6/elsearch/ES6_test.yml -X POST
查看相关库的总数据
curl http://127.0.0.1:8081/count/rdb/mytest_person2.yml
5.3 官方的性能测试报告
阅读来源
官网最好的学习资源: canal 官网