Redis(3):缓存与数据库一致性

1 设计缓存

缓存利用率(内存置换策略)缓存一致性(缓存与数据库一致性)缓存过期时间(过期键策略)

2 保证缓存和数据库数据的一致性

2.1 可能的解决方案

方式 存在问题 解决方法
先更新缓存,再更新数据库 更新缓存成功,更新数据库异常,导致缓存与数据库不一致 不考虑
先更新数据库,再更新缓存 更新数据库正常,更新缓存失败,数据不一致,缓存中数据一直存在
先删除缓存,后更新数据库 删除缓存后,还未更新数据库,并发下另一读请求将数据读入缓存 延迟双删
先更新数据库,后删除缓存 1. 缓存刚好失效
2. 请求A查询数据库,得到一个旧值
3. 请求B将新值写入数据库
4. 请求B删除缓存
5. 请求A将查到的旧值写入缓存
异步延时双删
::: level1

先更新数据库,后删除缓存

:::
image.png

保证两个操作执行成功
1. 重试机制

引入消息队列,将第二个操作(删除缓存)要操作的数据加入到消息队列,由消费者来操作数据。

  • 如果应用删除缓存失败,可以从消息队列中重新读取数据,然后再次删除缓存,这个就是重试机制。当然,如果重试超过的一定次数,还是没有成功,我们就需要向业务层发送报错信息了。

  • 如果删除缓存成功,就要把数据从消息队列中移除,避免重复操作,否则就继续重试。

2. 订阅 MySQL binlog,再操作缓存。

先更新数据库,再删缓存」的策略的第一步是更新数据库,那么更新数据库成功,就会产生一条变更日志,记录在 binlog 里。于是我们就可以通过订阅 binlog 日志,拿到具体要操作的数据,然后再执行缓存删除。

3. 缓存失效时间变短

缓存和数据库一致性问题,看这篇就够了 (qq.com)
数据库和缓存如何保证一致性? | 小林coding (xiaolincoding.com)

聊聊如何保证Redis和Mysql中数据双写一致性面试官常拷打:如何下保证MySQL数据库与Redis缓存数据一致性? (qq.com)

3 数据不一致情况

  • 先删缓存,再更新数据库

  • 主从同步,读写分离的情况下,读从库而产生脏数据

4 缓存读写策略

image.png

4.1 Cache Aside Pattern(旁路缓存模式)

Cache Aside(旁路缓存)策略是最常用的,应用程序直接与「数据库、缓存」交互,并负责对缓存的维护,该策略又可以细分为「读策略」和「写策略」。Cache Aside 策略适合读多写少的场景,不适合写多的场景,因为当写入比较频繁时,缓存中的数据会被频繁地清理,这样会对缓存的命中率有一些影响。

写策略的步骤:

  • 先更新数据库中的数据,再删除缓存中的数据。

读策略的步骤:

  • 如果读取的数据命中了缓存,则直接返回数据;

  • 如果读取的数据没有命中缓存,则从数据库中读取数据,然后将数据写入到缓存,并且返回给用户。

缺陷 1:首次请求数据一定不在 cache 的问题
解决办法:可以将热点数据可以提前放入 cache 中。

缺陷 2:写操作比较频繁的话导致 cache 中的数据会被频繁被删除,这样会影响缓存命中率 。
解决办法:

  • 数据库和缓存数据强一致场景:更新 db 的时候同样更新 cache,不过我们需要加一个锁/分布式锁来保证更新 cache 的时候不存在线程安全问题。

  • 可以短暂地允许数据库和缓存数据不一致的场景:更新 db 的时候同样更新 cache,但是给缓存加一个比较短的过期时间,这样的话就可以保证即使数据不一致的话影响也比较小。
    image.png

4.2 Read/Write Through Pattern(读写穿透)

Read/Write Through(读穿 / 写穿)策略原则是应用程序只和缓存交互,不再和数据库交互,而是由缓存和数据库交互,相当于更新数据库的操作由缓存自己代理了。

Read/Write Through Pattern 中服务端把 cache 视为主要数据存储,从中读取数据并将数据写入其中。cache 服务负责将此数据读取和写入 db,从而减轻了应用程序的职责。

image.png

1、Read Through 策略

先查询缓存中数据是否存在,如果存在则直接返回如果不存在,则由缓存组件负责从数据库查询数据,并将结果写入到缓存组件,最后缓存组件将数据返回给应用。

2、Write Through 策略

当有数据更新的时候,先查询要写入的数据在缓存中是否已经存在:

  • 如果缓存中数据已经存在,则更新缓存中的数据,并且由缓存组件同步更新到数据库中,然后缓存组件告知应用程序更新完成。

  • 如果缓存中数据不存在,直接更新数据库,然后返回;

4.3 Write Back(写回策略)

Write Back(写回)策略,即写入时复制(Copy On Write),在更新数据的时候,只更新缓存,同时将缓存数据设置为脏的,然后立马返回,并不会更新数据库。对于数据库的更新,会通过批量异步更新的方式进行。

实际上,Write Back(写回)策略也不能应用到我们常用的数据库和缓存的场景中,因为 Redis 并没有异步更新数据库的功能。

Write Back 是计算机体系结构中的设计,比如 CPU 的缓存、操作系统中文件系统的缓存都采用了 Write Back(写回)策略。

Write Back 策略特别适合写多的场景,因为发生写操作的时候, 只需要更新缓存,就立马返回了。比如,写文件的时候,实际上是写入到文件系统的缓存就返回了,并不会写磁盘。

4.4 Write Behind Pattern(异步缓存写入)

Write Behind Pattern 和 Read/Write Through Pattern 很相似,两者都是由 cache 服务来负责 cache 和 db 的读写。

Read/Write Through 是同步更新 cache 和 db,而 Write Behind 则是只更新缓存,不直接更新 db,而是改为异步批量的方式来更新 db。

旁路缓存模式(Cache-Aside Pattern)如何保证一致性的问题-CSDN博客