劳保用品 技术支持 东莞网站建设,商洛城乡建设局网站,嘉兴做网站seo的,潍坊精神文明建设网站【redis】redis缓存与数据库的一致性【1】四种同步策略【2】更新缓存还是删除缓存#xff08;1#xff09;更新缓存#xff08;2#xff09;删除缓存【3】先更新数据库还是先删除缓存#xff08;1#xff09;出现失败时候的情况1-先删除缓存#xff0c;再更新数据库1更新缓存2删除缓存【3】先更新数据库还是先删除缓存1出现失败时候的情况1-先删除缓存再更新数据库更新数据库失败了2-先更新数据库再删除缓存删除缓存失败了3-总结2没有出现失败时候的情况1-先删除缓存再更新数据库延时双删解决这个问题如果是读写分离的架构怎么办强制读主库删除失败了怎么办2-先更新数据库再删除缓存最优方案利用消息队列进行删除的补偿【4】总结【1】四种同步策略
想要保证缓存与数据库的双写一致一共有4种方式即4种同步策略 1先更新缓存再更新数据库 2先更新数据库再更新缓存 3先删除缓存再更新数据库 4先更新数据库再删除缓存。
更新缓存与删除缓存哪种方式更合适应该先操作数据库还是先操作缓存
【2】更新缓存还是删除缓存
1更新缓存
1优点 每次数据变化都及时更新缓存所以查询时不容易出现未命中的情况。
2缺点 更新缓存的消耗比较大。如果数据需要经过复杂的计算再写入缓存那么频繁的更新缓存就会影响服务器的性能。如果是写入数据频繁的业务场景那么可能频繁的更新缓存时却没有业务读取该数据。
2删除缓存
1优点 操作简单无论更新操作是否复杂都是将缓存中的数据直接删除。
2缺点 删除缓存后下一次查询缓存会出现未命中这时需要重新读取一次数据库。从上面的比较来看一般情况下删除缓存是更优的方案。
【3】先更新数据库还是先删除缓存
1出现失败时候的情况
首先我们将先删除缓存与先更新数据库在出现失败时进行一个对比
1-先删除缓存再更新数据库更新数据库失败了
先删除缓存再更新数据库在出现失败时可能出现的问题 1线程A删除缓存成功线程A更新数据库失败 2线程B从缓存中读取数据由于缓存被删进程B无法从缓存中得到数据进而从数据库读取数据此时数据库中的数据更新失败线程B从数据库成功获取旧的数据然后将数据更新到了缓存。 3最终缓存和数据库的数据是一致的但仍然是旧的数据 2-先更新数据库再删除缓存删除缓存失败了
先更新数据库再删除缓存在出现失败时可能出现的问题 1线程A更新数据库成功线程A删除缓存失败 2线程B读取缓存成功由于缓存删除失败所以线程B读取到的是缓存中旧的数据。 3最后线程A删除缓存成功有别的线程访问缓存同样的数据与数据库中的数据是一样。 4最终缓存和数据库的数据是一致的但是会有一些线程读到旧的数据。 3-总结
经过上面的比较我们发现在出现失败的时候是无法明确分辨出先删缓存和先更新数据库哪个方式更好以为它们都存在问题。上述场景出现的问题应该如何解决呢都建议采用重试机制解决。
2没有出现失败时候的情况
1-先删除缓存再更新数据库
1线程A删除缓存成功 2线程B读取缓存失败 3线程B读取数据库成功得到旧的数据 4线程B将旧的数据成功地更新到了缓存 5线程A将新的数据成功地更新到数据库。 可见进程A的两步操作均成功但由于存在并发在这两步之间进程B访问了缓存。最终结果是缓存中存储了旧的数据而数据库中存储了新的数据二者数据不一致。
延时双删解决这个问题
如果是先删缓存、再更新数据库在没有出现失败时可能会导致数据的不一致。如果在实际的应用中出于某些考虑我们需要选择这种方式可以采用延时双删的策略延时双删的基本思路如下 1删除缓存 2更新数据库 3sleep N毫秒 4再次删除缓存。
public void write(String key, Object data) {Redis.delKey(key);db.updateData(data);Thread.sleep(1000);Redis.delKey(key);
}阻塞一段时间之后再次删除缓存就可以把这个过程中缓存中不一致的数据删除掉。而具体的时间要评估你这项业务的大致时间按照这个时间来设定即可。最终保证了数据库和缓存的数据一致
如果是读写分离的架构怎么办强制读主库
如果数据库采用的是读写分离的架构那么又会出现新的问题如下图 此时来了两个请求请求 A更新操作 和请求 B查询操作 1请求 A 更新操作删除了 Redis 2请求主库进⾏更新操作主库与从库进行同步数据的操作 3请 B 查询操作发现 Redis 中没有数据 4去从库中拿去数据 5此时主从同步数据还未完成拿到的数据是旧数据 此时的解决办法就是如果是对 Redis 进行填充数据的查询数据库操作那么就强制将其指向主库进⾏查询。
删除失败了怎么办
如果删除依然失败则可以增加重试的次数但是这个次数要有限制当超出一定的次数时要采取报错、记日志、发邮件提醒等措施。
2-先更新数据库再删除缓存最优方案
1线程A更新数据库成功 2线程B读取缓存成功 3线程A删除缓存成功。 可见最终缓存与数据库的数据是一致的并且都是最新的数据。但线程B在这个过程里读到了旧的数据可能还有其他线程也像线程B一样在这两步之间读到了缓存中旧的数据但因为这两步的执行速度会比较快所以影响不大。对于这两步之后其他进程再读取缓存数据的时候就不会出现类似于进程B的问题了。
利用消息队列进行删除的补偿
先更新数据库后删除缓存这⼀种情况也会出现问题比如更新数据库成功了但是在删除缓存的阶段出错了没有删除成功那么此时再读取缓存的时候每次都是错误的数据了。
此时解决方案就是利用消息队列进行删除的补偿。具体的业务逻辑⽤语⾔描述如下 1请求 线程A 先对数据库进行更新操作 2在对 Redis 进行删除操作的时候发现报错删除失败 3此时将Redis 的 key 作为消息体发送到消息队列中 4系统接收到消息队列发送的消息后再次对 Redis 进行删除操作
但是这个方案会有⼀个缺点就是会对业务代码造成大量的侵入深深的耦合在⼀起所以这时会有⼀个优化的方法我们知道对 Mysql 数据库更新操作后再 binlog 日志中我们都能够找到相应的操作那么我们可以订阅 Mysql 数据库的 binlog 日志对缓存进行操作。
【4】总结
一般情况下删除缓存是比更新缓存更优的方案先更新数据库是比先删除缓存更优的方案总的来说【先更新数据库再删除缓存】就是四个策略中影响最小效果最优的方案。
但是如果需要使用【先删除缓存再更新数据库】的方案的话可以使用【延时双删】【读写分离时强制读主库】【重试机制】来解决问题。
如果使用【先更新数据库再删除缓存】时出现删除缓存失败的情况可以使用【binlog同步到redis】来解决问题。