- 强一致性,
任何一次读都能读到某个数据的最近一次写的数据。
系统中的所有进程,看到的操作顺序,都和全局时钟下的顺序一致。 - 弱一致性,
据更新后,如果能容忍后续的访问只能访问到部分或者全部访问不到,则是弱一致性。
最终一致性就属于弱一致性。 - 最终一致性
不保证在任意时刻任意节点上的同一份数据都是相同的,但是随着时间的迁移,不同节点上的同一份数据总是在向趋同的方向变化。
最终两个字用得很微妙,因为从写入主库到反映至从库之间的延迟,可能仅仅是几分之一秒,也可能是几个小时
简单说,就是在一段时间后,节点间的数据会最终达到一致状态。
Redis和MySQL如何保持数据一致性
我们通常使用redis集成springboot做数据缓存的时候,一般只是将数据存放到缓存中,设置过期时间。
问题:
如果来缓存失效前,修改了数据库,那就会出现,缓存和mysql数据不一致的情况。因为redis存在,请求就会直接返回redis缓存中的数据。
1.先更新数据库,再更新缓存(不建议)
A修改数据,B修改数据,但是A在修改完数据后,B立马修改,由于网络原因可能造成b先修改了缓存数据,a再修改缓存。这样缓存中的数据就是a请求修改后的数据,这样就造成了数据不一致的情况。
2.先删缓存,再更新数据库
如果先删除缓存,但是数据还没写入mysql,就有请求来读取,发现缓存没有数据,就会把旧数据再写入缓存,还是会造成数据不一致的情况。
解决:
延时双删策略
在数据库更新前删除缓存,然后对数据库进行写入操作,数据库更新完成后再删除再次删除缓存,目的是删除可能后来的读取请求写入缓存的脏数据。第二次删除之前可以休眠几秒。
3.先更新数据库,再删除缓存
如果线程修改了数据库,然后线程挂了,导致缓存没有删除,那么在缓存失效前,读取的是缓存中的旧数据。(但是这个比较极端就不考虑了)
①此时缓存刚好失效
②请求A 就会去查询数据库得到一个旧的值
③请求B将新的值写入数据库
④请求B写入成功后删除缓存
⑤请求A将查到的机制写入缓存,产生脏数据…
如果发声上述情况,确实会产生数据不一致的情况,但是XDM想一想,发生这种情况的概率是多少呢?如果先要产生这种结果,就必须有一个条件,就是请求B的操作时间非常短,短到什么程度呢,就是请求B写入数据库的操作要比请求A从数据库中读取数据的速度要快(因为redis非常快,因此操作redis的时间可以暂且忽略),只有这种情况下④才可能比⑤先发声,但是数据库的读操作要远比写操作快的多,不然做读写分离干嘛呢?所以这种情况发生的概率是非常非常非常的低,但是如果强迫症患者出现必须要解决怎么办呢?就可以采用给缓存设置过期时间或者采用第二种方案的延时双删策略,保证读请求完成之后在进行删除操作。
最后:
还有问题呀,就是最终解决方案三可能 出现的极低概率的数据不一致的方案是采用方案二的延时双删策略,可是在方案二中也说了,如果出现缓存删除失败的情况咋办?那不是还会出现数据不一致的问题吗?这个问题到底如何解决呢?这里提供一个重试机制,删除失败就重试一次呗,这里提供一种重试的方案。
①更新数据库
②由于各种原因缓存删除失败
③将删除失败的缓存放入消息队列中
④业务代码从消息队列中获取需要删除的key
⑤继续尝试删除操作,直到成功
参考博客:https://baijiahao.baidu.com/s?id=1706150811910444110&wfr=spider&for=pc