在实际开发中,我们常常会遇到这样的问题:数据库更新后,Redis 缓存数据与之不一致。虽然有多种解决方案,但并没有一种完美适配所有场景的方案。今天,我们就来深入探讨一种实用性较强的方案 —— 延迟双删。
常用缓存策略
在说正题之前,先介绍一下前置依赖,也就是缓存策略。
以下是一些常用的缓存策略:
缓存旁置(Cache-Aside)
- 基本思想 :在查询数据时,先查询缓存,如果缓存中有数据(缓存命中),直接返回缓存数据;如果缓存中没有数据(缓存未命中),则从数据库查询数据,将查询结果写入缓存,再返回数据。
- 优点 :缓存和数据库解耦,缓存系统和数据库系统相互独立,一个系统挂掉不影响另一个系统的使用。
- 缺点 :可能出现缓存与数据库数据不一致的情况,如在写数据库后删除缓存的过程中,有请求查询缓存,此时缓存还没有更新,就会读取到旧数据。
缓存贯穿(Read-Through)
- 基本思想 :查询缓存未命中时,由缓存服务器自动从数据库加载数据,并将数据缓存起来,之后的请求可以直接命中缓存。
- 优点 :对调用方来说,查询逻辑简单,直接查询缓存即可,无需关心数据加载逻辑。
- 缺点 :缓存服务器与数据库耦合度高,缓存系统复杂度增加;数据更新时需要考虑缓存更新策略,避免缓存污染。
写直达(Write-Through)
- 基本思想 :写数据时,数据同时写入缓存和数据库,确保缓存和数据库的数据一致性。
- 优点 :能确保缓存和数据库的数据一致性。
- 缺点 :写操作的性能会受到影响,因为需要同时写两个系统;缓存和数据库的写操作任何一个失败,都会导致数据不一致。
缓存更新策略
- 覆盖更新 :在缓存中更新数据,直接覆盖旧数据。
- 回写更新 :先在缓存中记录更新操作,待数据操作完成后再写回数据库,异步更新缓存。
- 写入数据库后删除缓存(延迟双删) :更新数据库后,先删除缓存,等待短暂时间后再次删除缓存,防止缓存污染。
缓存数据失效策略(TTL)
- 基本思想 :设置缓存数据的过期时间,当缓存数据超过设定的过期时间后,缓存数据失效。
- 优点 :简单易行,能有效避免缓存数据长期未更新导致的数据不一致。
- 缺点 :需要合理设置过期时间,过短的过期时间会导致缓存命中率低,过长的过期时间可能导致数据不及时。
延迟双删的技术方案,实际是采用缓存旁置(Cache-Aside)策略前提下,来提升数据一致性的技术方案。
延迟双删的背景
在高并发的业务场景下,缓存击穿、缓存雪崩等问题频发。此时,若按照传统的 “先更新数据库,再删除缓存” 或 “先删除缓存,再更新数据库” 的方式,很容易出现缓存与数据库数据不一致的情况。
例如,当一个请求先删除了缓存,再更新数据库,但在这两个操作之间,有另一个请求查询缓存,发现缓存不存在,就会从数据库读取旧数据并重新写入缓存,这样就导致了缓存数据与数据库更新后的数据不一致。
延迟双删的原理
延迟双删的核心思想是在更新数据库后,先删除一次缓存,然后等待一定时间,再次删除缓存,以确保缓存在数据库更新期间不会被旧数据污染。
具体操作步骤如下:
- 删除 Redis 缓存中的对应数据。
- 更新 数据库中的数据。
- 等待预设的短暂时间(例如 500 毫秒)。
- 再次删除 Redis 缓存中的对应数据。
通过这种方式,可以最大限度地保证缓存数据与数据库数据的一致性。
延迟双删的实现
以下是延迟双删的伪代码示例:
// 删除缓存
redis.delKey(key);
// 更新数据库
db.update(key, value);
// 等待一段时间,让数据库操作完成
Thread.sleep(500);
// 再次删除缓存
redis.delKey(key);
延迟双删的优缺点
优点
- 提高数据一致性 :通过两次删除缓存的操作,有效降低了缓存与数据库数据不一致的风险。
- 实现简单 :相较于其他复杂的数据一致解决方案,延迟双删的实现相对简单,易于理解和维护。
缺点
- 延时时间难以确定 :延时时间的设置需要根据具体业务场景进行调整,如果设置过短,可能无法有效避免数据不一致;如果设置过长,又会增加系统的延迟。
- 并发问题 :在高并发环境下,延迟双删可能无法完全避免数据不一致的问题。例如,在延时期间可能会有新的请求写入缓存,导致第二次删除缓存时将新数据删除。
- 实现复杂度增加 :需要额外的线程或定时任务来处理延时操作,这增加了系统的复杂度。
延迟双删的适用场景
延迟双删适用于对最终一致性要求较高但能容忍一定延迟的场景。例如,在一些对实时性要求不高的业务系统中,如电商的商品详情页缓存、新闻资讯类应用的内容缓存等,都可以考虑使用延迟双删策略来保证数据的一致性。
其他解决方案对比
- 先更新数据库,再删除缓存 :这种方式在读操作较少的场景下效果较好,但如果读操作频繁,仍然可能出现缓存与数据库数据不一致的情况。
- 先删除缓存,再更新数据库 :这种方式容易导致在缓存删除后、数据库更新前,其他请求将旧数据写入缓存的问题。
- 消息队列异步更新 :通过消息队列来解耦数据库和缓存的更新操作,也可以保证数据的最终一致性,但会增加系统的复杂度和延迟。
- Canal 监控 Binlog :利用 Canal 监控 的 Binlog 日志,实现准实时更新 Redis 缓存,保证数据一致性,但需要额外的运维成本和资源消耗。
总结
延迟双删策略是一种简单有效的缓存与数据库数据一致性解决方案。虽然它存在一些局限性,但在特定场景下仍然具有较高的实用价值。在实际应用中,我们可以根据业务需求和系统特点,灵活选择和组合不同的解决方案,以达到最佳的效果。
以上就是业务数据缓存延迟双删技术方案的全部内容。希望通过本文的介绍,能够帮助你更好地理解和应用这一技术方案。
注意,这是一个被面试玩坏了的问题,实际上,如果要保持强一致性,则必须采用锁机制,不可能避免的影响并发和系统的可用性。延迟双删技术方案相对简单,实用性强,但并不是完美的解决方案,最大程度上保证缓存与数据库中的数据一致,并且业务上可以接受最终一致性。
如果您在阅读本文时获得了帮助或受到了启发,希望您能够喜欢并收藏这篇文章,为它点赞~
请在评论区与我分享您的想法和心得,一起交流学习,不断进步,遇见更加优秀的自己!