缓存与数据库双写一致最佳解决方案分析

写在最前面

在大型互联网应用当中如果你的应用引入了缓存机制,那么有一个大前提就是你的业务场景上必须得接受数据的新鲜度上有可能会有一定时间的延迟。删除缓存失败是一个极小概率事件,且在不能保证所有操作100%成功的几率下,采用JOB补偿的机制是目前比较成熟的解决方案。
大并发量写请求的应用,不可能去实时写DB,基本都采用队列+消息异步写DB的机制,不然会有大量的并发问题


缓存机制介绍

如今利用缓存机制来提高查询效率已被广泛用在各大生产环境,查询数据的一般流程如下所示

使用缓存提高查询效率
  1. 如果数据在缓存里边有,则直接从缓存取数据返回。
  2. 如果缓存中没有想要的数据,则先去查询数据库,然后将数据库查出来的数据写到缓存中再返回

没有更新数据的情况下,数据库和缓存的数据是保持一致的;但是当要执行数据的更新操作的时候,数据库和缓存的数据就会出现不一致的情况

因此,为了解决数据不一致的问题,需要在更新数据库的时候,对缓存做一些额外的操作,有以下几种方案

  1. 先删缓存,再更新数据库
  2. 先更新数据库,再删缓存
  3. 缓存延时双删,更新前先删除缓存,然后更新数据,再延时删除缓存
  4. 监听MySQL binlog进行缓存更新

之所以缓存不采取更新操作而是直接删除是因为:高并发环境下,无论是先操作数据库还是后操作数据库而言,如果加上更新缓存,那就更加容易导致数据库与缓存数据不一致问题。(删除缓存直接且简单很多)

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

该方案在线程A进行数据更新操作,线程B进行查询操作时,有可能出现下面的情况导致数据不一致:

  1. 线程A删除缓存
  2. 线程B查询数据,发现缓存数据不存在
  3. 线程B查询数据库,得到旧值,写入缓存
  4. 线程A将新值更新到数据库

这样一来,缓存中的数据仍然是旧值

如果线程B执行的是更新操作,线程B查询得到的是旧值,A更新到数据库新值,然后B基于旧值计算写入了计算后的值,A的更新操作被抹去了,这种情况下属于更新数据事务原子性问题,需要用分布式锁来解决。

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

当缓存失效时,线程B原子性被破坏时会出现不一致问题:

  1. 缓存失效了
  2. 线程B从数据库读取旧值
  3. 线程A从数据库读取旧值
  4. 线程B将新值更新到数据库
  5. 线程B删除缓存
  6. 线程A将旧值写入缓存

这种情况概率很低,实际上数据库的写操作会比读操作慢得多,读操作必需在写操作前进入数据库操作,而又要晚于写操作更新缓存,这种情况下只需要线程B延时删除缓存就好。另外在数据库主从同步的情况下,延时删除还能防止数据更新还未从主数据库同步到从数据库的情况。

延时双删

延时双删即先删除缓存,然后更新数据,再延时n ms后删除缓存,这个我认为作用和更新数据库再删除缓存的策略几乎是等同的(欢迎讨论)

之所以设计为延时双删的目的在于当最后一次延时删除缓存失败的情况发生,至少一致性策略只会退化成先删缓存再更新数据的策略。

删除缓存失败这种事情个人认为在生产环境缓存高可用的情况下几乎不会出现,且这种情况如果发生了,不如考虑一下重试机制。

异步更新缓存(基于订阅binlog的同步机制)

通过异步更新缓存将缓存与数据库的一致性同步从业务中独立出来统一处理,保证数据一致性

整体技术思路:

  1. 读Redis:热数据基本都在Redis
  2. 写MySQL:增删改都是操作MySQL
  3. 更新Redis数据:订阅MySQ的数据操作记录binlog,来更新到Redis

数据操作分为两大部分:

  • 全量更新(将全部数据一次性写入redis)
  • 增量更新(实时更新)

这样一旦MySQL中产生了新的写入、更新、删除等操作,就可以把binlog相关的消息通过消息队列推送至Redis,Redis再根据binlog中的记录,对Redis进行更新。

这种同步机制类似于MySQL的主从备份机制,可以结合使用阿里的canal对MySQL的binlog进行订阅。

总结

综上所述,异步更新缓存、更新后延迟删与延迟双删都是不错的一致性解决方案,但除了异步更新缓存,其余两个方案都会对业务线的代码有侵入性。

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