在学习Canal的时候很好奇Canal是如何模拟成MySql Slave来接收数据的

MySql Slave会向主库发送dump协议来接收bin-log数据

Canal也是类似,在发起dump协议时会先获取MySql当前的bin-log信息,在根据自身已经消费的偏移量来判断从哪个位置开始获取,最后MySql将bin-log事件返回给Canal

Canal实现向MySql复制bin-log的实现类在MysqlEventParser,可以在AbstractEventParser中看到MysqlEventParser的执行流程

代码流程

// 开始执行replication
// 1. 构造Erosa连接
erosaConnection = buildErosaConnection();
// 2. 启动一个心跳线程
startHeartBeat(erosaConnection);
// 3. 执行dump前的准备工作
preDump(erosaConnection);
erosaConnection.connect();// 链接
// 4. 获取最后的位置信息
EntryPosition position = findStartPosition(erosaConnection);
final EntryPosition startPosition = position;
// 重新链接,因为在找position过程中可能有状态,需要断开后重建
erosaConnection.reconnect();
//调用dump方法开始同步
erosaConnection.dump

执行dump前

buildErosaConnection()方法会将配置文件中的MySql配置转换为MysqlConnection

protected ErosaConnection buildErosaConnection() {
return buildMysqlConnection(this.runningInfo);
}

findStartPosition(erosaConnection)方法会去解析和获取位点信息,

通过CanalLogPositionManagerCanalMetaManager

CanalLogPositionManager会去解析meta.dat里的数据,Canal提供了很多种读取meta.dat的方式

可以看看meta.dat里存了什么

{
"clientDatas": [{
"clientIdentity": {
"clientId": 1001,
"destination": "example",
//过滤策略
"filter": ".*\\..*"
},
"cursor": {
"identity": {
"slaveId": -1,
"sourceAddress": {
"address": "localhost",
"port": 3307
}
},
//记录的位点信息
"postion": {
"gtid": "",
"included": false,
"journalName": "binlog.000002",
"position": 11628,
"serverId": 1,
"timestamp": 1639646437000
}
}
}],
//实例名称
"destination": "example"
}

获取位点

//读取本地的meta.dat
LogPosition logPosition = logPositionManager.getLatestIndexBy(destination);
//如果没获取到,就获取新的,默认从当前最后一个位置进行消费
findEndPositionWithMasterIdAndTimestamp(mysqlConnection)
//从Mysql获取
ResultSetPacket packet = mysqlConnection.query("show master status");
//如果没有指定binlogName,尝试按照timestamp进行查找
findByStartTimeStamp(mysqlConnection, entryPosition.getTimestamp())

接着往下看,会看到Canal创建解析bin-log处理器,调用BinlogParser来解析成事件

final SinkFunction sinkHandler = new SinkFunction<EVENT>()

CanalEntry.Entry event = binlogParser.parse(bod, isSeek);

最后就是开始调用dump()了,在此之前会判断是否开启了并行,这个配置是

canal.instance.parser.parallel = true

如果是true的话就是用MultiStageCoprocessor处理其去解析,否则就是用上边创建的sinkHandler去处理

执行dump

Canal的dump方法实现在MysqlConnection,通过传入bin-log的文件名和偏移量和串行或并行的处理器

并行处理
public void dump(String binlogfilename, Long binlogPosition, MultiStageCoprocessor coprocessor)
串行处理
public void dump(String binlogfilename, Long binlogPosition, SinkFunction func)

MultiStageCoprocessorSinkFunction是用来解析bin-log

区别是MultiStageCoprocessor是用多线程来处理

针对解析器提供一个多阶段协同的处理
1. 网络接收 (单线程)
2. 事件基本解析 (单线程,事件类型、DDL解析构造TableMeta、维护位点信息)
3. 事件深度解析 (多线程, DML事件数据的完整解析)
4. 投递到store (单线程)

两个方法的前几步都是相同的

  updateSettings();
loadBinlogChecksum();
sendRegisterSlave(); //向Mysql注册从节点
sendBinlogDump(binlogfilename, binlogPosition);

updateSettings();方法会向MySql执行一些设置sql,比如超时设置checksum、设置一个server_id、设置心跳等

 update("set wait_timeout=9999999");
update("set @master_binlog_checksum= @@global.binlog_checksum");
update("set @slave_uuid=uuid()");

顺便可以看看Canal是怎么执行sql的,他是将sql转成字节,并封装成数据包,然后通过SocketChannel传输给MySql执行

 //封装成数据包
public byte[] toBytes() {
byte[] data = new byte[4];
data[0] = (byte) (packetBodyLength & 0xFF);
data[1] = (byte) (packetBodyLength >>> 8);
data[2] = (byte) (packetBodyLength >>> 16);
data[3] = getPacketSequenceNumber();
return data;
}
//传输给Mysql
PacketManager.writeBody(connector.getChannel(), bodyBytes);

loadBinlogChecksum();方法向MySql查询刚刚设置的checksum,并赋值给系统

query("select @@global.binlog_checksum");

这是由于binlog event发送回来的时候需要,在最后获取event内容的时候,会增加4个额外字节做校验用。mysql5.6.5以后的版本中binlog_checksum=crc32,而低版本都是binlog_checksum=none

sendBinlogDump()发送dump请求,通过BinlogDumpCommandPacket封装成dump数据包,向MySql发送COM_BINLOG_DUMP指令

bin-log数据会从SocketChannel中返回,Canal会去创建一个DirectLogFetcher对象去接收数据,然后创建解码器

//遍历数据
while (fetcher.fetch()) {
//消费
accumulateReceivedBytes(fetcher.limit());
LogEvent event = null;
//解码
event = decoder.decode(fetcher, context); if (event == null) {
throw new CanalParseException("parse failed");
}
//还原成Canal事件,这里的func是上边创建的sinkHandler
if (!func.sink(event)) {
break;
}
//发送确认包
if (event.getSemival() == 1) {
sendSemiAck(context.getLogPosition().getFileName(), context.getLogPosition().getPosition());
}
}

以上就是Canal实现dump并获取日志的过程

https://juejin.cn/post/6844904077583712264

https://www.helloworld.net/p/5322586930

Canal实现MySQL协议的更多相关文章

  1. 使用canal通过mysql复制协议从binlog实现热数据nosql缓存(2)

    开启mysql binlog功能 以5.7版本为例,找到/etc/mysql/mysql.conf.d/mysqld.cnf [mysqld] pid-file = /var/run/mysqld/m ...

  2. mysql 协议分析

    MYSQL Binlog协议分析 此处不讨论建立连接,验证和handshake的交互协议 Binlog协议 一个MYSQL 通信包由包头包体组成 包体根据具体的交互协议有自身的组成结构, 在binlo ...

  3. 转载:阿里canal实现mysql binlog日志解析同步redis

    from: http://www.cnblogs.com/duanxz/p/5062833.html 背景 早期,阿里巴巴B2B公司因为存在杭州和美国双机房部署,存在跨机房同步的业务需求.不过早期的数 ...

  4. alibaba/canal 阿里巴巴 mysql 数据库 binlog 增量订阅&消费组件

    基于日志增量订阅&消费支持的业务: 数据库镜像 数据库实时备份 多级索引 (卖家和买家各自分库索引) search build 业务cache刷新 价格变化等重要业务消息 项目介绍 名称:ca ...

  5. canal —— 阿里巴巴mysql数据库binlog的增量订阅&消费组件

    阿里巴巴mysql数据库binlog的增量订阅&消费组件canal ,转载自  https://github.com/alibaba/canal 最新更新 canal QQ讨论群已经建立,群号 ...

  6. 阿里巴巴开源项目: canal 基于mysql数据库binlog的增量订阅&消费

    背景 早期,阿里巴巴B2B公司因为存在杭州和美国双机房部署,存在跨机房同步的业务需求.不过早期的数据库同步业务,主要是基于trigger的方式获取增 量变更,不过从2010年开始,阿里系公司开始逐步的 ...

  7. 使用canal获取mysql的binlog传输给kafka,并交由logstash获取实验步骤

    1. 实验环境 CPU:4 内存:8G ip:192.168.0.187 开启iptables防火墙 关闭selinux java >=1.5 使用yum方式安装的java,提前配置好JAVA_ ...

  8. canal 基于Mysql数据库增量日志解析

    canal 基于Mysql数据库增量日志解析  1.前言  最近太多事情 工作的事情,以及终身大事等等 耽误更新,由于最近做项目需要同步监听 未来电视 mysql的变更了解到公司会用canal做增量监 ...

  9. Docker安装canal、mysql进行简单测试与实现redis和mysql缓存一致性

    一.简介 canal [kə'næl],译意为水道/管道/沟渠,主要用途是基于 MySQL 数据库增量日志解析,提供增量数据订阅和消费. 早期阿里巴巴因为杭州和美国双机房部署,存在跨机房同步的业务需求 ...

随机推荐

  1. Java学习day5

    API即应用程序编程接口,Java所包含的方法以及类很多,如果要使用他们就得了解这些的API如何使用,因为API多而复杂,我们可以通过帮助文档查询 与c/c++类似,Java通过Scanner类就可以 ...

  2. TemplatesImpl利用链

    FastJson利用链 Fastjson的版本在1.2.22-1.2.24主要有两条链利用TemplatsImpl和JdbcRowSetImpl利用链先来学习TemplatsImpl利用链,这个与前面 ...

  3. Java语言学习day40--8月15日

    ###12可变参数的注意事项 *A:可变参数的注意事项 /* * 可变参数的注意事项 * 1. 一个方法中,可变参数只能有一个 * 2. 可变参数,必须写在参数列表的最后一位 */ public st ...

  4. 【Vue3+Express实战】项目开发环境搭建

    大家好,我是半夏,一个刚刚开始写文的沙雕程序员.如果喜欢我的文章,可以关注 点赞 加我微信:frontendpicker,一起学习交流前端,成为更优秀的工程师-关注公众号:搞前端的半夏,了解更多前端知 ...

  5. 【Hadoop】ZooKeeper组件

    目录 一.配置时间同步 二.部署zookeeper(master节点) 1.使用xftp上传软件包至~ 2.解压安装包 3.创建 data 和 logs 文件夹 4.写入该节点的标识编号 5.修改配置 ...

  6. C#/VB.NET 获取Excel中图片所在的行、列坐标位置

    本文以C#和vb.net代码示例展示如何来获取Excel工作表中图片的坐标位置.这里的坐标位置是指图片左上角顶点所在的单元格行和列位置,横坐标即顶点所在的第几列.纵坐标即顶点所在的第几行.下面是获取图 ...

  7. 2022最新IntellJ IDEA的zheng开发部署文档

    目录 前景提示 一.环境整合 构建工具(参考工具部署方式) 二.git 导入编译器 三.模块描述浅析 四.配置文档 1.总配置 2.数据库配置 3.密码设置 4.配置建议 五.在IDEA中执行MySQ ...

  8. Linux和kali Linux 介绍

    常用的渗透测试平台 CTFTools kali (近亲 Ubuntu) Parrot Security OS PentestBox --由印度人开发,运行在Windows下的渗透测试环境 kali L ...

  9. SQL注入的几种类型

    SQL注入就是: 将构造SQL语句来插入到web提交的数据之中,让其返回数据时运行自己构造的恶意SQL语句. SQL注入构造恶意SQL语句的方法有: 构造堆叠,构造闭合,构造报错,构造时间差,等等 S ...

  10. selenium模块 phantomJs 谷歌无可视界面

    参考微博: 什么是selenium 一款基于浏览器自动化的模块 什么是浏览器自动化 通过脚本程序或者python代码,这组程序或者代码表示一些行为动作,selenium可以让这些行为动作映射到浏览器中 ...