【高频】如何保证缓存和数据库一致

简介: 【高频】如何保证缓存和数据库一致
  1. 如何确保缓存和数据库的数据一致性?
  2. 怎样解决缓存与数据库之间的数据同步问题?
  3. 如何处理缓存数据和数据库数据不一致的情况?

回答:


一、什么是数据一致性

缓存与数据库的数据一致性指的是,缓存中存储的数据与数据库中存储的数据需保持一致。

即缓存中存有数据,缓存的数据值 = 数据库中的值;缓存中没有该数据,数据库中的值 = 最新值。数据一致性主要包含以下两种情况:


  • 缓存中有数据,那么缓存中的值需要和数据库中值相同。
  • 缓存中本身没有数据,那么,数据库中的值必须是最新值。

如果存在以下情况,则说明存在不一致性情况:

  • 缓存中有数据,但是缓存中的数据与数据库中的数据不一致。
  • 缓存或者数据库中存在旧的数据,导致单个线程读到的数据是旧的。


二、数据不一致的原因

缓存(Redis)和 数据库(MySQL)是两套系统,所以任何一方的数据改写,都需要另一方的协同来保证。但这种协同可能存在一定的失败率,如下:


  • 数据库更新出错:在更新数据库时发生错误,导致缓存中的数据与数据库中的数据不一致。
  • 缓存刷新机制错误:一些缓存系统可能存在刷新机制的问题,导致缓存中的数据没有及时更新,从而与数据库数据出现不一致的情况。
  • 并发请求:当有多个请求同时进行操作时,由于缓存、数据库操作的顺序和时机不同,可能造成不一致的情况。

数据一致性策略不当:在实现缓存和数据库的数据一致性策略时,如果选择不当的数据一致性策略,可能会导致数据不一致的情况。

为了保持缓存和数据库的数据一致性,需要采取适当的一致性策略(如引入 2PC 或 Paxos 等分布式一致性协议,或者分布式锁),并及时处理数据库更新和缓存刷新中的错误。同时,在实现并发请求时,需要合理控制操作的顺序和时机,以避免不一致的情况发生。


三、缓存执行的策略

  • Cache-Aside(缓存旁路):这是最广泛使用的缓存策略之一。在读取数据时,先从缓存中读取数据,如果缓存中没有数据,则从数据库中读取数据,并将读取到的数据存储到缓存中。在写入数据时,先写入数据库,然后更新缓存中的数据。这个策略可以极大地提高读取性能,但是可能会降低写入性能。
  • Read-Through(读穿透):这个策略类似于Cache-Aside,但是它会自动从缓存中读取数据,而不需要先从数据库中读取数据。如果缓存中没有数据,则自动从数据库中读取数据,并将读取到的数据存储到缓存中。这个策略可以提高读取性能,但是可能会增加数据库的负载。
  • Write-Through(写贯穿):这个策略类似于Cache-Aside,但是在写入数据时,它会直接写入缓存和数据库,而不是先写入数据库再更新缓存。这个策略可以提高写入性能,但是可能会降低缓存的利用率。
  • Write-Behind(写后置):这个策略类似于Write-Through,但是在写入数据时,它会异步地更新缓存和数据库,而不是立即更新。这个策略可以提高写入性能,但是可能会增加数据库的负载和缓存的不一致性。
  • Update-In-Place(原地更新):这种策略在缓存中直接更新数据,而不是先删除旧数据再添加新数据。这样可以减少缓存的冲突,但是可能会增加缓存的大小和内存消耗。
  • Write-Back(回写):这种策略在写入数据时,先更新缓存,然后再异步地更新数据库。这样可以提高写入性能,但是可能会增加缓存的不一致性和数据库的负载。
  • Partitioning(分区):这种策略将缓存分成多个分区,不同的数据分区采用不同的缓存策略,以适应不同的访问模式和负载情况。


四、一致性解决方案

1.延迟双删策略主要是是应对先删除缓存,再更新数据库的场景。

我们知道在这种场景中,很容易因为删除数据库太慢导致重新获取的缓存依旧读是数据库旧值,读完旧值之后,数据库才更新完毕。这时候缓存的数据就跟数据库不一致了。参考 3.3 节。

所以这边多加了一个步骤,就是在数据库更新完成之后,再删除一次缓存。所以步骤如下:


  1. 删除缓存
  2. 缓存删除完成之后,更新数据库
  3. 数据库更新完成之后,休眠 n ms,二次删除缓存

这时候唯一存在的一个问题就是,在(更新据库 + 休眠 n ms) 这个时间窗口中,依旧能读取到旧值,而这个短暂时间控制的好的话,是可以接受的。


2.无论是先更新数据库,再删除缓存;还是先删除缓存,在更新数据库。

保持事务性都是一种方案,如果删除缓存失败,则数据库更新会被回滚;如果更新数据库失败,则缓存也不会被删除。这个需要一致性策略接入。不过无论怎么做,这个都会在一定程度上影响执行完成的性能


3.如果双删还是失败呢,那可咋整,还是会产生缓存和数据库数据不一致的现象。

一般的做法是做一层兜底,比如记录日志,人工来处理;或者通过MQ来发布消息,然后开发一个独立的服务来订阅,专门用于数据清理,这就将操作异步化了


4.数据库有类似Binlog之类的东西,记录每次数据的更新。所以我们有另外一种方案,就是把同步缓存的操作交给独立的能力中,从应用层解耦。

图中我们可以看到步骤如下:


更新数据库数据

  • 数据库更新完成之后会把变更记录在 binlog 中
  • 使用 canal 订阅 binlog 日志获取待删除的key(或者更完整的数据对象)
  • 消费者(缓存删除服务)获取到 canal 数据,获得待删除的key,并删除缓存


相关文章
|
11天前
|
消息中间件 canal 缓存
项目实战:一步步实现高效缓存与数据库的数据一致性方案
Hello,大家好!我是热爱分享技术的小米。今天探讨在个人项目中如何保证数据一致性,尤其是在缓存与数据库同步时面临的挑战。文中介绍了常见的CacheAside模式,以及结合消息队列和请求串行化的方法,确保数据一致性。通过不同方案的分析,希望能给大家带来启发。如果你对这些技术感兴趣,欢迎关注我的微信公众号“软件求生”,获取更多技术干货!
46 6
项目实战:一步步实现高效缓存与数据库的数据一致性方案
|
19天前
|
canal 缓存 NoSQL
Redis缓存与数据库如何保证一致性?同步删除+延时双删+异步监听+多重保障方案
根据对一致性的要求程度,提出多种解决方案:同步删除、同步删除+可靠消息、延时双删、异步监听+可靠消息、多重保障方案
Redis缓存与数据库如何保证一致性?同步删除+延时双删+异步监听+多重保障方案
|
2月前
|
消息中间件 缓存 监控
如何保证缓存和数据库的一致性?
保证缓存和数据库的一致性的做法
|
3月前
|
缓存 NoSQL Java
Redis 缓存与数据库数据不一致问题
Redis 缓存与数据库数据不一致问题
73 3
|
3月前
|
存储 缓存 关系型数据库
MySQL数据库缓存query_cache 19
【7月更文挑战第19天】MySQL数据库缓存query_cache
170 73
|
3天前
|
消息中间件 缓存 NoSQL
15)如何保证缓存和数据库之间的数据一致性
15)如何保证缓存和数据库之间的数据一致性
10 0
|
2月前
|
缓存 NoSQL Redis
一天五道Java面试题----第九天(简述MySQL中索引类型对数据库的性能的影响--------->缓存雪崩、缓存穿透、缓存击穿)
这篇文章是关于Java面试中可能会遇到的五个问题,包括MySQL索引类型及其对数据库性能的影响、Redis的RDB和AOF持久化机制、Redis的过期键删除策略、Redis的单线程模型为何高效,以及缓存雪崩、缓存穿透和缓存击穿的概念及其解决方案。
|
2月前
|
存储 缓存 关系型数据库
Django后端架构开发:缓存机制,接口缓存、文件缓存、数据库缓存与Memcached缓存
Django后端架构开发:缓存机制,接口缓存、文件缓存、数据库缓存与Memcached缓存
35 0
|
3月前
|
缓存 NoSQL 数据库
Redis问题之在高并发场景下,保证Redis缓存和数据库的一致性如何解决
Redis问题之在高并发场景下,保证Redis缓存和数据库的一致性如何解决
100 3
|
3月前
|
canal 消息中间件 缓存
面试题:如何解决缓存和数据库的一致性问题?
面试题:如何解决缓存和数据库的一致性问题?
62 1
下一篇
无影云桌面