110:基于canal整合kafka异步解决数据一致性的问题
1 canal整合kafka的效果演示
课题内容
- 简单回顾canal基本实现原理
- windows环境快速搭建kafka+Zookeeper环境
- canal快速整合kafka异步实现保证数据一致性
canal的实现原理基本总结
canal会启动一个Server端作为一个mysql从节点拉取mysql主节点最新的binlog文件,只要mysql主节点的binlog文件发生变化都会以增量的形式通知给canalServer端,canalServer再通知给canalClient,canalClient自己手动配置刷新Redis接口。
2 构建zookeeper环境
canal目前支持三种监听通讯模式 tcp/kafka/rocketmq
安装zookeeper(当前服务器已有java环境)
- 解压zk压缩包(zookeeper-3.4.14.tar.gz),进入conf目录,将zoo_sample.cfg修改为 zoo.cfg;
- conf同级目录创建文件夹data,修改 zoo.cfg 中的dataDir=xx\xx\data(创建的data文件夹目录)
- 新增环境变量:
ZOOKEEPER_HOME: D:\devtool\zookeeper (zookeeper目录)
Path: 在现有的值后面添加 “;%ZOOKEEPER_HOME%\bin;”
运行zk,双击bin目录下文件zkServer.cmd
3 构建kafka的环境
安装kafka
- 解压kafka安装包(kafka_2.13-2.4.0)改名为 kafka(名称太长运行可能报错)
- config同级目录新建文件夹logs,修改\config\server.properties中的配置
log.dirs= D:\devtool\kafka\logs - 进入到kafka安装目录,执行命令
.\bin\windows\kafka-server-start.bat .\config\server.properties
4 canal将消息异步投递到kafka中
修改canal\conf\example\instance.properties文件配置
canal.instance.master.address=127.0.0.1:3306
canal.instance.dbUsername=canal
canal.instance.dbPassword=canal
canal.mq.topic=mayikt-topic
修改canal\conf\canal.properties文件配置
canal.serverMode = kafka
canal.mq.servers = 127.0.0.1:9092
5 消费者整合kafka获取消息
@KafkaListener(topics = "mayikt-topic")
public void receive(ConsumerRecord<?, ?> consumer) {
System.out.println("topic名称:" + consumer.topic() + ",key:" +
consumer.key() + "," +
"分区位置:" + consumer.partition()
+ ", 下标" + consumer.offset() + "," + consumer.value());
String json = (String) consumer.value();
JSONObject jsonObject = JSONObject.parseObject(json);
String sqlType = jsonObject.getString("type");
JSONArray data = jsonObject.getJSONArray("data");
JSONObject userObject = data.getJSONObject(0);
String id = userObject.getString("id");
String database = jsonObject.getString("database");
String table = jsonObject.getString("table");
String key = database + "_" + table + "_" + id;
if ("UPDATE".equals(sqlType) || "INSERT".equals(sqlType)) {
redisUtils.setString(key, userObject.toJSONString());
return;
}
if ("DELETE".equals(sqlType)) {
redisUtils.deleteKey(key);
}
}
测试效果:
6 canal异步json消息的原理分析
如果是批量插入一次性commit的情况下,data的数据可能是一个数组的形式,需要注意循环遍历批量同步到redis中。
Begin
Insert Insert Insert Update Update
Commit
Kafka推送两条消息 Insert类型消息(data数组长度3)、Update类型消息(data数组长度2)
Ps:conf下自配置文件夹(类似example)下的h2.mv.db是canal缓存数据库结构的文件,如果数据库表有变动可能canal启动后同步不了数据或者字段错位,删除h2.mv.db和meta.dat文件后重启canal即可。