简介
Canal是的作用是监听数据库变化,并向外通知消息。 这篇文章,尝试利用Docker搭建一个Canal环境,体会下Canal生态。 本次部署是在Windows的docker环境下部署,请预先安装好WSL2、Docker Desktop等。
版本
| 组件 | 版本 |
|---|---|
| Spring Boot | 3.3.4 |
| MySql | 5.7.44 |
| Canal | 1.1.8 |
| RabbitMq | 4.0.5 |
docker设置
创建一个 mynetwork 的网络,理由是,cannal需要通过这个网络连接MySql和rabbitMQ。
docker network create -d bridge mynetwork
MySql
本来下载了版本9.0,但是一直MQ一直没有接收到消息,不太清楚原因。先降级成5.7,按照网上能找到的公开资料进行尝试。
# Use root/example as user/password credentials
services:
db:
image: mysql:5.7
container_name: db
restart: always
environment:
MYSQL_ROOT_PASSWORD: example
TZ: Asia/Shanghai
volumes:
- ./57datadir:/var/lib/mysql
- ./conf:/etc/mysql/conf.d
ports:
- 3306:3306
networks:
- mynetwork
networks:
mynetwork:
name: mynetwork
external: true
需要准备一下MySql的配置文件,主要是为了打开BinLog,这是Canal工作的基础。Canal是通过BinLog同步数据库的变更。 配置如下:
[mysqld]
log_bin=/var/lib/mysql/binlog
log_bin_index=/var/lib/mysql/binlog.index
binlog-format=ROW # 选择 ROW 模式
server_id=66 # 配置 MySQL replaction 需要定义,不要和 canal 的 slaveId 重复
character_set_server=UTF8MB4
connect_timeout=60 # 将默认值(如30秒)改为60秒
wait_timeout=28800 # 将空闲连接超时时间改为8小时
interactive_timeout=28800 # 对于交互式连接也作同样修改
数据库启动后记得创建一个Canal用户,给Canal进行连接:
CREATE USER canal IDENTIFIED BY 'canal';
GRANT SELECT, REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'canal'@'%';
FLUSH PRIVILEGES;
RabbitMq
# Use root/passwordA as user/password credentials
services:
rabbitmq:
image: rabbitmq:management
container_name: rabbitmq
environment:
TZ: Asia/Shanghai
RABBITMQ_DEFAULT_USER: user
RABBITMQ_DEFAULT_PASS: passwordA
ports:
- 5671:5671
- 5672:5672
- 4369:4369
- 15671:15671
- 15672:15672
- 25672:25672
networks:
- mynetwork
networks:
mynetwork:
name: mynetwork
external: true
需要预先新建一个交换器,原因是Canal不会自动注册交换器。
新建一个名为“canal-queue”的队列并与这个交换器绑定。
Canal
# Use root/example as user/password credentials
services:
canal:
image: canal/canal-server
environment:
TZ: Asia/Shanghai
canal.destinations: main
canal.instance.mysql.slaveId: 677
canal.instance.master.address: db:3306
canal.instance.dbUsername: canal
canal.instance.dbPassword: canal
canal.instance.connectionCharset: UTF-8
canal.instance.tsdb.enable: true
canal.instance.gtidon: false
# 指定监听的过滤规则
canal.instance.filter.regex: xxl_job\..*
canal.mq.topic: canal.topic
# 指定模式
canal.serverMode: rabbitMQ
# 压缩
canal.mq.compressionType: lz4
# rabbitmq 服务端 ip
rabbitmq.host: rabbitmq
# rabbitmq 虚拟主机
rabbitmq.virtual.host: spring_demo
# rabbitmq 交换机
rabbitmq.exchange: ex_canal
# rabbitmq 用户名
rabbitmq.username: user
# rabbitmq 密码
rabbitmq.password: passwordA
rabbitmq.queue: canal-queue
rabbitmq.routingKey: canal.routing.key
ports:
- 11111:11111
- 11110:11110
- 11112:11112
- 9100:9100
networks:
- mynetwork
volumes:
- ./log:/home/admin/canal-server/logs/
networks:
mynetwork:
name: mynetwork
external: true
这里面rabbitmq开头的都是和RabbitMQ有关的,按照自己的配置去配。
canal.instance.filter.regex 这个参数就是监听什么标的配置,这里的规则,xxl_job是我的库名,中间的“.”是固定的,不是两个斜杠,有的教程写错了,我踩了大坑。最后的“.*”是匹配任何表,如果有具体表名,可以写成具体表名。总之,支持一定的正则表达式。
Spring Boot
新建一个Spring Boot工程,用于监听消息。
重要的依赖为
<!-- 实现对 RabbitMQ 的自动化配置 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
配置文件为
spring:
# RabbitMQ 配置项,对应 RabbitProperties 配置类
rabbitmq:
host: 192.168.31.179 # RabbitMQ 服务的地址
port: 5672 # RabbitMQ 服务的端口
username: user # RabbitMQ 服务的账号
password: passwordA # RabbitMQ 服务的密码
virtualHost: spring_demo
重要的监听器:
@Component
@Slf4j
public class CanalListener {
@RabbitListener(bindings = {
@QueueBinding(
value = @Queue(value = "canal-queue", durable = "true"),
exchange = @Exchange(value = "ex_canal"),
key = "canal.routing.key"
)
})
public void handleDataChange(String message) {
log.info("Canal 监听 发生变化;明细:{}", message);
}
}
配置完成后启动即可。