git 地址
https://github.com/alibaba/canal
架构
(图片来自:https://www.jianshu.com/p/0ccbd1a1a5ec)
代码
-
Demo
com/alibaba/otter/canal/parse/MysqlBinlogDumpPerformanceTest.java
-
start
// com/alibaba/otter/canal/parse/inbound/AbstractEventParser.java
public void start() {
super.start();
MDC.put("destination", destination);
// 配置transaction buffer
// 初始化缓冲队列
transactionBuffer.setBufferSize(transactionSize);// 设置buffer大小
transactionBuffer.start();
// 构造bin log parser
binlogParser = buildParser();// 初始化一下BinLogParser
binlogParser.start();
// 启动工作线程
parseThread = new Thread(new Runnable() {
public void run() {
MDC.put("destination", String.valueOf(destination));
ErosaConnection erosaConnection = null;
while (running) {
try {
// 开始执行replication
// 1. 构造Erosa连接,对于 Mysql 而言,就是连接 Mysql
erosaConnection = buildErosaConnection();
// 2. 启动一个心跳线程,定期往 EventSink 传输数据,
// 保证下游能收到数据(在上游 mysql 无 binlog 时),能知道 Canal server 自身是否工作正常。
startHeartBeat(erosaConnection);
// 3. 执行 dump 前的准备工作,包括如下:
// 检测 BinlogFormat,BinlogImage
// show variables like 'binlog_format',参考:https://www.cnblogs.com/xingyunfashi/p/8431780.html
// show variables like 'binlog_row_image' -> 参考:https://blog.csdn.net/actiontech/article/details/81701362
preDump(erosaConnection);
// 连接源 mysql
erosaConnection.connect();
// show variables like 'server_id';
long queryServerId = erosaConnection.queryServerId();
if (queryServerId != 0) {
serverId = queryServerId;
}
// 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 (startPosition == null) {
throw new PositionNotFoundException("can't find start position for " + destination);
}
........
// 重新链接,因为在找position过程中可能有状态,需要断开后重建
erosaConnection.reconnect();
final SinkFunction sinkHandler = new SinkFunction<EVENT>() {
private LogPosition lastPosition;
public boolean sink(EVENT event) {
try {
CanalEntry.Entry entry = parseAndProfilingIfNecessary(event, false);
if (!running) {
return false;
}
if (entry != null) {
exception = null; // 有正常数据流过,清空exception
transactionBuffer.add(entry);
// 记录一下对应的positions
this.lastPosition = buildLastPosition(entry);
// 记录一下最后一次有数据的时间
lastEntryTime = System.currentTimeMillis();
}
return running;
} catch (TableIdNotFoundException e) {
throw e;
} catch (Throwable e) {
if (e.getCause() instanceof TableIdNotFoundException) {
throw (TableIdNotF