canal框架实现数据库与缓存一致

保证缓存和数据库一致,市面上通常有2种方法,一是使用延迟双删加消息队列的方式,另外一种是使用canal框架。
那前者有一些问题存在:
1、删除的时间不好控制;
2、并发情况下有些问题不好复现;
3、需要写业务代码完成;
4、如果手动对数据库进行操作,可能会导致缓存与数据库不一致

使用canal框架就可以比较好的去解决以上问题,当然它也有些小缺点,比如前期需要去配置一下相应的文件,也需要写一些代码来确定同步那张表的数据。下面就来看下如果整合canal框架

一、数据库相关配置调整 (此处是采用window安装的mysql)

1、开启binlog

找到 MySQL 配置文件,Linux 默认配置在 /etc/my.cnf 文件中,而 Windows 在安装目录的路径如下:

MySQL 8.0 及更高版本:C:\ProgramData\MySQL\MySQL Server 8.0\my.ini  (需要注意的是,ProgramData 可能是一个隐藏文件夹)

MySQL 5.7 及更低版本:C:\Program Files\MySQL\MySQL Server 5.7\my.ini (具体路径可能因安装时的选择而有所不同)

log-bin="JAVACN-bin"
binlog_format=ROW
binlog-do-db=xxx

上面的xxx代表的是哪个数据库,如果此项不配置,则所有数据库都会开启 Binlog,如果需要指定开启多个只需要如下配置即可:

binlog-do-db=aicloud
binlog-do-db=aicloud2
binlog-do-db=aicloud3
binlog_format 支持三种数据库格式:

STATEMENT (语句模式):基于 SQL 语句的复制。binlog 中记录的是执行的 SQL 语句。

②、ROW (行模式):基于行的复制。binlog 中记录的是每行数据的变化。

③、MIXED (混合模式):默认情况下使用 STATEMENT 模式,如果遇到某些不确定的语句,会自动切换到 ROW 模式。

bin log的混合模式(MIXED)是如果你的SQL没有now(),rand()这类函数,那么就采用STATEMENT模式,而如果有函数,那么就采用ROW模式

早期bin log是为了实现主从数据库的同步,从数据库可以去检测主数据库的bin log,从而去实现从库的数据同步

注意:基于 Canal 实现的数据同步只能使用 ROW 格式,因为它不能将 SQL 语句执行变成对应的数据,所以它只能获取修改后的数据进行同步。

2、重启mysql服务

Linux 平台使用命令重启:systemctl restart mysqld
Windows 平台在 我的电脑==>管理==>服务和应用管理,找到服务列表中的 MySQL 服务重启即可,如下图所示:

 3、赋值数据同步权限(非必须)

在 MySQL 中执行以下命令给 Canal 赋值同步权限:
use mysql;
CREATE USER canal IDENTIFIED BY 'canal';  
GRANT SELECT, REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'canal'@'%';
FLUSH PRIVILEGES;

这个use mysql就是自带的那个mysql数据库,canal使用mysql的用户,最好别用root,原因:1、root用户权限很大,而canal同步只需要查询;2、canal那边使用的用户默认是canal,如果MySQL不改那canal那边也要改用户为root。

 二、安装并配置canal

1、下载解压:下载地址:https://github.com/alibaba/canal/releases。解压到一个没有中文路径和空格的目录中。

2、解压后,修改conf/canal.properties文件

canal.serverMode=kafka
canal.mq.servers=127.0.0.1:9092

3、修改conf/example/instance.properties内容

① 打开注释并修改“canal.instance.mysql.slaveId=20”,不能为 1,这个表示从节点 id,因为默认主节点 id 为 1,所以这里不能为 1.

② 连接的 MySQL 地址检查下是否需要修改“canal.instance.master.address=127.0.0.1:3306”。

③ 修改配置“canal.mq.topic=canal_test”,发送到 Kafka 某个主题下。

 对了,这个canal框架需要配合消息队列使用

4、将 plugin jar 包拷贝到 lib 目录。

5、启动canal:打开bin目录,双击startup.bat 启动。

三、项目中集成canal
此处我是集成了kafka这消息队列来配合使用的,至于项目中如何集成kafka,可以参照我之前的文章: https://www.cnblogs.com/qwg-/p/18921313
    @KafkaListener(topics = {CANAL_TOPIC})
    public void canalListen(String data,  Acknowledgment ack) throws JsonProcessingException {
        HashMap<String, Object> map = objectMapper.readValue(data, HashMap.class);  //去获取数据
        if (CollUtil.isNotEmpty(map) &&
                map.get("database").toString().equals("aicloud") &&
                map.get("table").toString().equals("answer")){   //判断需要监听的数据库和对应表
            // 更新 Redis 缓存
            String cacheKey = "";
            List<HashMap<String,Object>> list = (List<HashMap<String,Object>>) map.get("data");  //获取里面数据
            for (HashMap<String,Object> item : list) {
                long uid = Long.parseLong(item.get("uid").toString());
                Integer model = Integer.valueOf(item.get("model").toString());
                Integer type = Integer.valueOf(item.get("type").toString());
                cacheKey = AppVariable.getListCacheKey(uid, model, type);   //获取key
                redisTemplate.delete(cacheKey);    //将缓存删除

            }
        }
        ack.acknowledge();   // 手动提交
    }

验证:使用navicate进行SQL执行,或者直接操作表,都能看到数据被清空,那么缓存就会重新去数据库拉取数据,当然也可以对缓存进行更新操作,具体根据自行设计。

canal其流程原理:监听mysql的bin log,当发现bin log日志内容发生变化,就会发送消息给kafka,kafka接收到消息以后,消费者会对消息进行处理,在消息处理的时候,可以对缓存数据进行删除或者更新操作,从而达到缓存与数据库一致的目的。

 

 

posted @ 2025-07-05 10:21  多多指教~  阅读(48)  评论(0)    收藏  举报