如何保证本地缓存、分布式缓存、数据库之间的数据一致性?

很高兴能够看到和回答这个问题,作为一个科技爱好者 , 我每天都在科技发展方面的消息,每天收获也蛮多的 。
首先,我觉得这是一个非常好的问题 , 也是很多小白用户困惑之处 , 下面我将根据自己的经验认真回答这个问题 。
分布式类型高速缓存现在是许多分布式应用程序中必不可少的组件 , 但是如果以分布式格式使用高速缓存,则它可能与高速缓存和双数据库关联 。如果您写两次,那么数据序列肯定会出现问题,您该如何解决兼容性问题?
最经典的缓存+数据库模式是“缓存备用模式”
读取高速缓存,不带单词的高速缓存,读取数据库,然后删除数据并将其放入高速缓存中,然后作为响应进行回调 。更新数据库 , 然后删除缓存 。
为什么要删除缓存而不更新缓存?
原因是在许多情况下 , 缓存是复杂点的场景,缓存不只是从数据库输出 。例如,您可以先更新一个表字段,然后再更新相应的缓存 。为了计算最新的缓存值,有必要从另外两个表中请求数据并执行操作 。
有时,更新缓存的成本非常高 。这是否意味着每次对数据库进行更改时,都需要更新相应的缓存?也许有这样的场景,但是对于更复杂的缓存脚本 , 情况不再如此 。如果您经常更改缓存 , 那么它也会经常更新 。但是问题在于缓存将不经常可用吗?
如果添加栗子,则包括表字段的缓存将更改20次或在1分钟内更改100次 , 然后将缓存更新20次和100次,但是每分钟仅读取一次缓存,其中包含有关冷的大量数据 。实际上,如果您只是删除缓存,那么在一分钟之内就可以对缓存进行简单的重新计数 , 并且所花费的费用比缓存要少得多 。
实际上,删除缓存而不是更新缓存是一种惰性计算的思想,无论是否使用缓存,都不要每次都进行复杂的计算,而是在必要时重新进行计算 。就像,冬眠一样,每个人都认为自己很懒 。应部门的要求,部门带来了一份员工名单 , 无需说出每个部门的要求,它还包含1000名员工的数据 。在80%的情况下,检查该扇区足以访问有关该扇区的信息 。首先检查部门 , 还联系内部的员工,然后仅当您要访问数据库中的人员时,才可以联系1000名员工 。
缓存问题和解决方案
问题:首先更改数据库 , 然后删除缓存 。如果缓存删除错误,则将导致以下事实:数据库中的数据将是新的,缓存中的数据将是旧的,并且数据将不一致 。
解决方案:首先删除缓存,然后修改数据库 。如果数据库更改错误,则表明数据库中有旧数据,并且高速缓存为空 , 则数据不会彼此不同 。由于无法读取缓存 , 因此请读取数据库中的旧数据并在缓存中进行更新 。
分析更复杂的数据不一致问题
更改了数据,首先删除了缓存,然后对数据库进行了更改 , 直到进行了更改 。读取缓存的一个请求,发现缓存为空,转到数据库 , 在进行更改之前找到了旧数据,并将其放入缓存中 。数据修改程序已完成数据库的更新 。
一切都消失了,数据库和数据中的缓存不相似…
为什么缓存与脚本结合使用时会产生数十亿的高流密度的问题?
仅当同时读取和写入数据时,才会出现此类问题 。实际上,如果您的并行增长非常低,尤其是阅读和分发 , 则每天的访问量为10,000,那么在极少数情况下,就会出现刚才提到的不一致的情况 。但是,问题在于,如果流的日流量为每秒1亿,则如果请求更新数据,则上述数据库+缓存之间可能不匹配 。
解决方法如下:
当更新数据时 , 根据单个数据标识符 , 将在发送到jvm内部队列后沿该路由执行操作 。当读取数据时,如果在缓存中找不到数据 , 则会根据将发送到jvm内部队列的唯一标识路由,重新读取数据并更新缓存操作 。
队列对应于一个工作讨论,每个讨论按顺序执行 , 然后执行一篇文章 。因此,数据修改操作首先删除高速缓存,然后更新数据库 , 但不更新它 。同时,如果读取了读取请求且缓存为空 , 则可以先将请求更新缓存以发送到队列 。此时,队列中的滞后将累积,然后同步将等待缓存更新完成 。
这里有一个优化点 , 一个队列中没有几个请求一起更新缓存,因此您可以过滤是否已经有更新队列中的缓存的请求,您不需要在队列中输入更新请求 , 只需等到请求更新将完成 。
在此队列完成上一个操作的数据库中的更改之后,将执行下一个操作,即缓存将被更新 。在这种情况下 , 将读取数据库中的最后一个值并将其输入到高速缓存中 。
如果该请求仍在可及范围内,并且事实证明该请求可用,则立即返回;如果等待时间超过一定时间,则这次将直接从数据库中读取当前的旧值 。
在高度一致的情况下,该解决方案需要注意:
1.Ready请求被长时间阻止
由于读取请求非常轻巧且异步,因此必须注意读取延迟,并且每个读取请求都应在等待时间内返回 。
该决定主要是由于很可能会经常更新数据,这导致以下事实:队列中积累了大量更新操作,然后在读取请求中发生了许多中断,最终导致大量查询直接进入数据库 。有必要通过进行一系列模拟和实际测试来检查数据更新的频率 。
此外,由于在其中一个队列中可能存在积压的多个位置更新数据 , 因此有必要考虑到您自己的操作来检查它们,因此您可能需要部署多个服务 , 每个服务都将分发部分数据更新操作 。如果在存储队列中您确实从修改库存中挤出了100种商品,则每次库存更改需要10毫秒才能完成时 , 那么读取最后一种商品的请求可能会等待10*100==1s来接收数据,这会导致较长的读取延迟要求 。
必须根据实际操作系统进行几次压力测试 , 并对网络环境进行建模,以查看内存队列有多繁忙可以产生更新,这可能导致对应于读取请求的最新更新,如果读取请求返回200ms,则挂起要花多长时间如果您甚至计算出最紧张的时间,即10次更新的滞后 , 最多200ms,那么这是可能的 。
如果大量更新可以在内存队列中累积 , 那么您需要添加设备,以使部署在计算机上的服务的每个实例处理的数据更少,那么队列中累积的更新数量将减少 。
实际上,根据先前项目的经验,数据记录的频率通常很低 , 因此在实践中,通常 , 在队列中更新的滞后应该微不足道 。与该项目有关读取和读取缓存的体系结构的情况一样,写入请求通常非常少,每秒QPS可以达到数百 。
1、实际流利度计算
如果在一秒钟内执行500次写入操作,如果除以5个计时器,每次操作以及该存储队列中的20个操作,则每个存储队列可能会延迟5次写入操作 。通常java简单实现一个阻塞队列 , 在每次记录性能测试之后,大约需要20ms,然后读取每个内存队列中的数据的请求也将挂起一会儿,可以返回200ms 。
经过简单的测量,我们知道支持一台机器成百上千个QPS并不是问题,如果将QPS记录增加10倍 , 则该机器将扩展10倍,每台机器20个队列 。
2、读取请求过多
还必须在此处进行压力测试java简单实现一个阻塞队列,以确保在遇到上述情况时,存在服务意外的大量读取请求被延迟数十毫秒的风险,以使服务了解如何进行服务不可用,以及需要多少辆汽车才能承受最大峰值 。
但是,由于并非同时更新所有数据 , 因此高速缓存不会同时过期,因此,每次高速缓存中可能会丢失多个数据时 , 此数据将成为读取请求,并且它们的数量不是应该特别大 。
3、多服务路由请求部署示例
也许此服务包含几个示例 , 所以有必要确保通过Nginx服务器将数据更新操作的执行以及缓存更新请求的执行定向到同一服务目录 。
例如,请求读取和写入同一产品 , 到同一机器的整个路径 。您可以根据所请求的参数之一沿着哈希路由前往服务办公室,也可以使用Nginx哈希路由 , 依此类推 。
4、热货路线问题,导致要求
如果读取和写入产品的顺序特别高,则与在同一台计算机上相同的队列中的所有内容都可能对同一台计算机造成过大的压力 。这意味着 , 由于仅在更新产品数据时才清除缓存,然后它们导致读写,实际上是看业务系统 , 如果刷新率不太高,则此问题的后果不会特别明显很好,但是,当然 , 某些汽车上可能会有很大的负载 。
以上便是我的一些见解和回答,可能不能如您所愿,但我真心希望能够对您有所帮助!不清楚的地方您还可以我的头条号“每日精彩科技”我将竭尽所知帮助您!
码字不易,感觉写的还行的话,还请点个赞哦!
【如何保证本地缓存、分布式缓存、数据库之间的数据一致性?】本文到此结束 , 希望对大家有所帮助 。