Canal搭建
需求:解决私有环境数据库的基础数据同步问题,每当中心库基础数据发生改变时,其他私有库都会增量同步
Canal主要用途是基于 MySQL 数据库增量日志解析,提供增量数据订阅和消费
Canal将自己伪装成MySQL的从服务器,接收主服务器的binlog日志,然后转发给客户端消费
搭建环境
MySQL环境
这里使用docker来快速启动一个mysql来模拟
docker run --name mysql -p 3307:3306 -d -e MYSQL_ROOT_PASSWORD=mysql mysql
启动后需要开启binlog,还需要将binlog的储存格式设置为ROW模式因为用的镜像是8.0的,默认开启了binlig,模式也是ROW
可以根据
SHOW VARIABLES LIKE 'log_bin'
SHOW VARIABLES LIKE 'binlog_format'
这两个sql来查看mysql是设置好
如果要设置的话可以进入到容器里边设置
docker exec -it mysql bash
配置文件在/etc/mysql/里
echo 'log-bin=mysql-bin' >> my.cnf
echo 'binlog-format=ROW' >> my.cnf
将配置追加到my.cnf里,然后重启容器即可
以上命令可以简化为
docker exec -it mysql bash -c "echo 'log-bin=mysql-bin' >> /etc/mysql/my.cnf"
docker exec -it mysql bash -c "echo 'binlog-format=ROW' >> /etc/mysql/my.cnf"
这样就可以省去进入容器的那一步
如果修改了配置记得重启容器
docker restart mysql
最后需要授权一个账号给canal
CREATE USER canal IDENTIFIED BY 'canal';
GRANT SELECT, REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'canal'@'%';
-- GRANT ALL PRIVILEGES ON *.* TO 'canal'@'%' ;
FLUSH PRIVILEGES;
Canal环境
Canal使用的是软件包
官网:https://github.com/alibaba/canal/wiki/QuickStart
下载
wget https://github.com/alibaba/canal/releases/download/canal-1.0.17/canal.deployer-1.0.17.tar.gz
解压
mkdir /tmp/canal
tar zxvf canal.deployer-$version.tar.gz -C /tmp/canal
配置文件夹里有个example的文件夹,这是一个实列配置(instance),需要将这个实列配置成自己的数据源
vi conf/example/instance.properties
主要是修改数据库地址和用户名
canal.instance.master.address
canal.instance.dbUsername
canal.instance.dbPassword
在启动前还需要改一下启动脚本,因为canal启动默认是需要1G以上的jvm内存,如果内存太小会报错
canal Cannot allocate memory
在启动脚本startup.sh里找到JAVA_OPTS,将内存参数改成256m
然后启动
sh bin/startup.sh
在logs里查看canal的日志,观察是否启动成功
客户端
启动成功后需要一个客户端来接收消息
先添加依赖
<dependency>
<groupId>com.alibaba.otter</groupId>
<artifactId>canal.client</artifactId>
<version>1.1.0</version>
</dependency>
官网提供了一个Java版本得Demo
https://github.com/alibaba/canal/wiki/ClientExample
将程序里得ip地址改成canal所在得ip,然后就可以启动了
在连接后会注册一个过滤规则
connector.subscribe(".*\\..*");
这个规则可以指定哪些表被监听
常见例子:
1. 所有表:.* or .*\\..*
2. canal schema下所有表: canal\\..*
3. canal下的以canal打头的表:canal\\.canal.*
4. canal schema下的一张表:canal\\.test1
5. 多个规则组合使用:canal\\..*,mysql.test1,mysql.test2 (逗号分隔)
注意在canal中得instance.properties配置文件里也有这个配置canal.instance.filter.regex,如果在客户端重新注册新的规则,配置文件的规则会被覆盖
使用了哪个规则可以看example日志
2022-02-14 14:41:59.773 [main] INFO c.a.otter.canal.instance.core.AbstractCanalInstance - subscribe filter change to .*\..*
2022-02-14 14:41:59.773 [main] WARN c.a.o.canal.parse.inbound.mysql.dbsync.LogEventConvert - --> init table filter : ^.*\..*$
在这个demo中,处理空事件超过120次就会停止
int totalEmptyCount = 120;
while (emptyCount < totalEmptyCount)
可以设置为while(true)
接下来获取事件
Message message = connector.getWithoutAck(batchSize);
Message中保存了List<CanalEntry.Entry>,遍历这个集合就能拿到消息,CanalEntry.Entry保存了元数据以及变更的详情
//反序列化
CanalEntry.RowChange rowChage = CanalEntry.RowChange.parseFrom(entry.getStoreValue());
//具体事件
CanalEntry.EventType eventType = rowChage.getEventType();
接下来就是消费消息
for (CanalEntry.RowData rowData : rowChage.getRowDatasList()) {
if (eventType == CanalEntry.EventType.DELETE) {
printColumn(rowData.getBeforeColumnsList());
} else if (eventType == CanalEntry.EventType.INSERT) {
printColumn(rowData.getAfterColumnsList());
} else {
System.out.println("-------> before");
printColumn(rowData.getBeforeColumnsList());
System.out.println("-------> after");
printColumn(rowData.getAfterColumnsList());
}
}
demo中监听了删除事件、新增事件和修改事件,可以看到
getBeforeColumnsList()是变更前的
getAfterColumnsList()是变更后的
更多的事件类型被封装在EventType中
最后需要转化为具体的SQL,并在具体环境中执行变更SQL来解决业务场景
新增
/**
* @param entry
* @param rowData
* @param flag 忽略主键新增
*/
static void insertSql(CanalEntry.Entry entry, CanalEntry.RowData rowData, boolean flag) {
StringBuilder sql = new StringBuilder();
sql.append("insert into ").append(entry.getHeader().getTableName()).append(" (");
for (int i = 0; i < rowData.getAfterColumnsList().size(); i++) {
if (flag && rowData.getAfterColumnsList().get(i).getIsKey()) {
continue;
}
sql.append(rowData.getAfterColumnsList().get(i).getName());
if (i != (rowData.getAfterColumnsList().size() - 1)) {
sql.append(",");
}
}
sql.append(") ").append("values (");
for (int i = 0; i < rowData.getAfterColumnsList().size(); i++) {
if (flag && rowData.getAfterColumnsList().get(i).getIsKey()) {
continue;
}
sql.append(rowData.getAfterColumnsList().get(i).getValue());
if (i != (rowData.getAfterColumnsList().size() - 1)) {
sql.append(",");
}
}
sql.append(") ");
System.out.println(sql);
}
更新
static void updateSql(CanalEntry.Entry entry, CanalEntry.RowData rowData) {
StringBuilder sql = new StringBuilder();
sql.append("update ").append(entry.getHeader().getTableName()).append(" set ");
for (int i = 0; i < rowData.getAfterColumnsList().size(); i++) {
sql.append(rowData.getAfterColumnsList().get(i).getName())
.append("=").append(rowData.getAfterColumnsList().get(i).getValue());
if (i != (rowData.getAfterColumnsList().size() - 1)) {
sql.append(",");
}
}
sql.append(" where ");
for (CanalEntry.Column column : rowData.getAfterColumnsList()) {
if (column.getIsKey()) {
sql.append(column.getName()).append("=").append(column.getValue());
}
}
System.out.println(sql);
}
删除
static void deleteSql(CanalEntry.Entry entry, CanalEntry.RowData rowData) {
StringBuilder sql = new StringBuilder();
sql.append("delete ").append(entry.getHeader().getTableName()).append(" where ");
for (CanalEntry.Column column : rowData.getBeforeColumnsList()) {
if (column.getIsKey()) {
sql.append(column.getName()).append("=").append(column.getValue());
}
}
System.out.println(sql);
}
最后消费了需要提交或者回滚事务
在/logs/example中的meta.log中可以看到消费到哪个binlog,哪个偏移量
总结
Canal使用起来并不是非常复杂,虽然需要额外的写一个客户端,但实现起来代码量并不大
在我这个业务场景中,因为基础数据的变更不会非常频繁,所以对性能这方面没有太高要求
Canal搭建的更多相关文章
- 阿里Canal框架(数据同步中间件)初步实践
最近在工作中需要处理一些大数据量同步的场景,正好运用到了canal这款数据库中间件,因此特意花了点时间来进行该中间件的的学习和总结. 背景介绍 早期,阿里巴巴B2B公司因为存在杭州和美国双机房部署,存 ...
- canal数据同步
前面提到数据库缓存不一致的几种解决方案,但是在不同的场景下各有利弊,而今天我们使用的canal进行缓存与数据同步的方案是最好的,但是也有一个缺点,就是相对前面几种解决方案会引入阿里巴巴的canal组件 ...
- canal demo搭建全记录
一.环境介绍 canal是阿里开源的中间件,主要用于同步mysql数据库变更.具体参见:https://github.com/alibaba/canal/releases 搭建环境: vmware c ...
- mysql同步之otter/canal环境搭建完整详细版
接上一篇mysql 5.7多源复制(用于生产库多主库合并到一个查询从库). 这一篇详细介绍otter/canal环境搭建以及当同步出现异常时如何排查.本文主要参考https://blog.csdn.n ...
- 「从零单排canal 02」canal集群版 + admin控制台 最新搭建姿势(基于1.1.4版本)
canal [kə'næl],译意为水道/管道/沟渠,主要用途是基于 MySQL 数据库增量日志解析,提供增量数据 订阅 和 消费.应该是阿里云DTS(Data Transfer Service)的开 ...
- 阿里Canal中间件的初步搭建和使用
一.前言 Binlog是MySQL数据库的二进制日志,用于记录用户对数据库操作的SQL语句(除了数据查询语句)信息.而Binlog格式也有三种,分别为STATEMENT.ROW.MIXED.STATM ...
- CanalAdmin搭建Canal Server集群
CanalAdmin搭建Canal Server集群 一.背景 二.机器情况 三.实现步骤 1.下载canal admin 2.配置canalAdmin 3.初始化canal admin数据库 4.启 ...
- Canal监控Mysql同步到Redis(菜鸟也能搭建)
首先要Canal服务端下载:链接: https://pan.baidu.com/s/1FwEnqPC1mwNXKRwJuMiLdg 密码: r8xf 连接数据库的时候需要给予连接数据库权限:在my.i ...
- canal 环境搭建 canal 与kafka通信(三)
canal 占用了生产者 .net core端 使用消费者获取canal 消息 安装 Confluent.Kafka demo使用 1.3.0 public static void Consumer ...
随机推荐
- 靶场vulnhub-CH4INRULZ_v1.0.1通关
1.CH4INRULZ_v1.0.1靶场通关 ch4inrulz是vulnhub下的基于Linux的一个靶场,作为练习之用 目的:通过各种手段,获取到靶机内的flag的内容 2.环境搭建: 攻击机 K ...
- AcWing周赛43
AcWing周赛43 题源:https://www.acwing.com/activity/content/1233/ 4314. 三元组 直接暴力做就是了,我一开始还在找规律..悲 我滴代码 #in ...
- Python多线程Threading爬取图片,保存本地,openpyxl批量插入图片到Excel表中
之前用过openpyxl库保存数据到Excel文件写入不了,换用xlsxwriter 批量插入图片到Excel表中 1 import os 2 import requests 3 import re ...
- 【大话云原生】煮饺子与docker、kubernetes之间的关系
云原生的概念最近非常火爆,企业落地云原生的愿望也越发强烈.看过很多关于云原生的文章,要么云山雾罩,要么曲高和寡. 所以笔者就有了写<大话云原生>系列文章的想法,期望用最通俗.简单的语言说明 ...
- JavaWeb和WebGIS学习笔记(五)——使用OpenLayers显示地图
系列链接: Java web与web gis学习笔记(一)--Tomcat环境搭建 Java web与web gis学习笔记(二)--百度地图API调用 JavaWeb和WebGIS学习笔记(三)-- ...
- Ansible Notes: module: get_facts
功能:用来获取remote host的facts 它是一个非常基础的模块[1],playbook里面可以直接当关键字用gather_facts: False 执行set_up模块时自动调用get_fa ...
- Bugku CTF练习题---加密---凯撒部长的奖励
Bugku CTF练习题---加密---凯撒部长的奖励 flag:SYC{here_Is_yOur_rEwArd_enjOy_It_Caesar_or_call_him_vIctOr_is_a_Exc ...
- GitHub 桌面版 v3.0 新特性「GitHub 热点速览」
新版本一般意味着更强的功能特性,比如 GitHub Desktop v3.0.虽然未发布新版本,但本周收录的 7 个开源项目颇有"新版"味.比如,破解(恢复)密码能力 Max 的 ...
- Django学习——图书管理系统图书修改、orm常用和非常用字段(了解)、 orm字段参数(了解)、字段关系(了解)、手动创建第三张表、Meta元信息、原生SQL、Django与ajax(入门)
1 图书管理系统图书修改 1.1 views 修改图书获取id的两种方案 1 <input type="hidden" name="id" value=& ...
- logging日志模块详细,日志模块的配置字典,第三方模块的下载与使用
logging日志模块详细 简介 用Python写代码的时候,在想看的地方写个print xx 就能在控制台上显示打印信息,这样子就能知道它是什么 了,但是当我需要看大量的地方或者在一个文件中查看的时 ...