【分布式系统-缓存系统架构设计疑难点系列】mysql、redis数据一致性怎么解决?

1、需求背景

     在高并发的业务场景下,数据库大多数情况都是用户并发访问最薄弱的环节。所以,就需要使用redis做一个缓冲操作,让请求先访问到redis,而不是直接访问MySQL等数据库。读取缓存步骤一般没有什么问题,但是一旦涉及到数据更新:数据库和缓存更新,就容易出现缓存(Redis)和数据库(MySQL)间的数据一致性问题

      一般的项目大家都是不会怎么在意数据库和缓存的数据一致性的,都是一个api接口先查询redis,有则返回,没有则表示数据过期了,去数据库取,然后存入redis。也即是直接通过设置缓存数据的有效时间来做的简单最终一致性。

       上面的针对大量读请求,而且能接收脏读,倒没什么问题(其实也有,如果并发过高,可能会出现缓存穿透问题,但要是项目确实需要处理数据一致性呢?

       也就是要保证数据库的数据和缓存中的数据是一致的,一般你可能看到过或者想到的是两种:先删除缓存再更新数据库;先更新数据库再删除缓存。

为什么会有顺序差异呢(删除缓存和更新数据库)?

        因为并发会引入“间断性”、“不可封闭性”、“不可再现性”问题(也即失去了“顺序性”)。当然你如果是把“加锁”处理(即加锁删除缓存和更新数据库),那么这两个操作的步骤顺序无所谓。但加锁就意味着并发不高(自损),所以一般都不会这么做。

那这两个步骤顺序不一致,我们选择哪一种呢?

2、思考

你可能稍加思索,会说“先删除缓存,再更新数据库”

1,删除缓存;2,更新数据库。

     假设1成功2失败了,则缓存没数据了,数据库是旧的。那么此时来了一个读请求,读缓存miss(缓存已被删了),则去读数据库读到旧数据,然后再更新缓存(旧数据),数据一致(缓存和数据库中都是旧数据)。

如果是先更新数据库再删除缓存

1,更新数据库;2,删除缓存。

       假设1成功2失败了,则数据库是新数据,缓存是旧数据。那么此时来了一个读请求,读缓存命中(读到旧数据),不用再去读数据库了,那么读到的是旧数据,而且数据不一致(缓存是旧数据,数据库是新数据)。

那这么分析下来,是该选择“先删除缓存,再更新数据库”。

因为只是会一次缓存miss而已。

      但如果是读请求并发非常高呢?而且缓存本来就是针对读多写少的场景(如果写多,那缓存就没啥意义了)。我们看下下面场景:当请求A写数据时,此时读请求并发非常高。

1,请求A删除缓存

2,请求B读数据,读缓存miss(因为请求A已删除缓存)

3,请求B到数据库读取数据(此时其实读取到的是旧数据)

4,请求B更新缓存(将数据库的旧数据读取放入到缓存)

5,请求A将新数据写入到数据库

      这下数据不一致了(缓存中为旧数据,数据库为新数据),如果这个缓存数据没有过期时间的话,会一直不一致状态(当然一般不会这么神操作)。

       那我们再换成“先更新数据库,再删除缓存”,看下面场景:当请求C写数据时,此时读请求并发非常高,而且刚好该数据的缓存过期了(主要是为了模拟出读请求缓存miss)。

1,缓存数据刚好过期

2,请求D读数据,读缓存miss(上面缓存数据刚好过期或者已过期)

3,请求D从数据库读取数据(读取到旧数据)

4,请求C向数据库写数据(写入新数据)

5,请求C删除缓存

6,请求D更新缓存(将旧数据放入缓存)

      这下数据不一致了(缓存为旧数据,数据库为新数据),但注意一个问题,出现这种场景的话,步骤4一定要比步骤3更快才会出现步骤5比步骤6先执行。也即是“请求C向数据库写数据”要比“请求D从数据库读数据”快才行,也就是说更新数据库要比读数据库数据快,你觉得这概率大吗?mysql读数据不加锁(mvcc方式快照读),写数据加锁(mdl锁,行锁,gap锁,next锁),为的就是提升读写并发,读一般肯定比写快(不然为嘛搞读写分离这些事)。那么也就是说上面的场景出现的概率非常低。而“先删除缓存,再更新数据库”在读高并发下出现不一致场景的概率会非常的高。

所以,当读多写少(读高并发)时,mysql和redis数据一致性解决采用“先更新数据库,再删除缓存”会合适一点。

3、改进

       问题又来了,我们采用“先更新数据库,再删除缓存”还是会出现不一致性问题,而且也会出现脏读(有请求在更新数据库删除缓存期间会拿到旧数据【可能从缓存中拿到可能从数据库拿到】)。

      那怎么办?而且没有绝对的数据一致性解决方案吗?

      绝对的数据一致性,没法,分布式cap,本身带缓存就是ap,但我们还是可以优化的。

双删缓存

1,先更新数据库

2,删除缓存

3,隔x秒后再次删除缓存

      恩?干嘛x秒后又删除一次缓存?这是尽量减小有请求读取到旧数据的影响,那具体多少秒?这个看业务场景,根据实际耗时时间来,也就是从更新数据库开始到X时间可能会有请求读到旧数据。

还有其他方案吗?

有啊,订阅数据库binlog结合mq消息队列处理。

     读取binlog后分析 ,利用消息队列,推送更新各台的redis缓存数据。这样一旦MySQL中产生了新的写入、更新、删除等操作,就可以把binlog相关的消息推送至Redis,Redis再根据binlog中的记录,对Redis进行更新。

      其实这种机制,很类似MySQL的主从备份机制,因为MySQL的主备也是通过binlog来实现的数据一致性。

       这里可以结合使用canal(阿里的一款开源框架),通过该框架可以对MySQL的binlog进行订阅,而canal正是模仿了mysql的slave数据库的备份请求,使得Redis的数据更新达到了相同的效果。

当然,这里的消息推送工具你也可以采用别的第三方:kafka、rabbitMQ等来实现推送更新Redis。

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

推荐阅读更多精彩内容