使用 Canal 实时从 MySql 向其它库同步数据
目前绝大多数项目还是采用 mysql 作为数据存储对于用户访问量较高的网站来说mysql 读写性能有限我们通常会把 mysql 中的数据实时同步到 Redis、mongodb、elastic search 等中间件中应对高并发访问场景减轻 mysql 压力防止数据库宕机。在项目开发中为了不会原有代码进行侵入采用 canal 中间件实现 mysql 向其它库的实时同步是一种很不错的方案。canal 译意为水道/管道/沟渠主要用途是基于 mysql 数据库增量日志解析提供增量数据订阅和消费其工作原理是模拟 mysql slave 的交互协议伪装自己为 mysql slave 向 mysql master 发送 dump 协议mysql master 收到 dump 请求开始推送 binary log 给 canalcanal 解析 binary log 提供出对具体表数据的增删改操作内容。本篇博客将采用 docker-compose 搭建 mysql 和 canal并采用代码方式演示如果使用 canal 从mysql 中同步数据监听对数据表的增删改操作。在本篇博客的最后会提供源代码下载。Canal 的 gitHub 地址为GitHub - alibaba/canal: 阿里巴巴 MySQL binlog 增量订阅消费组件一、部署 mysql 和 canal本篇博客使用虚拟机进行部署我的虚拟机操作系统是 CentOS7ip 地址是 192.168.136.128已经安装好了 docker 和 docker-compose 首先我们先创建好相关的目录我创建的主目录是 /app/canal具体结构如下在 /app/canal 创建一个 mysql 目录在 mysql 下创建一个 data 目录并创建了 mysql 的配置文件 my.cnf首先列出 mysql 的配置文件 my.cnf 的内容主要配置是开启 binlog 日志[mysqld]# 开启 binloglog-binmysql-bin# canal 需要使用 ROW 模式binlog-formatROW# 如果你只想同步部分数据库的话可以进行如下配置# 如果同步多个数据库的话可以配置多行。# 如果不配置的话默认是 mysql 所有库都进行同步# binlog-do-dbcanaldb# binlog-do-dbmytestdb# 不要和 canal 的 slaveId 重复mysql 默认是 1server-id1# 数据目录datadir/var/lib/mysqlsymbolic-links0socket/var/lib/mysql/mysql.socklog-error/var/log/mysqld.logpid-file/var/run/mysqld/mysqld.pid然后在 /app/canal 下创建 docker-compose.yml 文件内容如下version: 3.5services:mysql-server:image: mysql:5.7.42container_name: mysql-serverrestart: alwaysports:- 3306:3306volumes:# mysql的数据存放目录映射- /app/canal/mysql/data:/var/lib/mysql# mysql的配置文件映射- /app/canal/mysql/my.cnf:/etc/mysql/my.cnfenvironment:# mysql的root密码设置- MYSQL_ROOT_PASSWORDrootnetworks:- canal_netcanal-server:image: canal/canal-server:v1.1.7container_name: canal-serverrestart: alwaysports:- 11111:11111environment:# 设置连接 canal 服务的用户名和密码- CANAL_ADMIN_USERadmin- CANAL_ADMIN_PASSWORDpassword# 设置 canal 实例的名称- canal.destinationsjobs# 设置 canal 实例作为 mysql 从库的 server_id- canal.instance.mysql.slaveId100# 设置连接 mysql 的地址- canal.instance.master.addressmysql-server:3306# 设置连接 mysql 的账号密码- canal.instance.dbUsernameroot- canal.instance.dbPasswordroot# 设置要解析的表可以使用正则表达式多个之间配置用英文逗号分隔- canal.instance.filter.regexcanaldb.t_employeenetworks:- canal_netdepends_on:- mysql-server# 网络配置networks:canal_net:driver: bridge然后在 /app/canal 目录下运行docker-compose up -d即可启动 mysql 和 canal 服务。在 canal 服务配置中 canal.instance.filter.regex 用来配置要同步的数据库表可以配置正则表达式多个正则之间以英文逗号分隔转义符需要使用双斜杠\。常见例子如下1. 所有表 .* or .\..2. canal 数据库下所有表 canal\..*3. canal 数据库下的所有以 canal 开头的表canal\.canal.*4. canal 数据库下的一张表canal.test15. 多个正则表达式组合使用然后以英文逗号隔开canal\..*,mysql.test1,mysql.test2我们上面配置的是 canaldb.t_employee 也就是仅同步 canaldb 数据库下的 t_employee 表因此在部署完 mysql 之后需要运行以下 sql 脚本在数据库中简单出该表并添加一些示例数据DROP TABLE IF EXISTS t_employee;CREATE TABLE t_employee (e_id bigint(20) NOT NULL AUTO_INCREMENT COMMENT 员工id,e_name varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 员工姓名,e_age int(11) NOT NULL DEFAULT 0 COMMENT 员工年龄,PRIMARY KEY (e_id) USING BTREE) ENGINE InnoDB AUTO_INCREMENT 4 CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci ROW_FORMAT Dynamic;INSERT INTO t_employee VALUES (1, 任肥肥, 41);INSERT INTO t_employee VALUES (2, 侯胖胖, 42);INSERT INTO t_employee VALUES (3, 乔豆豆, 40);二、实时同步数据新建一个 springboot 工程具体结构如下所示由于工程代码非常简单这里就直接进行介绍先看 pom 文件引用的依赖?xml version1.0 encodingUTF-8?project xmlnshttp://maven.apache.org/POM/4.0.0xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsdmodelVersion4.0.0/modelVersiongroupIdcom.jobs/groupIdartifactIdspringboot_canal/artifactIdversion1.0/versionparentgroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-parent/artifactIdversion2.4.5/version/parentpropertiesmaven.compiler.source8/maven.compiler.sourcemaven.compiler.target8/maven.compiler.target/propertiesdependenciesdependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter/artifactId/dependencydependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactIdversion1.18.26/version/dependency!--引入 canal 的 springboot 依赖--dependencygroupIdtop.javatool/groupIdartifactIdcanal-spring-boot-starter/artifactIdversion1.2.1-RELEASE/version/dependency/dependencies/project这里最主要就是引入了 canal-spring-boot-starter 这个依赖该依赖包是第三方爱好者提供github 网址为GitHub - NormanGyllenhaal/canal-client: spring boot canal starter 易用的canal 客户端 canal client我们需要创建一个实体类其字段需要与要同步数据的 mysql 数据库表保持一致具体细节如下package com.jobs.pojo;import lombok.Data;//注意//这里的属性名称需要与数据库表中的字段名称保持一致Datapublic class Employee {private Long e_id;private String e_name;private Integer e_age;}然后再开发一个 handler 用于处理从 canal 服务获取到的解析记录对数据的增删改记录即可package com.jobs.handler;import com.jobs.pojo.Employee;import org.springframework.stereotype.Component;import top.javatool.canal.client.annotation.CanalTable;import top.javatool.canal.client.handler.EntryHandler;CanalTable(t_employee)Componentpublic class EmployeeHandler implements EntryHandlerEmployee {Overridepublic void insert(Employee employee) {System.out.println(添加了 employee);//这里可以将数据添加到同步的目标库中比如 redis 缓存}Overridepublic void update(Employee before, Employee after) {System.out.println(更新前 before);System.out.println(更新后 after);//这里可以将数据更新到同步的目标库中比如 redis 缓存}Overridepublic void delete(Employee employee) {System.out.println(删除了 employee);//这里可以将数据从同步的目标库中删除掉比如 redis 缓存}}最后在工程的 application.yml 文件中配置好连接 canal 服务的信息canal:# canal 服务部署时配置的 destination 值此处要保持一直destination: jobs# canal服务地址server: 192.168.136.128:11111# 连接 canal 服务的用户名和密码user-name: adminpassword: password三、验证成果启动 springboot 工程然后使用 navcat 连接到 mysql 数据库对 canaldb 下的表 t_employee 中的记录进行增删改首先我们在 mysql 中添加一条新纪录李墩墩38 岁然后程序就监听到数据添加事件控制台打印结果如下然后我们在 mysql 中修改李墩墩的数据修改为蔺赞赞36岁然后程序就监听到数据修改事件控制台打印结果如下最后我们在 mysql 中删除任肥肥这条记录然后程序就监听到数据修改事件控制台打印结果如下本篇博客的 Demo 代码仅仅是把数据打印出来在实际开发中大家可以根据自己的业务进行相应的操作。到此为止使用 Canal 服务从 mysql 实时同步数据的内容已经介绍完毕大家可以下载源代码自行体验本篇博客的源代码下载地址为https://files.cnblogs.com/files/blogs/699532/springboot_canal.zip