canal概述

前言

canal是模拟mysql从节点,从而可以和mysql主库进行binlog的摘取,并消费。
在这里插入图片描述
用户的数据都是写入主库Master,Master将数据写入到本地二进制日志binary log中。从库Slave启动一个IO线程(I/O Thread)从主从同步binlog,写入到本地的relay log中,同时slave还会启动一个SQL Thread,读取本地的relay log,写入到本地,从而实现数据同步。了解更多请参考《mysql的复制及备份

Canal架构

canal是模块依赖图及详细模块如下所示:
在这里插入图片描述

  1. deployer:部署模块。通过该模块提供的CanalLauncher来解析配置文件并启动canalServer.
  2. server模块:canal服务器端。核心接口为CanalServer
  3. instance模块:一个server有多个instance。每个instance都会模拟成一个mysql实例的slave。instance模块有四个核心组成部分:parser模块、sink模块、store模块,meta模块。核心接口为CanalInstance
  4. parser模块:数据源接入,模拟slave协议和master进行交互,协议解析。parser模块依赖于dbsync、driver,filter模块。
  5. driver模块和dbsync模块:这两个模块实际上是parser模块的组件。事实上parser是通过driver模块与mysql建立连接,从而获取到binlog。由于原始的binlog都是二进制流,需要解析成对应的binlog事件,这些binlog事件对象都定义在dbsync模块中,dbsync 模块来自于淘宝的tddl。
  6. filter模块:用于过滤parser获取的数据
  7. sink模块:parser和store链接器,进行数据过滤,加工,分发的工作。核心接口为CanalEventSink
  8. store模块:数据存储。核心接口为CanalEventStore
  9. meta模块:增量订阅&消费信息管理器,核心接口为CanalMetaManager,主要用于记录canal消费到的mysql binlog的位置,
  10. client模块:canal的客户端。核心接口为CanalConnector
  11. protocol模块:client和server模块之间的通信协议
  12. example模块:提供client模块使用案例。
  13. common模块:主要是提供了一些公共的工具类和接口。

Driver模块

driver,顾名思义为驱动。熟悉jdbc编程的同学都知道,当项目中需要操作数据库(oracle、sqlserver、mysql等)时,都需要在项目中引入对应的数据库的驱动。以mysql为例,我们需要引入的是mysql-connector-java这个jar包,通过这个驱动包来与数据库进行通信。

那么为什么canal不使用mysql官方提供的驱动包,而要自己编写一个driver模块?原因在于mysql-connector-java驱动包只是实现了JDBC规范,方便我们在程序中对数据库中的数据进行增删改查。

对于获取并解析binlog日志这样的场景,mysql-connector-java并没有提供这样的功能。因此,canal编写了自己的driver模块,提供了基本的增删改查功能,并提供了直接获取原始binlog字节流的功能,其他模块在这个模块的基础上对binlog字节进行解析.

#可以获得当前的binlog位置
show master status

#查询最早的binlog位置
show binlog events limit 1

#主要用于判断MySQL复制同步状态
#是否下面2线程在运行,判断mysql是否向名提供binlog服务
#Slave_IO_Running线程:负责把主库的bin日志(Master_Log)内容,投递到从库的中继日志上(Relay_Log)
#Slave_SQL_Running线程:负责把中继日志上的语句在从库上执行一遍
show slave status

#用于查看binlog格式,值为STATEMENT,MIXED,ROW的一种
show variables like 'binlog_format'

meta模块

管理一些元数据信息包括:

  1. 订阅信息,即是否有消费着订阅binlog.
  2. 每个Client消费游标信息,即消费进度
  3. 每个Client消费批次信息,根据批次获取此批次的开始游标,结束游标
#将元数据存存储到zk中
ZooKeeperMetaManager
#将元数据存储到内存中
MemoryMetaManager
#组合memory + zookeeper的使用模式
MixedMetaManager:
#基于定时刷新的策略的mixed实现
PeriodMixedMetaManager
#先写内存,然后定时刷新数据到File 
FileMixedMetaManager:

Parser模块

EventParser在启动之前

  • CanalLogPositionManager
    mysql在主从同步过程中,要求slave自己维护binlog的消费进度信息。在slave机器的data目录下,都会有一个master.info文件,这个文件的作用就是存储主库的消费binlog解析进度信息。
  • CanalHAController
    为了保持binlog消费的高可用,通常会配置,主备mysql的地址。当主库心跳丢失,Mysql会接取从库的binlog.

EventParser在启动之后

  • 会更新一下eventParser中的filter
    一个mysql实例中可能会有多个库,每个库里面又会有多个表,可能我们只是想订阅某个库中的部分表,这个时候就需要进行过滤。
    1. eventFilter属性:使用配置项canal.instance.filter.regex的值进行白名单过滤。
    2. eventBlackFilter属性:使用配置项canal.instance.filter.black.regex进行黑名单过滤。

EventParser启动后,会创建一个工作线程跑(因为binlog是顺序结构的)

  1. 获取最后的位置信息
    1. CanalLogPositionManager中历史消费信息
    2. 如果1没有,获取我们配置文件指定binlogName + offest
    3. 如果2没有,使用“show master status”获取Mysql的最新位置
  2. 根据获取的位置信息,在binlog中向上查找最新事务的位置(以事务维度消费,保证数据一致性)
  3. 构造SinkFunction
  4. 利用Driver的fetcher拉取数据
  5. 利用dbsync模块解析数据
  6. 把解析好的数据向SinkFunction导出
  7. SinkFunction中对数据进行filter,并向Sink模块输出

Sink模块

sink是处理数据的路由&分发,一份parse数据经过sink后可以分发为多份,每份的数据可以根据自己的过滤规则不同而有不同的数据 .但现在只做了:

  1. 数据二次过滤
  2. 向Store模块导入数据

Store模块

Store模块用于binlog事件的存储 ,目前开源的版本中仅实现了Memory内存模式MemoryEventStoreWithBuffer。其实现借鉴了Disruptor的RingBuffer。简而言之,你可以把其当做一个环形队列,如下:

在这里插入图片描述

  • Put 操作:添加数据。event parser模块拉取到binlog后,并经过event sink模块过滤,最终就通过Put操作存储到了队列中。
  • Get操作:获取数据。canal client连接到canal server后,最终获取到的binlog都是从这个队列中取得。
  • Ack操作:确认消费成功。canal client获取到binlog事件消费后,需要进行Ack。你可以认为Ack操作实际上就是将消费成功的事件从队列中删除,如果一直不Ack的话,队列满了之后,Put操作就无法添加新的数据了。

Instance模块

每个instance都会模拟成一个mysql实例的slave.
在这里插入图片描述

  1. client向instance订阅服务,存到meta中
  2. parser启动,模拟slave接取对应的信息并导入sink
  3. sink将数据引入store
  4. client通过instance向store摘取数据

分库分表场景:比如产品数据拆分了4个库,位于不同的mysql实例上。正常情况下,我们需要配置四个CanalInstance。对应的,业务上要消费数据时,需要启动4个客户端,分别链接4个instance实例。

  1. 使用GroupEventParser,由GroupEventParser内部维护4个MysqlEventParser去4个不同的mysql实例去拉取binlog,
  2. 通过GroupEventSink并到一起到store中。
  3. client只需要启动1个客户端,链接这个CanalInstance即可.

Server模块

server包含多个instance实例,根据业务场景的不同大致可分为
在这里插入图片描述
右边的图是内置部署
直接在应用中嵌入CanalServerWithEmbeded,不需要独立部署canal。

左图表示的是Canal独立部署
不同的应用通过canal client与canal server进行通信,所有的canal client的请求统一由CanalServerWithNetty接受,之后CanalServerWithNetty会将客户端请求派给CanalServerWithEmbeded 进行真正的处理。

总结

我们可以利用CanalServerWithEmbeded进行扩展

  1. 与消息机制结合
  2. 与jdbc结合
  3. 其它

主要参考

CANAL源码解析

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值