Redis缓存与数据库一致性解决方案

你可能会说这题我会,很简单嘛。

  • 读请求:先查缓存,查不到再查数据库,然后将数据保存到缓存中
  • 写请求:先删除缓存,在更新数据库,在通过后续的读请求把数据保存到缓存中。

乍一听,很有道理的样子,然而这是有问题的。试想这样一种场景,有两个并发操作,一个是更新操作,另一个是查询操作。当更新操作删除缓存后,查询操作开始了,由于此时Redis中无对应数据了,查询操作会将旧数据取出来放到缓存中去,然后更新操作继续进行更新了数据库。此时,在缓存中的数据将是旧数据,导致缓存中的数据是脏的,而且还一直这样脏下去了。
在不同的业务场景下,实际选用的缓存的读写策略也是不同的。为方便讨论,这里假定更新数据库和更新缓存都是成功。

Cache Aside Pattern 旁路缓存

最常用的模式,其具体逻辑:

  • 失效:先查缓存,查不到再查数据库,然后将数据保存到缓存中
  • 命中:从缓存中取数据,命中后直接返回
  • 更新:先更新数据库,成功后在删除缓存
    Cache Aside Pattern 旁路缓存
    注意,这里我们的更新是先更新数据库,成功后在删除缓存。此时可以解决文章之前提到的那个问题。例如
    一个查询操作,一个更新操作。更新操作首先更新数据库,此时缓存仍然是有效的,此时查询操作取的是旧数据。然后更新操作把缓存删了,后续的查询操作会先查数据库,在将数据保存到缓存中,就不会产生文章开头提到的那个问题,即后续的查询操作取得一直都是旧数据。
    这是标准的design pattern,包括Facebook的论文《Scaling Memcache at Facebook》也使用了这个策略。为什么不是写完数据库后更新缓存?你可以看一下Quora上的这个问答《Why does Facebook use delete to remove the key-value pair in Memcached instead of updating the Memcached during write request to the backend?》,主要是怕两个并发的写操作导致脏数据。
    那么,是不是Cache Aside这个就不会有并发问题了?不是的,比如,一个是读操作,但是没有命中缓存,然后就到数据库中取数据,此时来了一个写操作,写完数据库后,让缓存失效,然后,之前的那个读操作再把老的数据放进去,所以,会造成脏数据。
    但这个场景虽然在理论上会出现,不过,实际上出现的概率可能是非常低的,因为这个条件比较苛刻:需要发生在读缓存时缓存失效,而且并发着有一个写操作。而实际上数据库的写操作会比读操作慢得多,而且还要锁表,而读操作必需在写操作前进入数据库操作,而又要晚于写操作更新缓存,所有的这些条件都具备的概率基本并不大。
    所以,这也就是Quora上的那个答案里说的,要么通过2PC或是Paxos协议保证一致性,要么就是拼命的降低并发时脏数据的概率,而Facebook使用了这个降低概率的玩法,因为2PC太慢,而Paxos太复杂。当然,最好还是为缓存设置上过期时间。

Read/Write Through Pattern

上面的Cache Aside方法需要我们的代码维护两个数据存储:缓存和数据库,相对而言比较麻烦。
这里提出另一种方法:把更新数据库的操作由缓存自己代理。此时,对应用层而言就方便多了。可以理解为,应用认为后端就是一个单一的存储,而存储自己维护自己的Cache。

Read Through

Read Through 套路就是在查询操作中更新缓存,也就是说,当缓存失效的时候(过期或LRU换出):

  • Cache Aside是由调用方负责把数据加载入缓存。
  • Read Through则用缓存服务自己来加载,从而对应用方是透明的。

Write Through

Write Through 套路和Read Through相仿,不过是在更新数据时发生。当有数据更新的时候

  • 如果没有命中缓存,直接更新数据库,然后返回。
  • 如果命中了缓存,则更新缓存,然后再由Cache自己更新数据库(这是一个同步操作)

下图的Memory可以理解为数据库
Read/Write Through Pattern

Write Behind Caching 异步写回

又叫 Write Back,其核心思想就是在更新数据的时候,只更新缓存,不更新数据库,而我们的缓存会异步地批量更新数据库。
好处

  • 让数据的I/O操作飞快无比(因为直接操作内存嘛 )
  • 因为异步,write backg还可以合并对同一个数据的多次操作,所以性能的提高是相当可观的。

但是他也是有一定的缺点的

  • 数据不是强一致性的,而且可能会丢失(我们知道Unix/Linux非正常关机会导致数据丢失,就是因为这个事)。
  • Write Back实现逻辑比较复杂,因为他需要track有哪数据是被更新了的,需要刷到持久层上。操作系统的write back会在仅当这个cache需要失效的时候,才会被真正持久起来,比如,内存不够了,或是进程退出了等情况,这又叫lazy write。
    Write Behind Caching 异步写回

参考文献:

  • https://coolshell.cn/articles/17416.html
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值