binlog监听核心实现
在AbstractEventParser中启动1个parseThread线程做定时(thread线程sleep间隔时间为10-20s, 10000 + RandomUtils.nextInt(10000))从mysql服务器端拉取 binlog日志做处理。
启动监听拉取线程
-
配置transaction buffer初始化缓冲队列CanalEntry.Entry[]数组(队列大小默认为1024 byte)
-
构造并启动bin log parser的binlogParser
实例(AbstractMysqlEventParser子类有MysqlEventParser、RdsBinlogEventParserProxy、LocalBinlogEventParser、RdsLocalBinlogEventParser等实现), 核心为构建类 LogEventConvert,做slaver模拟和binlog dump。 -
启动parseThread定时sink的线程(while循环,空闲则sleep)
- buildErosaConnection构造Erosa连接,即调用socket或netty做数据库tcp连接。
- 启动一个心跳线程,保持tcp连接keepAlive不断开,避免重复创建新的socket对mysql服务端带来的压力。
- 执行dump前的准备工作
- 获取最后的位置信息位点信息EntryPosition position = findStartPosition(erosaConnection)
- 定义SinkFunction
- 开始dump数据
- 支持并发的话,创建multiStageCoprocessor进行多阶段处理
- 根据位点信息(GTID模式的话获取gtid;非gtid模式下,有journalName则使用journalName作为位点标识,否则使用时间戳timestamp作为开始位点)dump数据erosaConnection.dump(startPosition.getTimestamp(), multiStageCoprocessor);
- 设置请求binlog的命令参数 -> 打开socket网络连接 -> 通过inputStream获取binlog数据二进制量 -> 按binlog格式解析二进制流提取数据库event -> 更新位点(到redis等介质中)
AbstractEventParser#start()启动源码如下
public void start() {
super.start();
MDC.put("destination", destination);
// 配置transaction buffer
// 初始化缓冲队列
transactionBuffer.setBufferSize(transactionSize);// 设置buffer大小
transactionBuffer.start();
// 构造bin log parser, 构建的类 LogEventConvert
binlogParser = buildParser();// 初始化一下BinLogParser
binlogParser.start();
// 启动工作线程
parseThread = new Thread(new Runnable() {
public void run() {
MDC.put("destination", String.valueOf(destination));
ErosaConnection erosaConnection = null;
boolean isMariaDB = false;
while (running) {
try {
// 开始执行replication
// 1. 构造Erosa连接
erosaConnection = buildErosaConnection();
// 2. 启动一个心跳线程
startHeartBeat(erosaConnection);
// 3. 执行dump前的准备工作
preDump(erosaConnection);
erosaConnection.connect();// 链接
long queryServerId = erosaConnection.queryServerId();
if (queryServerId != 0) {
serverId = queryServerId;
}
if (erosaConnection instanceof MysqlConnection) {
isMariaDB = ((MysqlConnection) erosaConnection).isMariaDB();
}
// 4. 获取最后的位置信息
long start = System.currentTimeMillis();
logger.warn(
"---> begin to find start position, it will be long time for reset or first position");
EntryPosition position = findStartPosition(erosaConnection);
final EntryPosition startPosition = position;
if (startPo