数据一致性
一致性就是数据保持一致,在分布式系统中,可以理解为多个节点中数据的值是一致的。
- 强一致性:这种一致性级别是最符合用户直觉的,它要求系统写入什么,读出来的也会是什么,用户体验好,但实现起来往往对系统的性能影响大
- 弱一致性:这种一致性级别约束了系统在写入成功后,不承诺立即可以读到写入的值,也不承诺多久之后数据能够达到一致,但会尽可能地保证到某个时间级别(比如秒级别)后,数据能够达到一致状态
- 最终一致性:最终一致性是弱一致性的一个特例,系统会保证在一定时间内,能够达到一个数据一致的状态。这里之所以将最终一致性单独提出来,是因为它是弱一致性中非常推崇的一种一致性模型,也是业界在大型分布式系统的数据一致性上比较推崇的模型
业务延时双删
先删除缓存,再更新数据库中如何避免脏数据?采用延时双删策略。
- 先删除缓存
- 再写数据库
- 休眠1秒后再次删除缓存(这1秒=业务可能最大耗时,主要是等待正在加载脏数据的请求完成)
① 读写分离架构
读写架构中,先删除缓存,再更新数据库中如何避免脏数据?采用延时双删策略。
- 先淘汰缓存
- 再写数据库
- 休眠1秒后再次淘汰缓存(这1秒=主从同步可能最大耗时+业务可能最大耗时,主要是等待正在加载脏数据的请求完成)
② 延时双删导致吞吐量降低
延时双删的方式同步淘汰策略导致了吞吐量降低如何解决?
- 将第二次删除作为异步
MQ重试机制
不管是延时双删还是Cache-Aside的先操作数据库再删除缓存,都可能会存在第二步的删除缓存失败,导致的数据不一致问题,可以引入删除缓存重试机制来解决。
流程如下:
- 更新数据库数据
- 删除缓存中的数据,可此时缓存服务出现不可用情况,造成无法删除缓存数据
- 当删除缓存数据失败时,将需要删除缓存的 Key 发送到消息队列 (MQ) 中
- 应用自己消费需要删除缓存 Key 的消息
- 应用接收到消息后,删除缓存,如果删除缓存确认 MQ 消息被消费,如果删除缓存失败,则让消息重新入队列,进行多次尝试删除缓存操作
biglog异步删除
重试删除缓存机制会造成好多业务代码入侵。其实还可以这样优化:通过数据库的binlog来异步淘汰key。
流程如下:
- 更新数据库数据
- MySQL将数据更新日志写入binlog中
- Canal订阅&消费MySQL binlog,并提取出被更新数据的表名及ID
- 调用应用删除缓存接口
- 删除缓存数据
- Redis 不可用时,将更新数据的表名及 ID 发送到 MQ 中
- 应用接收到消息后,删除缓存,如果删除缓存确认 MQ 消息被消费,如果删除缓存失败,则让消息重新入队列,进行多次尝试删除缓存操作,直到缓存删除成功为止