1、先更新数据库,再更新缓存
①问题一:redis若更新失败会发生mysql和redis数据不一致的情况(比如向某个redis集群里写数据,在往某个主机里写数据的时候,主机挂了,集群里从机正在准备上位,没空响应写命令)
②问题二:写入覆盖
2、先更新redis,在更新数据库
这种方式不推荐,业务上一般把mysql数据库中的数据作为底单,保证最后的解释性
①问题一
类似于第一种方法,也会出现redis和mysql数据不一致的现象
3、先删除缓存,在更新数据库
删除完缓存后,第一个到达的请求在redis中没有找到数据,会到mysql中查找并回写到redis,这样就保证了redis和mysql数据一致。
存在的问题:
解决方法:延时双删
首先悲观的认为一定会有线程B在线程A更行mysql数据库的时候方位该数据
延时双删不是强一致性的,这样也存在一些问题,
①线程应该sleep多长时间
因为当线程B发现缓存中没有数据后,会向mysql申请这个数据的值(而此时线程A还没有完成数据的更新),若果sleep的时间过短,线程A在线程B向redis中写入旧值之前做第二次删除操作,然后线程B有往redis中写入了旧值(而在此之前线程A已经在mysql将数据更新为了新值),这就造成了redis和mysql数据不一致的情况
②同步淘汰会降低吞吐量,应该怎么办
红框内启动一个异步线程用来监控是否更新完mysql,若完成则立刻二次删除。
4、先更新数据库,在删除缓存(主流)
虽然存在问题,但相对上面三种来说危害较小。
但这样可能存在线程A更新失败的情况,解决方法用到了消息队列,如下图所示
五、总结
(一般用MQ作为兜底的方案)
先动redis还容易造成更多的请求访问mysql,集火了,压力太大
六、落地实战
对Mysql的操作进行监控,最重要的是binlog日志
需要一种技术方案,能监听到mysql的变动通知redis(既是监听者又是吹哨人),用阿里巴巴的canal
canal作用:
Mysql主从复制原理:
canal工作原理、
总的来说,canal会模仿mysql从机向mysql主机访问数据实现主从一致
实操:
①mysql端
ps:开启MYSQL的binlog写入功能要修改mysql.ini文件,参考相关视频
授权canal连接mysql账号
②canal服务端
注意,canal在linux端,要安装好jdk8
③编写JAVA业务代码(canal客户端代码)
将canal检测到的更改操作(被修改的数据)通过java代码回写到redis
SQL脚本:建立被监控的表
详细步骤参考下图中的canal官网
业务类:主要由 增 删 改 打印实体 ,其中启动的只有main函数
main函数启动后,每秒会打印日志