canal框架实现数据库与缓存一致
保证缓存和数据库一致,市面上通常有2种方法,一是使用延迟双删加消息队列的方式,另外一种是使用canal框架。
那前者有一些问题存在:
1、删除的时间不好控制;
2、并发情况下有些问题不好复现;
3、需要写业务代码完成;
4、如果手动对数据库进行操作,可能会导致缓存与数据库不一致
使用canal框架就可以比较好的去解决以上问题,当然它也有些小缺点,比如前期需要去配置一下相应的文件,也需要写一些代码来确定同步那张表的数据。下面就来看下如果整合canal框架
一、数据库相关配置调整 (此处是采用window安装的mysql)
1、开启binlog
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
①、STATEMENT (语句模式):基于 SQL 语句的复制。binlog 中记录的是执行的 SQL 语句。
②、ROW (行模式):基于行的复制。binlog 中记录的是每行数据的变化。
③、MIXED (混合模式):默认情况下使用 STATEMENT 模式,如果遇到某些不确定的语句,会自动切换到 ROW 模式。
bin log的混合模式(MIXED)是如果你的SQL没有now(),rand()这类函数,那么就采用STATEMENT模式,而如果有函数,那么就采用ROW模式
早期bin log是为了实现主从数据库的同步,从数据库可以去检测主数据库的bin log,从而去实现从库的数据同步
2、重启mysql服务

3、赋值数据同步权限(非必须)
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 启动。
@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接收到消息以后,消费者会对消息进行处理,在消息处理的时候,可以对缓存数据进行删除或者更新操作,从而达到缓存与数据库一致的目的。
浙公网安备 33010602011771号