在学习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. STL空间配置器源码分析(四)bitmap_allocator

    一.摘要 bitmap_allocator是STL空间分配器的其中一种,它采用内存池策略,最多存储64条空闲链表(freelist,实际是一块空间连续的内存区,后面也称为超级块),每条空闲链表存储的内 ...

  2. 新手小白入门C语言第五章:C存储类

    一 .存储类 在理解C的存储类之前,首先要搞懂的概念有:作用域.生存周期.连接属性 C中的存储类说明符实际上是上述属性的不同组合 作用域:一个C变量的作用域可以是 代码块作用域(在函数内部代码块中定义 ...

  3. optimoptions requires Optimization Toolbox(optimoptions 需要 Optimization Toolbox)解决方法

    问题:在下载版的matlab中做coursera的machine learning里的ex2,做到 1.2.3 Learning parameters using fminunc 时出现optimop ...

  4. 「Python实用秘技07」pandas中鲜为人知的隐藏排序技巧

    本文完整示例代码及文件已上传至我的Github仓库https://github.com/CNFeffery/PythonPracticalSkills 这是我的系列文章「Python实用秘技」的第7期 ...

  5. Go通过cobra快速构建命令行应用

    来自jetbrains Go 语言现状调查报告 显示:在go开发者中使用go开发实用小程序的比例为31%仅次于web,go得益于跨平台.无依赖的特性,用来编写命令行或系统管理这类小程序非常不错. 本文 ...

  6. JMeter如何设置中文

    打开Option => Choose Language => Chinese

  7. 推荐系统 TOP K 评价指标

    目录 符号说明 示例数据 一.Hit Rate 二.Recall 三.NDCG 符号说明 \(top\_k\): 当前用户预测分最高的k个items,预测分由高到低排序 $pos$: 当前用户实际点击 ...

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

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

  9. 五二不休息,今天也学习,从JS执行栈角度图解递归以及二叉树的前、中、后遍历的底层差异

    壹 ❀ 引 想必凡是接触过二叉树算法的同学,在刚上手那会,一定都经历过题目无从下手,甚至连题解都看不懂的痛苦.由于leetcode不方便调试,题目做错了也不知道错在哪里,最后无奈的cv答案后心里还不断 ...

  10. Linux vs Unix - Linux与Unix到底有什么不同?

    来自:Linux迷链接:https://www.linuxmi.com/linux-vs-unix.html Linux和Unix这两个术语可以互换地用来指同一操作系统.这在很大程度上是由于他们惊人的 ...