数据库缓存一致性的讨论

引入

在项目中,我们通常会使用缓存技术来避免巨大的数据库访问压力和提高获取数据的效率问题,在使用缓存中我们通常的模式是,第一次查询数据库,然后把结果放入缓存中,下次的查询会先访问缓存,当缓存不存在的时候才会访问数据库,在引入缓存的情况下可能会引发数据库和缓存不一致的问题。

问题1:怎么保持缓存与数据库一致?

也就是说在数据更新(包括删除)的时候,如何做到DB和缓存同时更新且保持一致?在缓存和数据库不一致的情况主要有以下3种情况的不一致:

  1. 数据库有数据,缓存没有数据;
  2. 数据库有数据,缓存也有数据,数据不相等;
  3. 数据库没有数据,缓存有数据。

对于上面的不一致产生的原因进行分析:

  1. 对于第一种,在读数据的时候,会自动把数据库的数据写到缓存,因此不一致自动消除
  2. 对于第二种,数据是最终变成的不相等,但他们之前在某一个时间点一定是相等的(不管你使用懒加载还是预加载的方式,在缓存加载的那一刻,它一定和数据库一致)。这种不一致是由于更新数据所引发的,在先更新数据库,然后删除缓存的操作中。数据库更新成功,删除缓存失败而导致的不一致。
  3. 对于第三种,情况和第二种类似,数据库数据删除成功,删除缓存失败。

因此,最终的结论是,需要解决的不一致,产生的原因是更新数据库和删除缓存没有处于同一事物。 解决方案大概有以下几种:

  1. 对删除缓存进行重试,数据的一致性要求越高,我越是重试得快。
  2. 定期全量更新,简单地说,就是我定期把缓存全部清掉,然后再全量加载。
  3. 给所有的缓存一个失效期。

任何不一致,都可以靠失效期解决,失效期越短,数据一致性越高。但是失效期越短,查数据库就会越频繁。因此失效期应该根据业务来定。

 

问题2:为什么更新缓存的策略是先更新数据库在删除缓存

读取的策略很容易理解,在更新数据的时候。使用的是先更新DB,在删除缓存,而不是其他的,除了上面的策略还可以采用以下策略

策略1:先删除缓存,在更新数据库

可能存在的问题:两个线程并发操作,A线程更新操作,B线程查询操作,A线程更新操作执行到删除缓存后,B线程执行查询操作没有命中缓存,于是把老数据读出来后放到缓存中,然后A线程继续更新了数据库。最终导致在缓存中的数据还是老的数据,从而引发不一致。且缓存的数据是脏数据。

策略2:先更新数据库,后更新缓存,而不是删除缓存

可能存在的问题:A,B两个线程同时做数据更新,A线程先更新了数据库,B线程后更新数据库,则此时数据库里存的是B线程的数据。而更新缓存的时候,是B线程先更新了缓存,而A线程后更新了缓存,则缓存里是A的数据。这样缓存和数据库的数据也不一致。

结论:以上2种策略都会引发数据库和缓存的不一致

 

其他问题

如果你的数据库没有做高可用的话,上面的缓存和数据库策略就没什么太大的问题,但是如果数据库做了高可用,就会涉及到主从数据库的数据同步问题。就是如果在数据还未同步到「从库」的时候,由于缓存未命中去「从库」取到了未同步前的旧值。

 

解决它的第一个方式很简单,也很粗暴。就是定时去「从库」读数据,发现数据和缓存不一样了就set到缓存里去。

但是这个方式有点“治标不治本”。不断的从数据库定时读取,对资源的消耗大不说,这个间隔频率也不好定义一个比较合适的统一标准,太短吧,会导致重复读取的次数加大,太长吧,又会导致缓存和数据库不一致的时间变长。

 

第二种方式使用更底层的方式进行,就是“哪里有问题处理哪里”,当「从库」完成同步的时候再额外做一次delete cache或者set cache的操作

如此,虽说也没有100%解决短暂的数据不一致问题,但是已经将脏数据所存在的时长降到了最低(最终由主从同步的耗时决定),并且大大减少了无谓的资源消耗。

对于一些数据要求比较严格不允许脏数据存在的情况,可以通过在在产生数据库写入动作后的一小段时间内强制读「主库」来加载缓存。然后,你在事务提交之后往共享存储中临时存一个{ key = dbname + tablename + id,value = null,expire = 3s }这样的数据,并且再做一次delete cache的操作。如此一来,当「读数据」的时候发生cache miss,先判断是否存在这个临时数据,只要在3秒内就会强制去主库取数据。这样会增加主库的压力

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值