一、缓存与数据库不一致情况

在一般的网站的架构中,我们都会采用缓存架构来抗住高并发场景下的读请求。那么对于写请求,先更新缓存还是先更新数据库?
本文以商品库存信息为例,我们展开讨论,假设刚开始数据库库存=100,缓存中库存=100.

1.先更新数据库,后更新缓存

这种情况下,当需要更新库存的时候,先更新数据库中的库存=99,然后再更新缓存=99。

但是想象一种场景,由于网络原因,数据库更新成功,但是缓存更新失败,那么此时来了读请求,那么此时会读到缓存中的数据,与数据库中的数据不一致,那么就会产生错误。

2. 先更新缓存,后更新数据库。

使用该策略,当需要更新库存的时候,先更新缓存中库存=99,然后再更新数据库=99。

此时假设更新完缓存之后,由于网络原因,数据库还没有更新成功,但是此时有一个写请求过来,去缓存中请求数据得到的是更新之后的数据,然而数据库中还是之前的数据,这样就产生了不一致性的问题。虽然这种不一致性情况有些牵强,有人认为,写请求在前,读请求在后,虽然数据库此时没有更新成功,但是一旦网络恢复就会更新成功,与之前读到的是一致的,那么我们暂且认为这种情况也可以行得通。

那么来看看该方案下的另一种情况,如果此时有大量的写请求,每次写请求都需要更新缓存,然后更新数据库,假设10ms中有10个写请求,但是只有一个读请求,需要更新10次缓存和10次数据库。这样在高并发场景下会给系统带来很大的延迟。那么,这种方案真的可行吗?真的是更新吗?

3.先删除缓存,后更新数据库

这里要强调删除,而不是更新,我们可以看到上面一种情况在高并发场景下根本不适用,先删除缓存,之前需要更新10次缓存,10次数据库,我们优化为只需要删除一次缓存,更新10次数据库,当有一个读请求过来只是没有命中,去数据库读取一下,这样对性能的影响也不是很大。

那么,再次思考一下,这样做在高并发情况下真的可以保证数据库和缓存中数据一致吗?

在高并发场景下,当一个写请求过来之后,我们删除了缓存,还没有更新数据库,紧接着来了一个读请求,发现缓存中的数据被删除了,去数据库中读取数据后返回给用户,同时也更新到缓存。在这一系列请求结束之后,写请求才将数据库的数据更新到最新值,此时数据不一致性的问题。

高并发库存扣减 redis多集群_更新数据

二、高并发场景下的优化方案

在上面,我们主要发现最主要的问题是数据库没有更新成功,读请求就直接读数据库了。那么我们是否可以让读请求在写请求完成之后再去读数据库呢?

1.消息队列串行化方案

该方案的主要思路是在后台进程中我们可以创建多个队列,然后根据hash算法将写请求路由到不同的队列中,当来读请求的时候,就加入队列中,当写请求处理完毕后,再去处理读请求。

该方案需要注意以下几点:

  1. 可能会有大量读请求,这样读请求不就串行化了?因此只需要将第一个读请求加入队列中,其他读请求阻塞在cache。
  2. 需要将同一份数据的写请求和读请求路由到同一个队列中。

高并发库存扣减 redis多集群_缓存_02


这种情况下,如果对于同一份数据有多个写请求同时在队列中,那么来一个读请求中加入队列中之后,一般写请求耗时比较久,那么读请求会需要很久才能返回。也许是缓存中根本没有,我们只需直接去数据库中读取即可,但是加入队列中却需要等待这么长时间。

因此,我们可以设置读请求在队列中的等待超时时间,当达到一定时间时还在等待,那么直接去数据库读取返回即可。

以上是本人对缓存数据库不一致情况的理解,本人能力有限,如有问题还望包含,也欢迎指正。谢谢!