使用Canal实时同步Mysql数据库数据

目录

一、下载安装包

二、解压

三、配置canal_deplayer

四、配置canal_adapter

五、测试同步效果

六、拓展(可选)

七、linux设置canal_deployer和canal_adapter服务常驻内存,每次随主机启动而启动(可选)


本文针对canal同步mysql数据库,通过一个测试表来演示同步的安装、配置、示例。

一、下载安装包

wget https://github.com/alibaba/canal/releases/download/canal-1.1.8/canal.adapter-1.1.8.tar.gz
wget https://github.com/alibaba/canal/releases/download/canal-1.1.8/canal.deployer-1.1.8.tar.gz

如果下载很慢,可以百度其他镜像站下载或通过代理方式来下载。
下载完成后,如下图,其中canal_admin提供的一个可视化管理平台,用于集中管理和配置 Canal Deployer、Adapter 实例和同步任务。本文为单机同步,咱不安装它,有兴趣伙伴可以自行尝试。
canal-master.zip是我下载的源码,暂时用不上,忽略它。

二、解压

创建安装目录
mkdir -p /usr/local/canal/canal_deployer && mkdir -p /usr/local/canal/canal_adapter

解压文件到安装目录
tar -zxvf /usr/local/soft/canal.deployer-1.1.8.tar.gz -C /usr/local/canal/canal_deployer
tar -zxvf /usr/local/soft/canal.adapter-1.1.8.tar.gz -C /usr/local/canal/canal_adapter 

三、配置canal_deplayer

进入conf目录
cd /usr/local/canal/canal_deployer/conf
修改canal.properties

1.新增这两行
canal.id=1
canal.ip=192.168.7.47 (canal服务所在主机外网IP)

2.修改如下字段值:
canal.register.ip = 你的主机ip,如:192.168.7.47
canal.destinations = example 默认example,此处默认即可


3.进入conf/example目录里,修改instance.properties
cd /usr/local/canal/canal_deployer/conf/example
修改如下字段属性值:
canal.instance.master.address=192.168.7.47:3306 此处为源库ip:端口


canal.instance.dbUsername=root 此处为源库登录账号
canal.instance.dbPassword=root 此处为源库登录密码


canal.instance.filter.regex=test\\.user 指定要同步的库表,例如我要同步test库下的user表

canal.instance.filter.regex=test1\\..*|test2\\..*|test3\\..*表示我要同步test1、test2、test3库里的所有表。

新增这两行(可选)

canal.instance.defaultDatabaseName=test 默认同步的数据库名
canal.instance.defaultTableName=user 默认同步的数据库表名

4.启动canal_deployer
进入bin目录,执行启动脚本
cd /usr/local/canal/canal_deployer/bin
./startup.sh

5.查看启动日志和执行日志
tail -f /usr/local/canal/canal_deployer/logs/canal/canal.log

tail -f /usr/local/canal/canal_deployer/logs/example/example.log 


上图表示canal-deployer启动成功

四、配置canal_adapter

配置canal_adapter之前,一定要将源库test库里的test表结构,导入到目标库test库里,因为Canal Adapter 不会自动建库建表,你需要手动在目标库中建库建表,这步骤千万不要忘记,否则后续日志报找不到字段的异常

接下来开始配置canal_adapter

1.进入conf目录,修改application.yml 
cd /usr/local/canal/canal_adapter/conf
修改内容如下:
canal.tcp.server.host: 192.168.7.47:11111 此处为主机IP:11111,端口尽量不要修改,保持11111即可

#源库登录信息(root之外其他拥有权限的账号也行):
srcDataSources:
    defaultDS:
      url: jdbc:mysql://192.168.7.47:3306/test?useUnicode=true 
      username: root
      password: root
      
#目标库登录信息(root之外其他拥有权限的账号也行):
canalAdapters:
  - instance: example # canal instance Name or mq topic name
    groups:
    - groupId: g1
      outerAdapters:
      - name: logger
      - name: rdb
        key: mysql1
        properties:
          jdbc.driverClassName: com.mysql.jdbc.Driver
          jdbc.url: jdbc:mysql://192.168.7.47:4306/test?useUnicode=true
          jdbc.username: root
          jdbc.password: root
          druid.stat.enable: false
          druid.stat.slowSqlMillis: 1000

也可以配置多个数据库,如图:defaultDS,defaultDS2,defaultDS3,多个目标库mysql1/mysq2/mysql3


          
2.进入rdb目录,创建库表同步的配置文件
cd /usr/local/canal/canal_adapter/conf/rdb
例如我要同步test库下的user表,我创建的文件名就是:test_user.yml
内容如下:
dataSourceKey: defaultDS
destination: example
groupId: g1
outerAdapterKey: mysql1
concurrent: true
dbMapping:
  database: test
  table: user
  targetTable: user
  targetPk:
    id: id
  mapAll: true
#  targetColumns:
#    id:
#    name:
#    role_id:
#    c_time:
#    test1:

3.启动canal_adapter
进入bin目录,执行启动脚本
cd /usr/local/canal/canal_adapter/bin && ./startup.sh

4.查看执行日志
tail -f /usr/local/canal/canal_adapter/logs/adapter/adapter.log

如果表示canal_adapter启动成功。

五、测试同步效果

当源库user表插入数据后,刷新目标库,数据已经同步过来了

修改数据的时候也同步过来了

删除李四这条数据后,数据依然同步

至此canal同步单表配置完成

六、拓展(可选)

如果想同步指定库里所有的表,由于表比较多的情况下,canaladapter的rdb目录下要写多个.yml映射文件,太过于繁琐,且效率很低,为此,我们可以写一个脚本,来按每个表生成对应的yml文件

配置前一定要求将源库结构和目标库表结构进行同步,确保两变库表结构一致,这是前提

我这里提供两个脚本:

  • start_canal_mysql.sh:负责读取该脚本同级目录里mysql_tables目录里的test1.txt,例如:./mysql_tables/test1.txt,test1.txt文件名为你本次要同步的数据库名,因为我要同步test1库里所有的表,所以我命名为test1.txt,test1.txt里的内容,每行的内容格式:表名|主键字段名
    ,如果某个表没设置主键,则显示:表名|无,查询指定库下所有表名和主键id字段的sql如下:
    SELECT 
    		CONCAT(t.TABLE_NAME,'|',IFNULL(
            GROUP_CONCAT(k.COLUMN_NAME ORDER BY k.ORDINAL_POSITION SEPARATOR ', '),
            '无'
        ) ) as TABLE_NAME
    FROM 
        information_schema.TABLES t
    LEFT JOIN 
        information_schema.KEY_COLUMN_USAGE k 
        ON t.TABLE_SCHEMA = k.CONSTRAINT_SCHEMA 
        AND t.TABLE_NAME = k.TABLE_NAME 
        AND k.CONSTRAINT_NAME = 'PRIMARY'
    WHERE 
        t.TABLE_SCHEMA = 'test1'
    GROUP BY 
        t.TABLE_NAME
    ORDER BY 
        t.TABLE_NAME;

    start_canal_mysql.sh脚本内容如下:
    #!/bin/bash
    
    # 检查参数是否正确
    if [ $# -ne 3 ]; then
        echo "Usage: $0 <database_name> <outer_adapter_key> <data_source_key>"
        exit 1
    fi
    
    # 获取脚本所在目录
    SCRIPT_DIR=$(cd $(dirname $0); pwd)
    DB_NAME=$1
    # 定义 canal_mysql_table.txt 文件路径
    TABLE_LIST_FILE="$SCRIPT_DIR/mysql_tables/$DB_NAME.txt"
    
    # 检查文件是否存在
    if [ ! -f "$TABLE_LIST_FILE" ]; then
        echo "Error: File $TABLE_LIST_FILE does not exist."
        exit 1
    fi
    
    # 读取数据库名、outer_adapter_key、data_source_key
    #DB_NAME=$1
    OUTER_ADAPTER_KEY=$2
    DATA_SOURCE_KEY=$3
    
    # 逐行读取表信息并处理
    while IFS='|' read -r TABLE_NAME PK_ID; do
        # 去除前后空格(如果有的话)
        TABLE_NAME=$(echo $TABLE_NAME | xargs)
        PK_ID=$(echo $PK_ID | xargs)
    
        # 执行 canal_mysql.sh 脚本
        "$SCRIPT_DIR/canal_mysql.sh" "$DB_NAME" "$TABLE_NAME" "$PK_ID" "$OUTER_ADAPTER_KEY" "$DATA_SOURCE_KEY"
    done < "$TABLE_LIST_FILE"
    #chmod +x start_canal_mysql.sh
    #./start_canal_mysql.sh your_database outer_adapter_key data_source_key
    
    canal_mysql.sh
    #!/bin/bash
    
    # 检查参数数量是否正确,必须提供4个参数
    if [ "$#" -lt 4 ] || [ "$#" -gt 5 ]; then
        echo "Usage: $0 <database_name> <table_name> <target_pk_id> <outer_adapter_key> [data_source_key]"
        exit 1
    fi
    
    # 获取脚本参数
    db_name="$1"
    table_name="$2"
    target_pk_id="$3"
    outer_adapter_key="$4"
    data_source_key="${5:-defaultDS}"
    
    # 参数非空校验
    if [ -z "${db_name}" ]; then
        echo "Error: 第一个参数(database_name)不能为空"
        exit 1
    fi
    
    if [ -z "${table_name}" ]; then
        echo "Error: 第二个参数(table_name)不能为空"
        exit 1
    fi
    
    if [ -z "${target_pk_id}" ]; then
        echo "Error: 第三个参数(target_pk_id)不能为空"
        exit 1
    fi
    
    if [ -z "${outer_adapter_key}" ]; then
        echo "Error: 第四个参数(outer_adapter_key)不能为空"
        exit 1
    fi
    
    # 定义文件路径和名称
    output_dir="/usr/local/canal/canal_adapter/conf/rdb"
    file_name="${db_name}_${table_name}.yml"
    output_file="${output_dir}/${file_name}"
    
    # 创建目标目录(如果不存在)
    mkdir -p "$output_dir"
    rm -rf "$output_file"
    
    # 写入内容到YAML文件
    cat <<EOF > "$output_file"
    dataSourceKey: ${data_source_key}
    destination: example
    groupId: g1
    outerAdapterKey: ${outer_adapter_key}
    concurrent: true
    dbMapping:
      database: ${db_name}
      table: ${table_name}
      targetTable: ${table_name}
    EOF
    
    # 判断 target_pk_id 是否为 "无"
    if [ "${target_pk_id}" != "无" ]; then
        cat <<EOF >> "$output_file"
      targetPk:
        id: ${target_pk_id}
    EOF
    else
        cat <<EOF >> "$output_file"
      #targetPk:
      #  id: ${target_pk_id}
    EOF
    fi
    
    cat <<EOF >> "$output_file"
      mapAll: true
      etlCondition: "where 1=1"
      commitBatch: 3000
    EOF
    
    echo "YAML file created successfully at: $output_file"
    #chmod +x canal_mysql.sh
    #./canal_mysql.sh dbName tableName pkId outer_adapter_key data_source_key

脚本执行逻辑:执行start_canal_mysql.sh后,它内部逻辑会自动调取start_canal_mysql.sh,从而最终生成各个表的.yml映射文件

脚本执行:先授权脚本执行权限
chmod +x start_canal_mysql.sh
chmod +x canal_mysql.sh

再执行命令
./start_canal_mysql.sh your_database outer_adapter_key data_source_key
参数:your_database数据库名,例如:test1
           outer_adapter_key目标数据库key,可在adapter的application.yml中找到,例如:mysq1
           data_source_key源库数据库key,可在adapter的application.yml中找到,例如:defaultDS

执行示例:./start_canal_mysql.sh test1 mysql1 defaultDS
执行结果:

七、linux设置canal_deployer和canal_adapter服务常驻内存,每次随主机启动而启动(可选)

进入cd /etc/systemd/system目录后,创建my_canal_adapter.service和my_canal_deployer.service

my_canal_deployer.service

 [Unit]
   Description=My Custom Canal deployer Service

   [Service]
   Type=forking
   ExecStart=/usr/local/canal/canal_deployer/bin/restart.sh
   WorkingDirectory=/usr/local/canal/canal_deployer/bin
   Restart=on-failure
   User=root

   [Install]
   WantedBy=multi-user.target

my_canal_adapter.service

[Unit]
   Description=My Custom Canal adapter Service

   [Service]
   Type=forking
   ExecStart=/usr/local/canal/canal_adapter/bin/restart.sh
   WorkingDirectory=/usr/local/canal/canal_adapter/bin
   Restart=on-failure
   User=root

   [Install]
   WantedBy=multi-user.target

创建完成文件后,启用并启动服务

sudo systemctl daemon-reload
sudo systemctl enable my_canal_deployer.service --now
sudo systemctl enable my_canal_adapter.service --now

查看服务运行状态:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值