本文详解canal的总体架构。mysql
1、总体架构


说明:sql
- server表明一个canal运行实例,对应于一个jvm
- instance对应于一个数据队列 (1个server对应1..n个instance)
instance模块:数据库
- eventParser (数据源接入,模拟slave协议和master进行交互,协议解析)
- eventSink (Parser和Store连接器,进行数据过滤,加工,分发的工做)
- eventStore (数据存储)
- metaManager (增量订阅&消费信息管理器)
2、各模块架构
2.1 Parser

整个parser过程大体可分为几步:架构
- Connection获取上一次解析成功的位置(若是第一次启动,则获取初始制定的位置或者是当前数据库的binlog位点)
- Connection创建链接,发生BINLOG_DUMP命令
- Mysql开始推送Binary Log
- 接收到的Binary Log经过Binlog parser进行协议解析,补充一些特定信息
- 传递给EventSink模块进行数据存储,是一个阻塞操做,直到存储成功
- 存储成功后,定时记录Binary Log位置
2.2 Sink

说明:jvm
- 数据过滤:支持通配符的过滤模式,表名,字段内容等
- 数据路由/分发:解决1:n (1个parser对应多个store的模式)
- 数据归并:解决n:1 (多个parser对应1个store)
- 数据加工:在进入store以前进行额外的处理,好比join
1 数据1:n业务 :
为了合理的利用数据库资源, 通常常见的业务都是按照schema进行隔离,而后在mysql上层或者dao这一层面上,进行一个数据源路由,屏蔽数据库物理位置对开发的影响,阿里系主要是经过cobar/tddl来解决数据源路由问题。 因此,通常一个数据库实例上,会部署多个schema,每一个schema会有由1个或者多个业务方关注。设计
2 数据n:1业务:
一样,当一个业务的数据规模达到必定的量级后,必然会涉及到水平拆分和垂直拆分的问题,针对这些拆分的数据须要处理时,就须要连接多个store进行处理,消费的位点就会变成多份,并且数据消费的进度没法获得尽量有序的保证。 因此,在必定业务场景下,须要将拆分后的增量数据进行归并处理,好比按照时间戳/全局id进行排序归并.server
2.3 Store
目前实现了Memory内存、本地file存储以及持久化到zookeeper以保障数据集群共享。 Memory内存的RingBuffer设计:blog

定义了3个cursor排序
- Put : Sink模块进行数据存储的最后一次写入位置
- Get : 数据订阅获取的最后一次提取位置
- Ack : 数据消费成功的最后一次消费位置
借鉴Disruptor的RingBuffer的实现,将RingBuffer拉直来看:队列

实现说明:
Put/Get/Ack cursor用于递增,采用long型存储 buffer的get操做,经过取余或者与操做。(与操做: cusor & (size – 1) , size须要为2的指数,效率比较高)