1 前言
首先阐述一下mysql和redis的关系:mysql是关系型数据库,常用来持久化数据,一定程度可以保证数据的可靠性;redis是用来做缓存数据的,主要是用来提升数据访问的性能。
2 缓存不一致是如何产生的
在高并发的情况下,往往会非常频繁的去对数据库的读写操作,当请求量大了之后,数据库就会扛不住从而宕机,挂了,这个时候我们会引入缓存,将数据存放到缓存中,来减少数据库的压力,这个时候我们去读取数据的时候就会从两个地方读取,那么必然就好产生数据不一致的情况
3 如何去更新缓存和数据库
大致有四种方法
1. 先删除缓存,在更新数据库
2. 先更新数据库,在删除缓存
3. 先更新数据库,在更新缓存
4. 先更新缓存,在更新数据库
3.1 先删除缓存,在更新数据库
客户端1发送了一个写操作,先删除缓存,此时客户端2来了一个读操作进来缓存未命中,去数据库去读取数据,接着更新缓存,返回的结果就读出来的数据,客户端1的请求更新数据库的值
解决办法:
延迟双删:先删除缓存,在更新数据库,延迟一段时间,在去删除缓存,延迟一段时间,这个时间必须大于一次写操作的的时间,多长时间看测试而定,基本情况下不会出来数据不一致
3.2 先更新数据库,在删除缓存 (推荐)
推荐原因:
实际中,这个问题出现的并不高,因为缓存的写入是要比数据库的快,所以很难出现客户端1已经更新数据库并且删了缓存,客户端2才更新完缓存的情况,一般都是最后一个客户端2的情况,所以 先更新数据库在删除缓存的方案是可以保证数据的一致性的。
解决方案:
1. 加上缓存过期时间
2. 加上缓存过期时间,在异步操作缓存 (重试机制和订阅mysql binlog)
重试机制:借助消息队列完成,把删除缓存放入到消息队列,由消费者完成删除缓存操作
如果第一次删除缓存失败,消息队列重新读取数据,进行删除,删除成功,就把数据移除消息队列。
订阅Mysql binlog:只要更新数据库成功,就会产生一条变更日志,记录在 binlog 里。
于是我们就可以通过订阅 binlog 日志,拿到具体要操作的数据,然后再执行缓存删除,阿里巴巴开源的 canal 中间件就是基于这个实现的。