不懂缓存一致性,易把代码写成Bug

缓存一致性-3.jpeg

哈喽哈喽大家猴,我是把代码写成bug的大头菜。公众号:大头菜技术(bigheadit)。原创不易,但欢迎转载。

本文主要分享一下关于缓存一致性问题和其解决方案。下面是本文的主要目录,大家可以挑着看。

目录
  1. 什么是缓存一致性
  2. 为什么要保证缓存一致性
  3. 如何保证缓存一致性
  4. 如何做到强一致性
  5. 总结

01 什么是缓存一致性

就是缓存和数据库的数据不一致导致的问题,缓存一致性分为强一致性和最终一致性。

  • 强一致性,这个比较损耗性能,比较复杂,加入之后,可能会比没加缓存更慢。

  • 最终一致性,是允许缓存数据和数据库数据一段时间内不一致,但数据最终会保持一致。这个性能较高。

02 为什么要保证缓存一致性

因为业务中存在一些写操作导致的,是要先写缓存,还是先写数据库。二者顺序的不同会导致不同的问题。

单纯的读操作,是不会导致缓存一致性问题的,因为读是幂等的哈。读无数次都是不会变的,因此就不存在读操作引起缓存一致性问题。

因此导致缓存不一致的就是写操作了。写操作是导致缓存不一致的原因。但这不是要保证缓存一致性的理由,
归根结底都是业务需要,如果业务需求允许缓存和数据库的不一致,那就不需要保证缓存一致性了。

03 如何保证缓存一致性(解决方案)

相信很多人都知道经典方案:cache aside pattern。

首先明确的是,读不会产生缓存一致性问题。是写操作,才会产生缓存一致性问题。


image

第一点,失效:请求过来时,先访问缓存,缓存不存在,再去访问数据库,更新缓存。

第二点,读:请求过来时,缓存中有数据,直接返回数据。

第三点,写:先更新数据库,后删除缓存。

关键在第三点,前提,数据库肯定是更新的。剩下的问题就是:是要更新缓存?还是要删除缓存?是先对数据库操作?还是先对缓存操作?

俩俩组合有4种可能性:

  • 先更新缓存,后更新数据库

  • 先更新数据库,后更新缓存

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

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

1.先更新缓存,后更新数据库

首先我们要明白,更新数据库或者更新缓存,都面临着更新失败的风险。但在互联网高并发的环境中和根据墨菲定律,这个事是一定会发生的。

  1. 先更新缓存,成功了

  2. 后更新数据库,失败了,当然你会说重试,好,那我就重试N次,但如果数据库彻底挂了,恢复不了了,重试也没用

导致问题:数据丢失,数据库里面的数据还是老数据

2.先更新数据库,后更新缓存

假设有两个请求,A请求是更新,B请求是更新,A先B后,但二者间隔很短

  1. 线程A更新了数据库

  2. 线程B更新了数据库

  3. 线程B更新了缓存

  4. 线程A更新了缓存

导致问题:缓存中是旧数据,数据库中是新数据,这就不一致了。还有就是更新后的缓存,真的会被再读取吗?如果缓存数据不再被读取,那就白白操作了一次缓存更新操作。并且还占用内存空间。

根据这个例子,可以看出,更新缓存是不可取的,那就直接删除缓存吧。接着看

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

假设有两个请求,A请求是更新,B请求是读,可能出现的问题

  1. 线程A删除缓存

  2. 线程B查询不到缓存,直接去数据库查旧值

  3. 线程A将新值写入数据库

  4. 线程B更新缓存

导致问题:缓存中的是旧值,数据库中的是新值,二者不一致。进一步,如果数据库存在读写分离,那么缓存和数据库数据不一致的情况进一步加剧。

  1. 线程A删除缓存

  2. 线程A将新值写入主数据库,但未同步数据到从数据库

  3. 线程B查询不到缓存,直接去从数据库查,查到旧值

  4. 线程B更新缓存

  5. 新数据同步到从数据库

导致问题:缓存是旧值,数据库是新值,二者数据不一致

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

假设有两个请求,A请求是读,B请求是更新,可能会出现的问题

  1. 缓存刚好失效

  2. 线程A查数据库,得到旧值

  3. 线程B更新数据库

  4. 线程B删除缓存

  5. 线程A更新缓存

导致问题:缓存是旧值,数据库是新值,二者不一致。但这种情况的可能性相对来说比较小,因为需要缓存刚好失效,并且此时有一个线程去读,且刚好又有一个写的线程。而且写的线程理论上是比读的线程慢的,因为写的线程,需要加锁。而查询不用加锁,不包括复杂的查询。

在数据库读写分离的情况下,这种情况会更加明显:

  1. 线程B更新主库

  2. 线程B删除缓存

  3. 线程A查询缓存,没有命中,查询从库得到旧值

  4. 数据同步到从库

  5. 线程A更新缓存

导致问题:缓存数据和数据库数据不一致

如果考虑更新数据库或者更新缓存失败的话,那么更新数据库失败的话,其实数据库和缓存都是旧数据,因此不存在数据不一致的情况。

如果更新缓存失败,那么有过期时间来保证最终一致性。如果非要较真的话,可以加入重试机制。

重试机制可以用线程池,也可以用MQ。MQ更加可靠。可以直接订阅MySQL的binlog,来触发缓存的删除。当然,其实MQ也会挂。但是MQ和缓存都一起挂的几率,应该很小吧。

综上所述四种情况

虽然每种方案都有各自的问题,但出现几率较小的是先更新数据库,后删除缓存方案。为什么先更新数据库?因为数据库的持久化能力比缓存好。上述四种情况,还可能出现缓存并发,缓存穿透,缓存雪崩的问题。这些问题,这里就不讨论了。感兴趣的话,自己去看我的相关文章。

04 如何做到强一致性

方案一:分布式事务

可以用分布式事务,分布式事务,具体的实现有2PC、3PC、消息队列等。如果要采用这个方案,架构设计中要引入很多容错、回退、兜底的措施。业务代码就增加复杂性了。还有人说用分布式一致性算法paxos和raft,这就更复杂了。

方案二:分布式读写锁

首先,我们回到先更新数据库,后删除缓存 ,要明白什么时候会出现脏数据?

出现脏数据:更新数据库后,删除缓存之前。这时候二者数据是不一致的。

如果实现更新数据库时,所有读请求都被阻塞。这就解决了数据不一致的问题,这其实是串行化思路。但后果,当然是性能下滑。

总结

其实选择数据的强一致性和数据的最终一致性。得看具体需求,我好像说了一句废话。但是放弃强一致性,意味着我们系统的性能得到一定程度的提升。相反,如果我们追求强一致性,那就会巨复杂,而且可能得不偿失,可能性能比不加缓存时还低。缓存这东西,想要用得好,就需要好好琢磨,比如过期时间的设置,持久化,故障恢复,空间和时间的平衡,一致性的选择,这些都要好好斟酌,没有最好的方案,只有合适的方案。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,165评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,720评论 1 298
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,849评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,245评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,596评论 3 288
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,747评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,977评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,708评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,448评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,657评论 2 249
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,141评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,493评论 3 258
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,153评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,108评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,890评论 0 198
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,799评论 2 277
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,685评论 2 272

推荐阅读更多精彩内容