什么是Canal (卡耐尔) ?

Canal 是用 Java 开发的基于数据库增量日志解析,提供增量数据订阅&消费的中间件
原理基于MySQL的binlog从库监听
 
 
 

一、MySQL环境配置

1、更改MySQL配置 (my.ini / my.cnf):

[mysqld]

# 主库id标识
server-id=1 # 开启binlog日志
log-bin=mysql-bin # 日志格式类型
binlog_format=row # (可选)声明只对哪个库进行日志输出
binlog-do-db=gmall-2021

2、测试用例

没有表就创建一个测试用的表:

CREATE TABLE user_info(
  `id` VARCHAR(255),
  `name` VARCHAR(255),
  `sex` VARCHAR(255)
);

3、监听的账号

和主从复制一样,需要提供一个从库监听的账号:

CREATE USER 'canal'@'%' IDENTIFIED BY '123456';
GRANT ALL ON *.* TO 'canal'@'%' WITH GRANT OPTION;
FLUSH PRIVILEGES; -- GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'canal'@'%';

二、安装Canal

Linux平台:

# 解压方式一
tar -zxvf canal.deployer-1.1.2.tar.gz mkdir canal.deployer-1.1.2 mv bin canal.deployer-1.1.2/
mv logs canal.deployer-1.1.2/
mv lib canal.deployer-1.1.2/
mv conf canal.deployer-1.1.2/ # 解压方式二
mkdir ~/canal-1.1.2
tar -zxvf canal.deployer-1.1.2.tar.gz -C ~/canal-1.1.2/

Windows平台:

新建一个canal的目录,然后打开目录
把压缩包内容解压到目录中即可

通用配置操作:

案例只是为了演示,单机运行的方式进行配置

# 备份 instance.properties文件
cd ~/canal-1.1.2/example
cp instance.properties instance.properties.bak

编辑example下的实例文件

vim ~/canal-1.1.2/conf/example/instance.properties

关键参数项:

# 伪装从库的id,不要和主库id一致即可
canal.instance.mysql.slaveId=20
# 主库IP地址和端口号
canal.instance.master.address=192.168.2.225:3308
# 主库开设的监听账号
canal.instance.dbUsername=canal
canal.instance.dbPassword=123456
# 字符集
canal.instance.connectionCharset=UTF-8
# 默认监听的db?
canal.instance.defaultDatabaseName=canal

三、启动,关闭Canal

restart.sh
startup.bat
startup.sh
stop.sh # windows 平台直接运行 startup.bat
# 关闭就是直接关闭终端窗口即可
startup.bat # linux 平台
startup.
sh # 启动
restart.sh # 重启
stop.sh # 停止

四、创建Canal监听客户端:

canal没有提供默认的终端输出,强制要求客户端监听日志消息:

这里使用Java做一个客户端来查看消息

创建普通Maven项目,引入两个依赖

<dependencies>
<dependency>
<groupId>com.alibaba.otter</groupId>
<artifactId>canal.client</artifactId>
<version>1.1.2</version>
</dependency> <dependency>
<groupId>org.apache.kafka</groupId>
<artifactId>kafka-clients</artifactId>
<version>2.4.1</version>
</dependency>
</dependencies>

客户端类:

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 java.net.InetSocketAddress;
import java.util.List; public class CanalClient { public static void main(String[] args) throws InterruptedException, InvalidProtocolBufferException { //TODO 获取连接
CanalConnector canalConnector = CanalConnectors.newSingleConnector(new InetSocketAddress("127.0.0.1", 11111), "example", "", ""); while (true) { //TODO 连接
canalConnector.connect(); //TODO 订阅数据库
canalConnector.subscribe("canal.*"); //TODO 获取数据
Message message = canalConnector.get(100); //TODO 获取Entry集合
List<CanalEntry.Entry> entries = message.getEntries(); //TODO 判断集合是否为空,如果为空,则等待一会继续拉取数据
if (entries.size() <= 0) {
System.out.println("当次抓取没有数据,休息一会。。。。。。");
Thread.sleep(1000);
} else { //TODO 遍历entries,单条解析
for (CanalEntry.Entry entry : entries) { //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.获取当前事件的操作类型
CanalEntry.EventType eventType = rowChange.getEventType(); //7.获取数据集
List<CanalEntry.RowData> rowDataList = rowChange.getRowDatasList(); //8.遍历rowDataList,并打印数据集
for (CanalEntry.RowData rowData : rowDataList) { JSONObject beforeData = new JSONObject();
List<CanalEntry.Column> beforeColumnsList = rowData.getBeforeColumnsList();
for (CanalEntry.Column column : beforeColumnsList) {
beforeData.put(column.getName(), column.getValue());
} JSONObject afterData = new JSONObject();
List<CanalEntry.Column> afterColumnsList = rowData.getAfterColumnsList();
for (CanalEntry.Column column : afterColumnsList) {
afterData.put(column.getName(), column.getValue());
} //数据打印
System.out.println("Table:" + tableName +
",EventType:" + eventType +
",Before:" + beforeData +
",After:" + afterData);
}
} else {
System.out.println("当前操作类型为:" + entryType);
}
}
}
}
}
}

开启后,想指定的表中写入数据:

客户端输出消息:

当次抓取没有数据,休息一会。。。。。。
当次抓取没有数据,休息一会。。。。。。
当次抓取没有数据,休息一会。。。。。。
当次抓取没有数据,休息一会。。。。。。
当前操作类型为:TRANSACTIONBEGIN
Table:user_info,EventType:INSERT,Before:{},After:{
"sex":"男","name":"张三","id":"1"}
当前操作类型为:TRANSACTIONEND
当前操作类型为:TRANSACTIONBEGIN
Table:user_info,EventType:INSERT,Before:{},After:{"sex":"男","name":"张三","id":"2"
}
当前操作类型为:TRANSACTIONEND

当次抓取没有数据,休息一会。。。。。。

五、Kafka模式

修改 canal.properties
# 指定输出模式为kafka
canal.serverMode = kafka # kafka集群地址,如单机,则写一个即可
canal.mq.servers = hadoop102:9092,hadoop103:9092,hadoop104:9092

修改 example/instance.properties

# mq config
# 指定Topic名称 和 分区数量
canal.mq.topic=canal_test
canal.mq.partitionsNum=1

重启canal以加载配置信息

启动Kafka消费者来查看是否运行:

bin/kafka-console-consumer.sh --bootstrap-server hadoop102:9092 --topic canal_test

执行插入SQL:

INSERT INTO user_info VALUES('1001','zhangsan','male'),('1002','lisi','female');

Kafka控制台:

{
"data": [
{
"id": "1001",
"name": "zhangsan",
"sex": "male"
},
{
"id": "1002",
"name": "lisi",
"sex": "female"
}
],
"database": "gmall-2021",
"es": 1639360729000,
"id": 1,
"isDdl": false,
"mysqlType": {
"id": "varchar(255)",
"name": "varchar(255)",
"sex": "varchar(255)"
},
"old": "null",
"sql": "",
"sqlType": {
"id": 12,
"name": 12,
"sex": 12
},
"table": "user_info",
"ts": 1639361038454,
"type": "INSERT"
}
 
 

【Canal】01 入门 & Kafka模式的更多相关文章

  1. Python学习--01入门

    Python学习--01入门 Python是一种解释型.面向对象.动态数据类型的高级程序设计语言.和PHP一样,它是后端开发语言. 如果有C语言.PHP语言.JAVA语言等其中一种语言的基础,学习Py ...

  2. 设计模式入门,策略模式,c++代码实现

    // test01.cpp : Defines the entry point for the console application.////第一章,设计模式入门,策略模式#include &quo ...

  3. [译]Vulkan教程(01)入门

    [译]Vulkan教程(01)入门 接下来我将翻译(https://vulkan-tutorial.com)上的Vulkan教程.这可能是我学习Vulkan的最好方式,但不是最理想的方式. 我会用“d ...

  4. 「从零单排canal 01」 canal 10分钟入门(基于1.1.4版本)

    1.简介 canal [kə'næl],译意为水道/管道/沟渠,主要用途是基于 MySQL 数据库增量日志解析,提供增量数据 订阅 和 消费.应该是阿里云DTS(Data Transfer Servi ...

  5. Canal详细入门实战(使用总结)

    Canal介绍 Canal简介 canal [kə'næl],译意为水道/管道/沟渠,主要用途是基于 MySQL 数据库增量日志解析,提供增量数据订阅和消费 早期阿里巴巴因为杭州和美国双机房部署,存在 ...

  6. RabbitMQ入门-Topic模式

    上篇<RabbitMQ入门-Routing直连模式>我们介绍了可以定向发送消息,并可以根据自定义规则派发消息.看起来,这个Routing模式已经算灵活的了,但是,这还不够,我们还有更加多样 ...

  7. elasticsearch6.7 01.入门指南(2)

    2.安装(略) 默认情况下,elasticsearch 使用端口 9200 来访问它的 REST API.如果有必要,该端口也可以配置 3.探索集群 3.1 The REST API 既然我们已经启动 ...

  8. 带你入门代理模式/SpringAop的运行机制

    SpringAop 是spring框架中最重要的一项功能之一,同时也是企业级开发记录事物日志等不可或缺的一部分,如果说你的系统需要记录用户访问接口的操作,那SpringAop是很完美的了,当然,拦截器 ...

  9. canal 环境搭建 kafka Zookeeper安装(二)

    第一步 创建Zookeeper 下载完成后 修改 Zookeeper中的 zoo.cfg 修改 dataDir .dataLogDir 集群模式 server.1=ServerIP:2888:3888 ...

  10. Spring Cloud - Nacos注册中心入门单机模式及集群模式

    近几年微服务很火,Spring Cloud提供了为服务领域的一整套解决方案.其中Spring Cloud Alibaba是我们SpringCloud的一个子项目,是提供微服务开发的一站式解决方案. 包 ...

随机推荐

  1. win10系统(专业版)实现双网卡链路聚合

    win10系统(专业版)实现双网卡链路聚合 参考: https://learn.microsoft.com/zh-cn/powershell/module/netswitchteam/new-nets ...

  2. DBEAVER 23.0.2 调整SQL编辑器字体大小 ver:20240112

    DBEAVER 23.0.2 调整SQL编辑器字体大小 ver:20240112 版本是:23.0.2. 菜单-窗口-首选项.用户界面-外观-颜色和字体.展开 DBeaver Font."M ...

  3. gradle打包命令含离线模式

    gradle打包命令gradlew clean 清理gradlew clean build -x test --refresh-dependencies 离线方式: gradlew --offline ...

  4. Java基础:throw和throws的详解

    总结来说,throw是用来抛出一个具体的异常实例,而throws是用来声明方法可能会抛出哪些类型的异常,是对调用者的一种通知和要求. 1. throw 作用: throw关键字用于在方法体内实际抛出一 ...

  5. Linux 驱动:LED子系统

    Linux 驱动:LED子系统 背景 在调试aw9523的时候,为了实现客户要的一个效果.需要修改驱动,但是大概看了一下驱动,但是因为不太熟悉LED子系统,所以有点云里雾里. 参考: https:// ...

  6. hynitron ts 驱动分析

    # hynitron ts 驱动分析 背景 在公司项目中搞LCD移植的时候,在TP功能上,有时候频繁操作屏幕时会导致i2c总线返回-2错误. 问题描述: 1.安卓桌面起来以后,点击屏幕有响应. 2.此 ...

  7. 高通平台UEFI有关介绍

    高通平台UEFI有关介绍 背景 我需要在高通平台上学习点亮LCD,目前通过同事在别的平台的配置代码,我已经将kernel部分的屏幕点亮了:剩余的工作量就在BP侧,也就是系统刚开机的那一段时间.在开发过 ...

  8. Linux 时间 与 定时器

    背景 在学习 Linux 信号 有关知识中,提到了 alarm函数. 进程时间 (原文地址:https://www.cnblogs.com/clover-toeic/p/3845210.html) 进 ...

  9. 无业游民写的最后一个.net有关项目框架

    理想很丰满,现实往往很残酷. 一种按照ddd的方式,根据业务来把自己需要的模块一个一个写出来,再按照模块把需要的接口一个一个的写出来,堆砌一些中间件,以及解耦的command,handler等等 ,一 ...

  10. 【路径规划】 The Dynamic Window Approach to Collision Avoidance (附python代码实例)

    引用与前言 参考链接 引用参考如下: 博客园解释:https://www.cnblogs.com/dlutjwh/p/11158233.html 这篇博客园写的贼棒!我当时就是一边对着论文一边对着他这 ...