Windows Docker下Canal的搭建

403 阅读3分钟

简介

Canal是的作用是监听数据库变化,并向外通知消息。 这篇文章,尝试利用Docker搭建一个Canal环境,体会下Canal生态。 本次部署是在Windows的docker环境下部署,请预先安装好WSL2、Docker Desktop等。

版本

组件版本
Spring Boot3.3.4
MySql5.7.44
Canal1.1.8
RabbitMq4.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不会自动注册交换器。

image.png

新建一个名为“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);
    }
}

配置完成后启动即可。