Docker搭建Cannal监听MySQL8.x实战

Canal介绍

官网:https://github.com/alibaba/canal

canal是阿里巴巴旗下的一款开源项目,纯Java开发。基于数据库增量日志解析,提供增量数据订阅&消费,目前主要支持了MySQL(也支持mariaDB).
在这里插入图片描述

目标

实时监控MySQL数据变化(后续可进行数据同步)。

实操——Docker搭建Canal

前置条件:准备一台阿里云ECS(系统CentOS7),并Docker安装好MySQL8.x(默认开启了bin_log且模式为ROWDATA)

docker run -it -d -p 11111:11111 --name canal-server  canal/canal-server

进入该容器内部

docker exec -it canal-server /bin/bash

查看文件目录
在这里插入图片描述
进入canal-server并查看文件目录
在这里插入图片描述
重点是conf目录(涉及监听哪个数据源)
在这里插入图片描述
查看canal.properties文件
在这里插入图片描述
在这里插入图片描述

example文件夹是一个实例,如需监听多个实例,则配置多个。
进入example并查看目录
在这里插入图片描述
根据实际情况修改instance.properties配置文件
在这里插入图片描述
重启Canal-server

docker restart canal-server

=========================================================

实操——Java整合Canal,编写Canal客户端

创建Maven工程并配置pom.xml

	<properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>com.alibaba.otter</groupId>
            <artifactId>canal.client</artifactId>
            <version>1.1.5</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba.otter</groupId>
            <artifactId>canal.protocol</artifactId>
            <version>1.1.5</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.22</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.79</version>
        </dependency>
    </dependencies>

创建CanalClient类

package com.lemon.canal;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.otter.canal.client.CanalConnector;
import com.alibaba.otter.canal.client.CanalConnectors;
import com.alibaba.otter.canal.protocol.CanalEntry;
import com.alibaba.otter.canal.protocol.Message;
import com.google.protobuf.ByteString;
import com.google.protobuf.InvalidProtocolBufferException;
import lombok.extern.slf4j.Slf4j;

import java.net.InetSocketAddress;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * Canal客户端
 *
 * @author Jiahai
 */
@Slf4j
public class CanalClient {
    /**
     * TODO canal服务器IP
     */
    private static final String IP = "119.23.65.233";

    /**
     * canal端口
     */
    private static final int PORT = 11111;

    /**
     * 目标
     */
    private static final String DESTINATION = "example";

    /**
     * 用户名
     */
    private static final String USER = "admin";

    /**
     * 密码
     */
    private static final String PASSWORD = "4ACFE3202A5FF5CF467898FC58AAB1D615029441";

    public static void main(String[] args) throws InterruptedException, InvalidProtocolBufferException {
        // 创建单链接的客户端链接
        CanalConnector canalConnector = CanalConnectors.newSingleConnector(new InetSocketAddress(IP, PORT), DESTINATION, USER, PASSWORD);

        while (true) {
            // 连接
            canalConnector.connect();
            // 客户端订阅,重复订阅时会更新对应的filter信息
            //    说明:
            //    a. 如果本次订阅中filter信息为空,则直接使用canal server服务端配置的filter信息
            //    b. 如果本次订阅中filter信息不为空,目前会直接替换canal server服务端配置的filter信息,以本次提交的为准
            canalConnector.subscribe("test.*");
            // 获取数据,自动进行确认,该方法返回的条件:尝试拿batchSize条记录,有多少取多少,不会阻塞等待
            Message message = canalConnector.get(200);
            // 获取Entry集合
            List<CanalEntry.Entry> entryList = message.getEntries();
            if (entryList.isEmpty()) {
                log.warn("=== 没有新数据 等待10秒再尝试拉取 ===");
                TimeUnit.SECONDS.sleep(10);
                continue;
            }
            // 遍历 entryList并逐条解析
            for (CanalEntry.Entry entry : entryList) {
                // 1、获取数据库表名
                String tableName = entry.getHeader().getTableName();
                // 2、获取类型
                CanalEntry.EntryType entryType = entry.getEntryType();
                // 3、获取传输的二进制数据
                ByteString storeValue = entry.getStoreValue();
                // 4、判断当前 entryType是否为 ROWDATA
                if (CanalEntry.EntryType.ROWDATA.equals(entryType)) {
                    // 5、反序列化数据
                    CanalEntry.RowChange rowChange = CanalEntry.RowChange.parseFrom(storeValue);
                    // 6、获取数据集
                    List<CanalEntry.RowData> rowDataList = rowChange.getRowDatasList();
                    JSONObject before = new JSONObject();
                    JSONObject after = new JSONObject();
                    // 7、遍历数据集
                    rowDataList.forEach(rowData -> {
                        List<CanalEntry.Column> beforeColumnsList = rowData.getBeforeColumnsList();
                        List<CanalEntry.Column> afterColumnsList = rowData.getAfterColumnsList();
                        beforeColumnsList.forEach(column -> before.put(column.getName(), column.getValue()));
                        afterColumnsList.forEach(column -> after.put(column.getName(), column.getValue()));
                        log.info("表名:{}, 数据before: {}", tableName, before);
                        log.info("表名:{}, 数据after: {}", tableName, after);
                    });
                }
            }
        }
    }
}

MySQL新建数据库test,并创建表t_user
在这里插入图片描述

效果
插入数据

INSERT INTO t_user VALUES (1, 'Lisa', 19);

在这里插入图片描述
继续插入数据

INSERT INTO t_user VALUES (2, 'Tom', 20);
INSERT INTO t_user VALUES (3, '灰太狼', 18);

在这里插入图片描述
删除数据

DELETE FROM t_user WHERE user_id = 3;

在这里插入图片描述
批量更新数据

UPDATE t_user SET age = 6;

在这里插入图片描述

The end

可以自行整合RocketMQ 或 Kafka(Stream算子)等。
例 MySQL → Canal → MQ → Flink → MQ → 消费者

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值