前言 此篇章为分析如何将redis的缓存与mysql数据同步的解决方案,本人参照各路大神的解决方案汇聚而成,难免会有错误的地方,肯定各路大神评论区无情鞭挞~~ 你只要用缓存,就可能会涉及到缓存与数据库双存储双写,你只要是双写,就一定会有数据一致性的问题,那么你如何解决一致性问题? 我想,已经有小伙伴有了好的方案了,为什么我们不能直接将其中读请求与写请求串行化,全部整到一个队列中去消费,不就一定不会出现不一致的情况了吗?确实,但是这样做会严重降低系统的高可用型,你想想你的程序每秒能跑多少,你放到队列中又能跑多少呢 目前,已知三种解决方案,让我们来好好看看这其中的区别 首先,当我们一个改数据的请求进来,我们先更新数据库的值,然后再把缓存中的值去更新,当我们下一次请求进来的时候保证数据是最新值 这其中有问题吗? 试想如上情况,每秒一万次改请求,那我数据库会一直更新,而且当我们数据库更新的时候也会更新缓存值,那我其实只有一次读请求,那我更新这一万次缓存是不是没意义? 而且会造成我们系统很大开销,而缓存也没被访问几次 删除缓存如何? 试想一下,要是我们直接每次更新数据库的时候,不去更新缓存,而是直接删除缓存,是不是情况就简单很多,每秒一万次请求,改数据库然后删除缓存,那我们的缓存并没有持续更新,也不存在大开销,并且下次我们查请求进来,也只不过多了一次生成缓存的操作 这点其实用了懒加载的思想,我们只有用到的时候采取生成,不用的时候就一直不用,是不是很好? 下面我们来讨论这种方案 唉,既然上面这样分析了,其实还是又出现了新的问题,那我们是先删除缓存还是先更新数据库呢? 如上,我们来分析一下,当请求A进行写操作,刚刚删除缓存还没来得及更新数据库,突然cpu任务调度停了,B请求查询后没缓存,就去数据库查询旧值,查到后缓存这个旧值,那我们这时A请求又进行了,去把数据库的值更新了,这时候会出现什么情况?缓存是旧值,但是数据库是新值,出现数据不一致,而且每次有新请求进来,在缓存没失效的时候,永远查的都是旧值. 这样会一直出现脏数据,那我们怎么解决呢? 延时双删策略 例如在我们A请求进行写操作的时候,第一次不是删除了缓存吗,但容易被B请求更新成脏数据,那我们就等一段时间(休眠一段时间)再进行删除缓存,是不是可以把之前B请求的脏数据删除掉,下次新请求进来查询的时候查不到缓存,会去数据库缓存最新值 但是,又抛出一些问题,如何确定这个睡眠时间是多少呢?根据自己的业务可以调整休眠时间,也有不确定性,其次要是你的数据库是读写分离架构会出现如下问题 这样也会出现数据不一致的情况,解决的策略还是延时双删策略,适当将休眠时间延长,在主从同步后进行双删,于是这样加的时间值以及牺牲系统吞吐量来解决是不可取的,所以我们开另外一个线程进行异步删除,不用再休眠系统 但是问题最终解决了吗? 比如在上面延时双删的情况下,我们第二次删除失败,那前面一切不都是白做了?瓶颈口就在这里,只要第二次删除缓存失败,一切都白给了~~ 老外提出了一个缓存更新套路,名为 Cache-Aside pattern 。 另外,知名社交网站facebook也在论文《Scaling Memcache at Facebook》中提出,他们用的也是先更新数据库,再删缓存的策略。 更新:先把数据存到数据库中,成功后,再让缓存失效。 首先,我们再来分析一下这种模式会出现什么问题 也会出现缓存与数据库不一致的情况,但其实这种情况出现的概率很低 首先,这种情况出现在读请求穿插写请求中,且写请求用时比读请求长,从上面情况来分析不难得出.其次数据库写操作时长是远远大于读操作时长的,这也是为什么要数据库读写分离的原因,所以出现上述条件是非常苛刻的,再来说说为什么先删除缓存再写数据库这种情况的意外发生概率高,主要是因为**写操作中穿插读操作,而读操作时长非常短,**极易造成数据不一致 毕竟我们是优秀的程序员嘛,但其实如果要是真发生上述情况的话 开玩笑~ 那我们还是采用延时双删策略,保证读请求后删除缓存即可 那我们就是会出现删除缓存失败的时候嘛,那你怎么解决呢? 这里借鉴孤独烟大神的做法,只能怪自己太菜了唉~ 方案一 然而,该方案有一个缺点,对业务线代码造成大量的侵入。于是有了方案二,在方案二中,启动一个订阅程序去订阅数据库的binlog,获得需要操作的数据。在应用程序中,另起一段程序,获得这个订阅程序传来的信息,进行删除缓存操作。 方案二 借鉴大神操作 附上大神博客缓存的双写一致性
一. 何谓双写一致性
二. 解决方案
2.1 先更新数据库,再更新缓存
2.1.1 问题1 每秒一万次改请求,一次读请求?
那不如我们…2.2 先删除缓存,再更新数据库
我们设想有如下情景
如果我们删除失败怎么办?2.3 先更新数据库,再删除缓存
2.4 最终问题
流程如下所示
(1)更新数据库数据;
(2)缓存因为种种问题删除失败
(3)将需要删除的key发送至消息队列
(4)自己消费消息,获得需要删除的key
(5)继续重试删除操作,直到成功
流程如下图所示:
(1)更新数据库数据
(2)数据库会将操作信息写入binlog日志当中
(3)订阅程序提取出所需要的数据以及key
(4)另起一段非业务代码,获得该信息
(5)尝试删除缓存操作,发现删除失败
(6)将这些信息发送至消息队列
(7)重新从消息队列中获得该数据,重试操作。制作不易,转载都请标注 ~ 你看不懂,你也打不着我啊
本网页所有视频内容由 imoviebox边看边下-网页视频下载, iurlBox网页地址收藏管理器 下载并得到。
ImovieBox网页视频下载器 下载地址: ImovieBox网页视频下载器-最新版本下载
本文章由: imapbox邮箱云存储,邮箱网盘,ImageBox 图片批量下载器,网页图片批量下载专家,网页图片批量下载器,获取到文章图片,imoviebox网页视频批量下载器,下载视频内容,为您提供.
阅读和此文章类似的: 全球云计算