canal可以用来监控数据库数据的变化,从而获得新增数据,或者修改的数据。
canal是应阿里巴巴存在杭州和美国的双机房部署,存在跨机房同步的业务需求而提出的。
阿里系公司开始逐步的尝试基于数据库的日志解析,获取增量变更进行同步,由此衍生出了增量订阅&消费的业务。
6.1 Canal工作原理
MySQL中的binlog日志:面试,mysql数据如何备份,开启binlog日志即可( redis:aof----日志—。 )
redis:需要开启aof appendonly.aof文件----日志文件(记录所有的操作)
例如:
set name "tomcat"
set school "beijng"
set age "20"
... ...
redis:一共16号库,默认在0号库 断电后,内存丢失 重启 ,加载aof文件。
vim appendonly.aof
$6
select
$1
0
$3
set
$4
name
$6
tomcat
....
原理相对比较简单:
- canal模拟mysql slave的交互协议,伪装自己为mysql slave,向mysql master发送dump协议
- mysql master收到dump请求,开始推送binary log给slave(也就是canal)
- canal解析binary log对象(原始为byte流)
canal需要使用到mysql,我们需要先安装mysql,给大家发的虚拟机中已经安装了mysql容器,但canal是基于mysql的主从模式实现的,所以必须先开启binlog.
6.2 开启binlog模式
linux上安装mysql容器.此处不在演示。
(1) 修改/etc/mysqld.cnf 需要开启主 从模式,开启binlog模式。
执行如下命令,编辑mysql配置文件
命令行如下:
docker exec -it mysql /bin/bash
cd /etc/mysql/mysql.conf.d
vim mysqld.cnf
修改mysqld.cnf配置文件,添加如下配置:
上图配置如下:
log-bin=/var/lib/mysql/mysql-bin
server-id=12345
(2) 创建账号 用于测试使用,
使用root账号创建用户并授予权限
create user canal@'%' IDENTIFIED by 'canal';
GRANT SELECT, REPLICATION SLAVE, REPLICATION CLIENT,SUPER ON *.* TO 'canal'@'%';
FLUSH PRIVILEGES;
(3)重启mysql容器
docker restart mysql
6.3 canal容器安装
下载镜像:
docker pull docker.io/canal/canal-server
容器安装
docker run -p 11111:11111 --name canal -d docker.io/canal/canal-server
进入容器,修改核心配置canal.properties 和instance.properties,canal.properties 是canal自身的配置,instance.properties是需要同步数据的数据库连接配置。
执行代码如下:
docker exec -it canal /bin/bash
cd canal-server/conf/
vi canal.properties
cd example/
vi instance.properties
修改canal.properties的id,不能和mysql的server-id重复,如下图:
修改instance.properties,配置数据库连接地址:
这里的canal.instance.filter.regex有多种配置,如下:
mysql 数据解析关注的表,Perl正则表达式.
多个正则之间以逗号(,)分隔,转义符需要双斜杠(\\)
常见例子:
1. 所有表:.* or .*\\..*
2. canal schema下所有表: canal\\..*
3. canal下的以canal打头的表:canal\\.canal.*
4. canal schema下的一张表:canal.test1
5. 多个规则组合使用:canal\\..*,mysql.test1,mysql.test2 (逗号分隔)
注意:此过滤条件只针对row模式的数据有效(ps. mixed/statement因为不解析sql,所以无法准确提取tableName进行过滤)
配置完成后,设置开机启动,并记得重启canal。源码 cobar(分库分表) — mycat。
docker update --restart=always canal
docker restart canal
6.4 canal微服务搭建
当用户执行 数据库的操作的时候,binlog 日志会被canal捕获到,并解析出数据。我们就可以将解析出来的数据进行同步到redis中即可。
思路:创建一个独立的程序,并监控canal服务器,获取binlog日志,解析数据,将数据更新到redis中。这样广告的数据就更新了。
6.4.1 安装辅助jar包
在canal\spring-boot-starter-canal-master中有一个工程starter-canal,它主要提供了SpringBoot环境下canal的支持,我们需要先安装该工程,在starter-canal目录下执行mvn install,如下图:
6.4.2 canal微服务工程搭建
在Better_Po-service下创建Better_Po-service-canal工程,并引入相关配置。
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>Better_Po-service</artifactId>
<groupId>com.Better_Po</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>Better_Po-service-canal</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!--canal依赖-->
<dependency>
<groupId>com.xpand</groupId>
<artifactId>starter-canal</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
application.yml配置
server:
port: 18083
spring:
application:
name: canal
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:7001/eureka
instance:
prefer-ip-address: true
feign:
hystrix:
enabled: true
#hystrix 配置
hystrix:
command:
default:
execution:
timeout:
#如果enabled设置为false,则请求超时交给ribbon控制
enabled: true
isolation:
strategy: SEMAPHORE
#canal配置
canal:
client:
instances:
example:
host: 192.168.211.132
port: 11111
(3)启动类创建
在com.Better_Po中创建启动类,代码如下:
@SpringBootApplication(exclude={DataSourceAutoConfiguration.class})
@EnableEurekaClient
@EnableCanalClient
public class CanalApplication {
public static void main(String[] args) {
SpringApplication.run(CanalApplication.class,args);
}
}
(4)监听创建
在com.Better_Po.listener创建一个CanalDataEventListener类,实现对表增删改操作的监听,代码如下:
package com.Better_Po.canal.listener;
import com.alibaba.otter.canal.protocol.CanalEntry;
import com.xpand.starter.canal.annotation.*;
@CanalEventListener
public class CanalDataEventListener {
// 获取对应列的值
private String getColumnValue(CanalEntry.RowData rowData, String columnName) {
List<CanalEntry.Column> list = rowData.getAfterColumnsList();
for (CanalEntry.Column column : list) {
if (columnName.equals(column.getName())){
return column.getValue();
}
}
return null;
}
/**
* @author 栗子
* @Description 监听新增的数据
* @Date 0:19 2019/8/15
* @param entryType 监听对数据库操作(增、删、改、创建索引等等)
* @param rowData 监听数据
* @return void
**/
@InsertListenPoint
public void onEventInsert(CanalEntry.EntryType entryType, CanalEntry.RowData rowData){
List<CanalEntry.Column> list = rowData.getAfterColumnsList();
for (CanalEntry.Column column : list) {
System.out.println("列名:" + column.getName() + "<--->列值:" + column.getValue());
}
}
/**
* @author 栗子
* @Description 监听更新的数据
* @Date 0:23 2019/8/15
* @param entryType
* @param rowData
* @return void
**/
@UpdateListenPoint
public void onEventUpdate(CanalEntry.EntryType entryType, CanalEntry.RowData rowData){
List<CanalEntry.Column> beforeList = rowData.getBeforeColumnsList();
for (CanalEntry.Column column : beforeList) {
System.out.println("列名:" + column.getName() + "<--->列值:" + column.getValue());
}
System.out.println("----------更新前后----------");
List<CanalEntry.Column> afterList = rowData.getAfterColumnsList();
for (CanalEntry.Column column : afterList) {
System.out.println("列名:" + column.getName() + "<--->列值:" + column.getValue());
}
}
/**
* @author 栗子
* @Description 监听删除的数据
* @Date 0:25 2019/8/15
* @param entryType
* @param rowData
* @return void
**/
@DeleteListenPoint
public void onEventDelete(CanalEntry.EntryType entryType, CanalEntry.RowData rowData){
List<CanalEntry.Column> beforeList = rowData.getBeforeColumnsList();
for (CanalEntry.Column column : beforeList) {
System.out.println("列名:" + column.getName() + "<--->列值:" + column.getValue());
}
}
}
(5)测试
启动canal微服务,然后修改任意数据库的表数据,canal微服务后台输出如下:
来源:CSDN
作者:Better_Po
链接:https://blog.csdn.net/qq_45270898/article/details/102511396