简介
Canal 翻译为管道,主要用途是基于 MySQL 数据库的增量日志 Binlog 解析,提供增量数据订阅和消费。
早期阿里巴巴因为杭州和美国双机房部署,存在跨机房同步的业务需求,实现方式主要是基于业务 trigger 获取增量变更。从 2010 年开始,业务逐步尝试数据库日志解析获取增量变更进行同步,由此衍生出了大量的数据库增量订阅和消费业务。
基于日志增量订阅和消费的业务包括
当前的 canal 支持源端 MySQL 的版本包括 5.1.x,5.5.x,5.6.x,5.7.x,8.0.x。 工作原理 MySQL主备复制原理
canal 工作原理
github地址: https://github.com/alibaba/canal
完整wiki地址
Canal架构
一个 server 代表一个 canal 运行实例,对应于一个 jvm,一个 instance 对应一个数据队列。
instance模块:
Canal-HA机制
所谓 HA 即高可用,是 High Available 的简称。通常我们一个服务要支持高可用都需要借助于第三方的分布式同步协调服务,最常用的是zookeeper 。canal 实现高可用,也是依赖了zookeeper 的几个特性:watcher 和 EPHEMERAL 节点。
canal 的高可用分为两部分:canal server 和 canal client
server ha 的架构图如下:
大致步骤:
Canal Client 的方式和 canal server 方式类似,也是利用 zookeeper 的抢占 EPHEMERAL 节点的方式进行控制。 应用场景 同步缓存 Redis /全文搜索 ES
当数据库变更后通过 binlog 进行缓存/ES的增量更新。当缓存/ES更新出现问题时,应该回退 binlog 到过去某个位置进行重新同步,并提供全量刷新缓存/ES的方法。
下发任务
当数据变更时需要通知其他依赖系统。其原理是任务系统监听数据库变更,然后将变更的数据写入 MQ/kafka 进行任务下发,比如商品数据变更后需要通知商品详情页、列表页、搜索页等相关系统。
这种方式可以保证数据下发的精确性,通过 MQ 发送消息通知变更缓存是无法做到这一点的,而且业务系统中不会散落着各种下发 MQ 的代码,从而实现了下发归集。
数据异构
在大型网站架构中,DB都会采用分库分表来解决容量和性能问题。但分库分表之后带来的新问题,比如不同维度的查询或者聚合查询,此时就会非常棘手。一般我们会通过数据异构机制来解决此问题。
所谓的数据异构,那就是将需要 join 查询的多表按照某一个维度又聚合在一个 DB 中让你去查询,canal 就是实现数据异构的手段之一。
MySQL 配置 开启 binlog
首先在 mysql 的配置文件目录中查找配置文件 my.cnf(Linux环境)
在 [mysqld] 区块下添加配置开启 binlog
重启 mysql:service mysqld restart,会发现在 /var/lib/mysql 下会生成两个文件 mysql-bin.000001 和 mysql-bin.index,当 mysql 重启或到达单个文件大小的阈值时,新生一个文件,按顺序编号 mysql-bin.000002,以此类推。 扩展
binlog 日志有三种格式,可以通过 binlog_format 参数指定。 statement
记录的内容是 SQL语句 原文,比如执行一条 update T set update_time=now() where id=1,记录的内容如下
同步数据时,会执行记录的 SQL 语句,但是有个问题,update_time=now() 这里会获取当前系统时间,直接执行会导致与原库的数据不一致。
row
为了解决上述问题,我们需要指定为 row,记录的内容不再是简单的 SQL 语句了,还包含操作的具体数据,记录内容如下。
row 格式记录的内容看不到详细信息,要通过 mysql binlog 工具解析出来。
update_time=now() 变成了具体的时间 update_time=1627112756247,条件后面的 @1、@2、@3 都是该行数据第1个~3个字段的原始值(假设这张表只有3个字段)。
这样就能保证同步数据的一致性,通常情况下都是指定为 row,这样可以为数据库的恢复与同步带来更好的可靠性。
缺点:占空间、恢复与同步时消耗更多的IO资源,影响执行速度。 mixed
MySQL 会判断这条 SQL 语句是否可能引起数据不一致,如果是,就用 row 格式,否则就用 statement 格式。 配置权限
注意:如果密码设置的过于简单,会报以下错误
Canal 配置
官网下载地址,我下载的版本是 canal.deployer-1.1.6.tar.gz,然后通过 psftp 上传到服务器。
解压:tar -zxvf canal.deployer-1.1.6.tar.gz 配置
通过查看 conf/canal.properties 配置,发现需要暴漏三个端口
修改 conf/canal.properties
配置
修改 conf/example/instance.properties
实例配置
启动
需要在安装目录 /usr/local 下执行:sh bin/startup.sh 或者 ./bin/startup.sh。 报错
发现在 logs 下没有生成 canal.log 日志,在进程命令中 ps -ef | grep canal 也查不到 canal 的进程。 解决
在目录 logs 中存在文件 canal_stdout.log ,文件内容如下:
报错信息提示内存不足,Java 运行时环境无法继续。更详细的错误日志在文件:/usr/local/bin/hs_err_pid25186.log 中。
既然是内存原因,那就检查一下自己的内存,执行命令free -h ,发现可用内存仅为 96M,应该是内存问题,解决方法如下:
我就是用的第三种方法,首先用 vim 打开 startup.sh 修改内存参数,可以对照我的进行修改,按照自己服务器剩余内存进行修改,这里我将内存调整到了 80M。
改为 -server -Xms80m -Xmx80m -Xmn80m -XX:SurvivorRatio=2 -XX:PermSize=66m -XX:MaxPermSize=80m -Xss256k -XX:-UseAdaptiveSizePolicy -XX:MaxTenuringThreshold=15 -XX:+DisableExplicitGC -XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled -XX:+UseCMSInitiatingOccupancyOnly -XX:+HeapDumpOnOutOfMemoryError
改完之后执行命令发现依旧报错:found canal.pid , Please run stop.sh first ,then startup.sh 意思是找到了 canal.pid,请先运行stop.sh。
执行 stop.sh 命令后重新启动,成功运行,成功运行后可以在 canal/logs 文件夹中生成 canal.log 日志。
实战
引入依赖
代码样例
代码样例来自官网,仅用于测试使用
测试
启动项目,打印日志
手动修改数据库中的字段:
可以看出是在 mysql-bin.000002文件中,数据库名称 cheetah ,表名 product_info,事件类型:update。