基于canal和kafka同步,实现binlog同步mysql

在这里插入图片描述

前言

最近业务需要监听mysql的binlog日志,于是就看了下canal,下面记录踩到的坑。

简介

在这里插入图片描述
canal [kə’næl],译意为水道/管道/沟渠,主要用途是基于 MySQL 数据库增量日志解析,提供增量数据订阅和消费

早期阿里巴巴因为杭州和美国双机房部署,存在跨机房同步的业务需求,实现方式主要是基于业务 trigger 获取增量变更。从 2010 年开始,业务逐步尝试数据库日志解析获取增量变更进行同步,由此衍生出了大量的数据库增量订阅和消费业务。

基于日志增量订阅和消费的业务包括

  • 数据库镜像
  • 数据库实时备份
  • 索引构建和实时维护(拆分异构索引、倒排索引等)
  • 业务 cache 刷新
  • 带业务逻辑的增量数据处理

Canal 的工作原理

在这里插入图片描述

  • MySQL master 将数据变更写入二进制日志( binary log, 其中记录叫做二进制日志事件binary log events,可以通过 show binlog events 进行查看)
  • MySQL slave 将 master 的 binary log events 拷贝到它的中继日志(relay log)
  • MySQL slave 重放 relay log 中事件,将数据变更反映它自己的数据

canal 工作原理

  • canal 模拟 MySQL slave 的交互协议,伪装自己为 MySQL slave ,向 MySQL master 发送dump 协议
  • MySQL master 收到 dump 请求,开始推送 binary log 给 slave (即 canal )
  • canal 解析 binary log 对象(原始为 byte 流)

搭建环境

中间件 版本
mysql 5.7
kafka 2.13-2.4.0
zookeeper 3.6.0
canal 1.1.4

安装mysql

这个我用的docker-compose安装,需要安装的可以参考我之前的博客
docker搭建mysql主从搭建及Sharding-Jdbc读写分离,这篇博客我详细讲解了如何搭建mysql主从。但是要注意的是,binlog format需要设置为row模式。

├── docker-compose.yml
├── master
│   ├── Dockerfile
│   └── my.cnf
├── slave
│   ├── Dockerfile
│   └── my.cnf
└── slave2
    ├── Dockerfile
    └── my.cnf

这里需要改下my.cnf文件

binlog_format=mixed

启动成功,输入SHOW VARIABLES LIKE '%bin%'; 对照下下面两行。

在这里插入图片描述

安装Zookeeper及Kafka

Canal和Kafka集群都依赖于Zookeeper做服务协调,为了方便管理,一般会独立部署Zookeeper服务或者Zookeeper集群。这里使用docker-compose脚本部署,脚本如下:

version: '2'
services:
  zookeeper:
    image: wurstmeister/zookeeper   ## 镜像
    ports:
      - "2181:2181"                 ## 对外暴露的端口号
  kafka:
    image: wurstmeister/kafka       ## 镜像
    volumes:
        - /etc/localtime:/etc/localtime ## 挂载位置(kafka镜像和宿主机器之间时间保持一直)
    ports:
      - "9092:9092"
    environment:
      KAFKA_ADVERTISED_HOST_NAME: 192.168.56.119   ## 修改:宿主机IP
      KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181       ## 卡夫卡运行是基于zookeeper的
  kafka-manager:
    image: sheepkiller/kafka-manager                ## 镜像:开源的web管理kafka集群的界面
    environment:
        ZK_HOSTS:                    ## 修改:宿主机IP
    ports:
      - "9000:9000"

docker-compose up -d
Starting kafka_kafka_1         ... done
Starting kafka_zookeeper_1     ... done
Starting kafka_kafka-manager_1 ... done

搭建canal

终于到了主角登场,这里选用Canal的v1.1.4稳定发布版,只需要下载deployer模块:

mkdir /data/canal
cd /data/canal
# 这里注意一点,Github在国内被墙,下载速度极慢,可以先用其他下载工具下载完再上传到服务器中
wget https://github.com/alibaba/canal/releases/download/canal-1.1.4/canal.deployer-1.1.4.tar.gz
tar -zxvf canal.deployer-1.1.4.tar.gz

解压后的目录如下:

- bin   # 运维脚本
- conf  # 配置文件
  canal_local.properties  # canal本地配置,一般不需要动
  canal.properties        # canal服务配置
  logback.xml             # logback日志配置
  metrics                 # 度量统计配置
  spring                  # spring-实例配置,主要和binlog位置计算、一些策略配置相关,可以在canal.properties选用其中的任意一个配置文件
  example                 # 实例配置文件夹,一般认为单个数据库对应一个独立的实例配置文件夹
    instance.properties   # 实例配置,一般指单个数据库的配置
- lib   # 服务依赖包
- logs  # 日志文件输出目录

在开发和测试环境建议把logback.xml的日志级别修改为DEBUG方便定位问题。这里需要关注canal.properties和instance.properties两个配置文件。canal.properties文件中,需要修改:

  • 去掉canal.instance.parser.parallelThreadSize = 16这个配置项的注释,也就是启用此配置项,和实例解析器的线程数相关,不配置会表现为阻塞或者不进行解析。
  • canal.serverMode配置项指定为kafka,可选值有tcp、kafka和rocketmq(master分支或者最新的的v1.1.5-alpha-1版本,可以选用rabbitmq),默认是kafka。
  • canal.mq.servers配置需要指定为Kafka服务或者集群Broker的地址,这里配置为127.0.0.1:9092。

canal.mq.servers在不同的canal.serverMode有不同的意义。kafka模式下,指Kafka服务或者集群Broker的地址,也就是bootstrap.servers rocketmq模式下,指NameServer列表 rabbitmq模式下,指RabbitMQ服务的Host和Port

其他配置项可以参考下面两个官方Wiki的链接:

  • Canal-Kafka-RocketMQ-QuickStart
  • AdminGuide

instance.properties一般指一个数据库实例的配置,Canal架构支持一个Canal服务实例,处理多个数据库实例的binlog异步解析。instance.properties需要修改的配置项主要包括:

  • canal.instance.mysql.slaveId需要配置一个和Master节点的服务ID完全不同的值,这里笔者配置为654321。

  • 配置数据源实例,包括地址、用户、密码和目标数据库:

    • canal.instance.master.address,这里指定为127.0.0.1:33065。
    • canal.instance.dbUsername,这里指定为root。
    • canal.instance.dbPassword,这里指定为root。
    • 新增canal.instance.defaultDatabaseName,这里指定为test(需要在MySQL中建立一个test数据库,见前面的流程)。
  • Kafka相关配置,这里暂时使用静态topic和单个partition:

    • canal.mq.topic,这里指定为test,也就是解析完的binlog结构化数据会发送到Kafka的命名为test的topic中。
    • canal.mq.partition,这里指定为0。

配置工作做好之后,可以启动Canal服务:

sh /data/canal/bin/startup.sh
# 查看服务日志
tail -100f /data/canal/logs/canal/canal
# 查看实例日志  -- 一般情况下,关注实例日志即可
tail -100f /data/canal/logs/example/example.log

启动正常后,见实例日志如下:
在这里插入图片描述
在test数据库创建一个订单表,并且执行几个简单的DML:


use `test`;

CREATE TABLE `order`
(
    id          BIGINT UNIQUE PRIMARY KEY AUTO_INCREMENT COMMENT '主键',
    order_id    VARCHAR(64)    NOT NULL COMMENT '订单ID',
    amount      DECIMAL(10, 2) NOT NULL DEFAULT 0 COMMENT '订单金额',
    create_time DATETIME       NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
    UNIQUE uniq_order_id (`order_id`)
) COMMENT '订单表';

INSERT INTO `order`(order_id, amount) VALUES ('10086', 999);
UPDATE `order` SET amount = 10087 WHERE order_id = '10086';
DELETE  FROM `order` WHERE order_id = '10086';

这个时候,进入容器的kafka-console-consumer或者Kafka Tools查看test这个topic的数据

docker exec -it be206dc159e6 /bin/bash

sh ./bin/kafka-console-consumer.sh --bootstrap-server 127.0.0.1:9092 --from-beginning --topic test

在这里插入图片描述

可见Kafka的名为test的topic已经写入了对应的结构化binlog事件数据,可以编写消费者监听Kafka对应的topic然后对获取到的数据进行后续处理。

搭建canal

拉取代码 https://github.com/alibaba/canal/releases/tag/canal-1.1.4

在这里插入图片描述

  • 配置application.yml文件
server:
  port: 8081
logging:
  level:
    org.springframework: INFO
    com.alibaba.otter.canal.client.adapter.hbase: DEBUG
    com.alibaba.otter.canal.client.adapter.es: DEBUG
    com.alibaba.otter.canal.client.adapter.rdb: DEBUG
spring:
  jackson:
    date-format: yyyy-MM-dd HH:mm:ss
    time-zone: GMT+8
    default-property-inclusion: non_null

canal.conf:
  mqServers: 192.168.56.119:9092 #or rocketmq
  flatMessage: true
  batchSize: 500
  syncBatchSize: 1000
  retries: 0
  timeout:
  accessKey:
  secretKey:
  mode: kafka # tcp kafka rocketMQ
  srcDataSources:
    demoSrc:
      url: jdbc:mysql://192.168.56.119:33065/test?useUnicode=true
      username: root
      password: root
  canalAdapters:
    - instance: test # canal instance Name or mq topic name
      groups:
        - groupId: test
          outerAdapters:
            - name: logger
            - name: rdb
              key: demoDes
              properties:
                jdbc.driverClassName: com.mysql.jdbc.Driver
                jdbc.url: jdbc:mysql://{
    
    IP}:3306/test?useUnicode=true
                jdbc.username: root
                jdbc.password: 1234qwer

*配置demo.yml文件

dataSourceKey: demoSrc
destination: test
outerAdapterKey: demoDes
concurrent: true
groupId: test
dbMapping:
    database: test
    table: order
    targetTable: test.order
    targetPk:
        id: id
    mapAll: true
  • 启动com.alibaba.otter.canal.adapter.launcher.CanalAdapterApplication,观察目的数据库。

猜你喜欢

转载自blog.csdn.net/qq_37362891/article/details/107886537