0
点赞
收藏
分享

微信扫一扫

数据库与缓存的数据一致性

12a597c01003 2022-03-13 阅读 40

数据库与缓存的数据一致性

数据一致性和事务一致性的区别

数据一致性:在某一时刻同时读取分布式系统中同一份数据的多个副本,如果得到的结果相同,那么就是一致的,对应了CAP定理中的C。
事务一致性:数据库事务在开始前和结束后,数据库的完整性约束没有被破坏,但并不能保证事务的结果是正确的,这应该由应用程序来保证。参考维基百科中关于数据库一致性的定义:

附,维基百科中关于ACID的定义

数据一致性

强一致性

也称“线性一致性”,对数据的修改是同步的,数据修改前后都必须是一致的,比如库存、付款、转账等业务,大多数业务都不要求强一致性。

弱一致性

对数据的修改是异步的,可能存在某一时刻数据不一致的情况。最终一致性属于弱一致性的特殊情况。

最终一致性

对于任何人修改的数据,任何人最终都能读到修改后的数据,但不保证任何人能够立即读到修改后的数据。读写一致性、会话一致性、单调读一致性、因果一致性都属于最终一致性的特殊情况。

读写一致性

对于A修改的数据,A能够立即读到修改后的数据,但不保证B能够立即读到修改后的数据。

会话一致性

对于A修改的数据,只在同一个会话中保证读写一致性。对于A新建的会话,只保证最终一致性。

单调读一致性

任何人一旦读到了数据a的值v,那么接下来他都不会读到比v更早的值。

单调写一致性

对于A先后两次对数据a的修改操作,系统都要保证是顺序进行的。

因果一致性

如果数据a和数据b存在因果关系a->b,那么任何人如果能够读到数据b,则必须能读到数据a。

数据库与缓存的数据一致性

强一致性

将缓存和数据库理解为数据的两个副本,在任意时刻读取缓存或数据库,得到的结果都是一致的。

唯一的办法就是把写操作封装成事务,实现共享锁和排他锁的逻辑。锁的范围包括了在数据库和缓存中对应的数据及其衍生数据。只有获取了排他锁的线程才能对数据进行写操作,在排他锁释放前,其他线程无法读写。此时其他线程要么返回失败,要么进入等待队列。这种方式对并发性能影响很大。

若要提高并发性能,可以再实现MVCC的逻辑,也就是给数据增加版本号,这样锁的范围就变成了数据+版本。在排他锁释放前,其他线程的读操作可以正常进行,返回旧版本的数据,但写操作仍然阻塞。

最终一致性

实现最终一致性的方案有很多,需要根据业务场景对数据一致性的要求来设计具体方案,举一些常见的方案。总结不一定全面,思路可以参考。

写数据库-删缓存

优点:

  • 实现简单

缺点:

  • 写完数据库后,在删缓存前,一个进程读缓存,另一个进程读数据,就会出现数据不一致。
  • 如果删缓存失败,则无法保证数据最终一致性。
  • 删缓存会引入缓存击穿的风险,需要对读并发进行评估,避免删完缓存后,大量读请求打到数据库,造成数据库压力过大。

删缓存-写数据库

优点:

  • 实现简单,能够保证删缓存成功(如果失败则不会写数据库),解决了删缓存失败的风险。
  • 在没有读并发的情况下,写完数据库后,就能读到最新的数据。

缺点:

  • 如果在删缓存和写数据库之间,其他线程往缓存中写入旧数据,则无法保证数据最终一致性。

删缓存-写数据库-再删缓存

优点:

  • 实现简单,能够保证第一次删缓存成功(如果失败则不会写数据库),缓解了删缓存失败的风险。
  • 一般来说,两次删缓存间隔不会太长,第一次删成功说明缓存是可用的,所以第二次删失败的概率很低,大多数情况下都能确保数据最终一致性,除非在缓存在那一瞬间挂掉或网络不通。

缺点:

  • 如果在第一次删缓存和写数据库之间,其他线程往缓存中写入旧数据,并且第二次删缓存失败,则无法保证数据最终一致性。
  • 两次删缓存增加了缓存击穿的风险。

删缓存-写数据库-删缓存(-删除失败-异步删缓存直到成功)

优点:

  • 能够保证数据的最终一致性。

缺点:

  • 引入了异步操作,增加了系统复杂度和维护成本。

定时加载缓存

优点:

  • 能够保证数据的最终一致性,不会引入缓存击穿的风险。

缺点:

  • 只能配置有限的定时任务,所以只适用于小范围的数据更新,比如常量类。
  • 引入了全局定时任务,需要保证定时任务的可靠性,避免定时任务挂了导致缓存无法更新。
  • 加载频率直接影响到数据不一致的持续时间,需要权衡数据更新频率和业务对数据不一致的容忍程度。
  • 要考虑定时加载的数据量,避免反复加载大量无需更新的数据,给数据库增加不必要的压力。

写数据库-写缓存

优点:

  • 实现简单,不会引入缓存击穿的风险

缺点:

  • 如果写缓存失败,则无法保证数据最终一致性。
  • 在写并发情况下会出现覆盖更新,出现时光倒流问题,还可能导致脏数据。

写数据库-写缓存(-写失败-异步读数据库再写缓存直到成功)

优点:

  • 避免了写缓存失败,在没有写并发的情况下,可以保证数据一致性。

缺点:

  • 引入了异步操作,增加了系统复杂度和维护成本。
  • 在写并发情况下,增加了覆盖更新的几率,无法保证数据最终一致性。

写缓存-写数据库

优点:

  • 避免了写缓存失败,在没有写并发的情况下,可以保证数据一致性。

缺点:

  • 需要增加缓存的回滚操作,数据库回滚时,缓存也要一并回滚
  • 发生回滚时,会出现时光倒流问题,还可能导致脏数据。
  • 在写数据库完成前,缓存挂掉,如果之前已经读取了缓存中的新值,那就出现时光倒流问题,可能出现脏数据。

写缓存-写数据库(-写失败-异步写数据库直到成功)

优点:

  • 避免了写缓存失败。
  • 可以保证数据最终一致性。

缺点:

  • 引入了异步操作,增加了系统复杂度和维护成本。
  • 需要保证写数据库的顺序一致性。

参考文章

强一致性、顺序一致性、弱一致性和共识
如何理解数据库事务中的一致性的概念
数据库的ACID(原子性、一致性、隔离性与持久性)
通俗易懂 强一致性、弱一致性、最终一致性、读写一致性、单调读、因果一致性 的区别与联系

举报

相关推荐

0 条评论