后面的文章应用 canal 订阅 mysql 数据变动进而同步数据,这里钻研 canal 的外部个性,进而更好地应用 canal,大部分内容来自官网,还有一部分来自我的了解。
canal 主要用途是基于 MySQL 数据库增量日志解析,提供增量数据订阅和生产。
利用场景:
- 异构数据同步
- 数据库实时备份
- 业务 cache 刷新
原理
canal 模仿成 mysql slave 向 master 发送 dump 申请,收到 binlog 数据进行解析
slave 同步 master 原理:
- master 将扭转记录到二进制日志 (binary log) 中(这些记录叫做二进制日志事件,binary log events,能够通过 show binlog events 进行查看)
- slave 将 binary log events 拷贝到它的中继日志(relay log)
- slave 重做中继日志中的事件,将扭转反映它本人的数据
架构
server 代表一个 canal 运行实例,对应于一个 jvm
instance 对应一个数据队列,一个 destination,相当于一个数据库实例变更的监听,1 个 server 对应 1 - n 个 instance
instance 模块:
- eventParser (数据源接入,模仿 slave 协定和 master 进行交互,协定解析)
- eventSink (Parser 和 Store 链接器,进行数据过滤,加工,散发的工作)
- eventStore (数据存储)
- metaManager (增量订阅 & 生产信息管理器)
EventParser
- Connection 获取上一次解析胜利的地位 (如果第一次启动,则获取初始指定的地位或者是以后数据库的 binlog 位点)
- Connection 建设链接,发送 BINLOG_DUMP 指令
- Mysql 开始推送 Binaly Log
- 接管到的 Binaly Log 的通过 Binlog parser 进行协定解析,补充一些特定信息
- 传递给 EventSink 模块进行数据存储,是一个阻塞操作,直到存储胜利
- 存储胜利后,定时记录 Binaly Log 地位
EventSink
- 数据过滤:反对通配符的过滤模式,表名,字段内容等
- 数据路由 / 散发:解决 1:n (1 个 parser 对应多个 store 的模式)
- 数据归并:解决 n:1 (多个 parser 对应 1 个 store)
- 数据加工:在进入 store 之前进行额定的解决,比方 join
EventStore
Instance 设计
instance 代表了一个理论运行的数据队列,包含了 EventPaser,EventSink,EventStore 等组件。形象了 CanalInstanceGenerator,次要是思考配置的治理形式:
- manager 形式:提供 http 形式,能够和公司外部 web console/manager 零碎进行对接。
- spring 形式:基于 spring xml + properties 进行定义,通过 spring 配置
Spring 配置
spring 配置的原理是将整个配置形象为两局部:
- xxxx-instance.xml (canal 组件的配置定义,能够在多个 instance 配置中共享,在 canal.properties 中配置)
- xxxx.properties (每个 instance 通道都有各自一份定义,因为每个 mysql 的 ip,帐号,明码等信息不会雷同)
通过 spring 的 PropertyPlaceholderConfigurer 通过机制将其交融,生成一份 instance 实例对象,每个 instance 对应的组件都是互相独立的,互不影响
properties 配置文件
properties 配置分为两局部:
- canal.properties (零碎根配置文件,配置 destinations,注册 IP,启动端口)
- instance.properties (instance 级别的配置文件,每个 instance 一份,配置数据库信息,监听的表)
canal.properties 介绍:
canal 配置次要分为两局部定义:
- instance 列表定义 (列出以后 server 上有多少个 instance,每个 instance 的加载形式是 spring/manager 等)
- common 参数定义,比方能够将 instance.properties 的专用参数,抽取搁置到这里,这样每个 instance 启动的时候就能够共享.【instance.properties 配置定义优先级高于 canal.properties】
canal 如何保护一份增量订阅 & 生产的关系信息:
- 解析位点 (parse 模块会记录,上一次解析 binlog 到了什么地位,对应组件为:CanalLogPositionManager)
- 生产位点 (canal server 在接管了客户端的 ack 后,就会记录客户端提交的最初位点,对应的组件为:CanalMetaManager)
对应的两个位点组件,目前都有几种实现:
-
memory
- memory-instance.xml 中应用,所有的组件 (parser , sink , store) 都抉择了内存版模式,记录位点的都抉择了 memory 模式,重启后又会回到初始位点进行解析
- 速度最快,依赖起码(不须要 zookeeper)
- 场景:个别利用在 quickstart,或者是呈现问题后,进行数据分析的场景,不应该将其利用于生产环境
- zookeeper
- mixed
-
period:
- default-instance.xml 中应用,汇合了 zookeeper+memory 模式,store 抉择了内存模式,其余的 parser/sink 依赖的位点治理抉择了长久化模式,目前长久化的形式次要是写入 zookeeper,保证数据集群共享
- 反对 HA,可用于生产环境,集群化部署
一份 instance.xml 中有一份或者多份 instance 定义,优先以 destination 名字查找对应的 instance bean 定义,如果没有,则按默认的名字“instance”查找 instance 对象, 例如 xxxx-instance.xml 中定义 id 别离为 instance-1, instance-2 的两个 bean. 这两个 bean 将为同名的 instance 提供自定义的 eventParser , evnetSink , evnetStore , metaManager,alarmHandler. 如果没有自定义这些 bean, 就应用 id=”instance” 的 bean 来配置 canal instance.
一份 instance bean 定义,须要蕴含 eventParser , evnetSink , evnetStore , metaManager,alarmHandler 的 5 个模块定义,(alarmHandler 次要是一些报警机制解决,因为简略没开展,可扩大)
instance.xml 设计初衷:
容许进行自定义扩大,比方实现了基于数据库的位点治理后,能够自定义一份本人的 instance.xml,整个 canal 设计中最大的灵活性在于此
HA 模式配置
canal 的 ha 分为两局部:
- canal server: 不同 server 上的 instance 要求同一时间只能有一个处于 running,其余的处于 standby 状态,不然就是对 mysql dump 的反复申请。这里是 instance/destination 级别的负载平衡,而不是 server
- canal client: 为了保障有序性,一份 instance 同一时间只能由一个 canal client 进行 get/ack/rollback 操作,否则客户端接管无奈保障有序。
整个 HA 机制的管制次要是依赖了 zookeeper 的几个个性,watcher 和 EPHEMERAL 节点(和 session 生命周期绑定)
Canal Server:
- canal server 要启动某个 canal instance 时都先向 zookeeper 进行一次尝试启动判断 (实现:创立 EPHEMERAL 节点,谁创立胜利就容许谁启动)
- 创立 zookeeper 节点胜利后,对应的 canal server 就启动对应的 canal instance,没有创立胜利的 canal instance 就会处于 standby 状态
- 一旦 zookeeper 发现 canal server A 创立的节点隐没后,立刻告诉其余的 canal server 再次进行步骤 1 的操作,从新选出一个 canal server 启动 instance.
- canal client 每次进行 connect 时,会首先向 zookeeper 询问以后是谁启动了 canal instance,而后和其建设链接,一旦链接不可用,会从新尝试 connect.
Canal Client 的形式和 canal server 形式相似,也是利用 zookeeper 的抢占 EPHEMERAL 节点的形式进行管制.
canal 失落数据的状况:
失常状况下,在 canal server/client 挂掉或切换的状况下不会失落数据,因为 zk 会长久化 server 解析 binlog 及 clinet 生产数据的地位,重启时会从新读取。以下状况可能会失落数据:
- zk 保留的元数据被人为批改,如 server 解析 binlog 及 clinet 生产数据的地位
- client 应用 get 办法而非 getWithoutAck,如果 client 生产数据时挂掉,server 会认为这部分数据曾经被生产而失落
- MySQL binlog 非正常运维,比方 binglog 迁徙、重命名、失落等
- 切换 MySQL 源,比方原来基于 M1 实例,起初 M1 因为某种原因生效,那么 Canal 将数据源切换为 M2,而且 M1 和 M2 可能 binlog 数据存在不统一
Canal 性能剖析
- canal 解决数据流程为 master-parse-sink-store-comsume,整个流程中都是单线程、串行、阻塞式的。如果批量 insert、update、delete,都可能导致大量的 binlog 产生,也会加剧 Master 与 slave 之间数据同步的提早。(写入频繁)。
- 如果 client 生产的效力较低,比方每条 event 执行耗时很长。这会导致数据变更的音讯 ACK 较慢,那么对于 Canal 而言也将阻塞 sotre,没有有足够的空间存储新音讯进而梗塞 parse 解析 binlog。
- Canal 自身十分轻量级,次要性能开销就是在 binlog 解析,其转发、存储、提供消费者服务等都很简略。它自身不负责数据存储。原则上,canal 解析效率简直没有负载,canal 的自身的提早,取决于其与 slave 之间的网络 IO。
Canal 导致反复生产
- Canal instance 初始化时,依据“消费者的 Cursor”来确定 binlog 的起始地位,然而 Cursor 在 ZK 中的保留是滞后的(间歇性刷新),所以 Canal instance 取得的起始 position 肯定不会大于消费者实在已见的 position。
- Consumer 端,因为某种原因的 rollback,也可能导致一个 batch 内的所有音讯重发,此时可能导致反复生产。
因而 Consumer 端须要放弃幂等,对于反复数据能够进行校验或者 replace。对于非幂等操作,比方累加、计费,须要谨慎。
destination 的生产问题
一个 destination 无奈被多个 client 间接并行生产,解决方案:
- client 收到音讯当前转发到 kafka 或者 MQ 中,后继的其余 Consumer 只与 kafka 或者 MQ 接入
- 一个 Canal 中应用多个 destination,它们对应雷同的 MySQL 源
参考:
https://github.com/alibaba/canal/wiki/AdminGuide
https://www.bookstack.cn/read/canal-v1.1.4/10a3a22ce51cd92e.md
https://blog.csdn.net/guanfengliang1988/article/details/107357853
对于 canal 设计的一些思考
-
对于 canal 的高可用,通过 zk 保障 server 和 client 同一时间只能有一个节点工作
- server 能不能依据数据 id 进行分片读取,进步读取数据的性能,相似 kafka 的设计,应该是不能的。因为 parser 向 master 发动 dump 申请失去的是字节流,无奈获取原始数据。那能不能一个 parser 对应多个 sink 再放入 store。没必要,因为 canal 的性能瓶颈在 canal 与数据库的网络 IO,解析及 sink 是很快的。
- 客户端能不能多个节点同时工作,从一个 destination 生产数据。如果不保证数据胜利生产及有序性是能够的。如果某一 client 生产数据失败,以后 store 的设计(环形构造保留数据)无奈做到回滚。如果一个 destination 分多个队列由 client 生产,只能保证数据部分有序,同时设计简单。
-
以后 store 的数据保留在内存中,是否有必要长久化到文件
- 相似于 logstash 的数据也是保留在内存中,官网文档说会反对,但没有也能够,因为长久化会影响整体性能,通过 zk 存储 client 的生产地位会保证数据至多被生产一次。
- store 保留的数据受到大小和条数的限度,当达到限度时,sink 会梗塞 parser,不会撑爆内存
- canal 与 logstahs,kafka 的一些比拟
对当前写公共组件的一些启发:
- 反对多种配置形式如配置文件,http,并可动静失效
- 通过协调服务保证系统的高可用
- 裸露服务监控指标至 prometheus
- 获取数据的形式:达到肯定数量或工夫