redis缓存双写一致性与基于docker的canal搭建双写一致性工程

497 阅读5分钟

redis缓存双写一致性问题:

缓存双写一致性的理解

  • redis中有数据   需要和数据库的值相同

  • redis中无数据   数据库的值要是最新的,需要回写redis

  • 缓存细分两种   只读缓存和

  •  读写缓存   1.同步直写策略  写数据库后也同步写redis缓存,缓存和数据库中的数据一致(会对性能有一定的影响)

  •                   2.异步缓写策略 mysql数据变动,业务允许一段时间后作用于redis,异常情况出现的话,需要人工修补,或者借助kafka,rabbitMQ等消息中间件实现重写

  • 双检加锁策略

  • 数据库和缓存一致性的几种策略

双检加锁策略:

使用场景 redis中无数据时需要去mysql查数据,查到之后回写到redis,多线程会导致,一个线程正在回写,另一个线程也去查mysql然后也回写数据

从而mysql运动量飙升,可能打爆mysql 也就是 缓存击穿,所以再第一时间redis查不到数据时,就要立刻加锁,加锁之后再查一次,从而保证单线程操作回写,

这样其他线程拿到锁进来的时候就可以在redis查到值,从而跳过步骤

延时双删策略:

更新操作在更新mysql之前删一次redis数据,更新之后再删一次redis数据然后再回写最新的数据到redis

数据库和缓存一致性的几种策略:

  • 可以停止redis的情况下:挂牌报错,系统维护   
  • 先更新mysql再更新redis
  • 先更新redis后更新数据库 同上错误     
  • 先删除缓存,再更新数据库  延时双删策略:
  • 先更新数据库再删除redis再回写redis (建议选择)
  • 如何保证数据的最终一致性?  redis和mysql不可能百分之百一致,但可以通过binlog记录数据库更新操作,然后将数数据写入mq,然后如果后续操作缓存失败可以读取mq进行反复操作,从而保证数据一致性

Image.png

Image.png

如何搭建缓存双写一致性的工程?

canal工作原理:

canal模拟 MySQL slave的交互协议,伪装自己为MySQL slave,

向MySQLmaster发送dump协议 MySQL master 收到dump请求,

开始推送binarylog给slave(即canal) canal 解析 binary log 对象(原始为byte流)

Canal是一个开源的数据库复制和实时数据捕获(CDC)解决方案,用于与MySQL一起使用。它可以捕获MySQL数据库的变更日志,并将其传送给其他位置或系统进行进一步处理。

使用Canal可以实现以下功能:

  1. 数据同步和数据集成:Canal可以将MySQL数据库的变更日志传送到其他位置或系统,以实时保持数据的同步和一致性。这对于构建数据仓库、数据分析、缓存刷新等场景非常有用。

  2. 实时数据监控和分析:Canal可以订阅MySQL数据库的变更事件,并将其传送给实时数据分析或监控系统。这样可以实时监测数据库的变化,并及时做出相应的处理。

  3. 数据库解耦和架构升级:通过使用Canal,可以将数据库的写操作与读操作进行解耦,从而实现更高的扩展性和可用性。同时,在进行数据库架构升级时,可以先将变更日志传送给新的数据库实例,以确保数据的一致性和平滑过渡。

  4. 数据库镜像和备份:Canal可以实时复制MySQL数据库的变更日志,并将其传送给其他数据库实例,从而实现数据库的镜像和备份。这对于容灾和故障恢复非常重要。

总之,Canal提供了一种可靠而高效的方式来捕获和传送MySQL数据库的变更日志,为数据同步、实时监控和分析、解耦架构等场景提供了支持。

配置mysql:

[mysqld]

log-bin=mysql-bin #开启 binlog

binlog-format=ROW #选择ROW模式

server_id=1    #配置MySQL replaction,不要和canal的 slaveId重复

Image.png

启动mysql:


docker run -d -p 3306:3306 --privileged=true \

-v /xtstudy/mysql/log:/var/log/mysql \

-v /xtstudy/mysql/data:/var/lib/mysql \

-v /xtstudy/mysql/conf:/etc/mysql/conf.d \

-e MYSQL_ROOT_PASSWORD=123456 \

--name mysql mysql:5.7

通过以上配置,MySQL 将使用指定的字符集和校对规则运行。

  • 将容器内部的MySQL服务端口(3306)映射到主机的同一端口(3306)上。

  • 将主机上的目录 /xtstudy/mysql/log 映射到容器内部的 MySQL 日志目录 /var/log/mysql。

  • 将主机上的目录 /xtstudy/mysql/data 映射到容器内部的 MySQL 数据目录 /var/lib/mysql。

  • 将主机上的目录 /xtstudy/mysql/conf 映射到容器内部的 MySQL 配置文件目录 /etc/mysql/conf.d。

  • 设置 MySQL 的 root 用户密码为 "123456"。

mysql> CREATE USER 'canal'@'%' IDENTIFIED BY '123456';

Query OK, 0 rows affected (0.00 sec)

mysql> GRANT ALL PRIVILEGES ON . TO 'canal'@'%';

Query OK, 0 rows affected (0.00 sec)

mysql> FLUSH PRIVILEGES;

Query OK, 0 rows affected (0.01 sec)

mysql> SHOW GRANTS FOR 'canal'@'%';

启动canal:

docker run -p 11111:11111 --name canal -d canal/canal-server:v1.1.6

创建canal宿主机挂载目录

mkdir -p /docker/canal/conf

查看docker运行情况,复制容器id

docker ps

拷贝配置文件

docker cp canal:/home/admin/canal-server/conf/example/instance.properties /docker/canal/conf

530fd9f8fe96ebb05c94dbee193da51.png

这里密码不是canal是123456 CREATE USER 'canal'@'%' IDENTIFIED BY '123456';

删除容器重启canal

docker rm  -f canal

docker run -p 11111:11111 --name canal -v /docker/canal/conf/instance.properties:/home/admin/canal-server/conf/example/instance.properties -v/docker/canal/logs/:/home/admin/canal-server/logs/example/ -d canal/canal-server:v1.1.6

-- 创建user表

CREATE TABLE user (

  id INT PRIMARY KEY AUTO_INCREMENT,

  username VARCHAR(50) NOT NULL,

  age INT,

  email VARCHAR(100) UNIQUE,

  address VARCHAR(255)

);

-- 插入示例值

INSERT INTO user (username, age, email, address) VALUES

  ('张三', 25,  'zhangsan@example.com', '北京市朝阳区'),

  ('李四', 30,  'lisi@example.com', '上海市浦东新区'),

  ('王五', 28, 'wangwu@example.com', '广州市天河区');

手动修改数据库,查看canal监听效果,控制台打印监听:

Image.png

通过id查询redis回写成功

Image.png

java代码可以参考canal官网,也可以私信博主!!