>>号外:关注“Java精选”公众号,回复“面试资料”,免费领取资料!“Java精选面试题”小程序,3000+ 道面试题在线刷,最新、最全 Java 面试题!
在一般的网站的架构中,我们都会采用缓存架构来抗住高并发场景下的读请求。那么对于写请求,先更新缓存还是先更新数据库?本文以商品库存信息为例,我们展开讨论,假设刚开始数据库库存=100,缓存中库存=100。这种情况下,当需要更新库存的时候,先更新数据库中的库存=99,然后再更新缓存=99。但是想象一种场景,由于网络原因,数据库更新成功,但是缓存更新失败,那么此时来了读请求,那么此时会读到缓存中的数据,与数据库中的数据不一致,那么就会产生错误。使用该策略,当需要更新库存的时候,先更新缓存中库存=99,然后再更新数据库=99。此时假设更新完缓存之后,由于网络原因,数据库还没有更新成功,但是此时有一个写请求过来,去缓存中请求数据得到的是更新之后的数据,然而数据库中还是之前的数据,这样就产生了不一致性的问题。虽然这种不一致性情况有些牵强,有人认为,写请求在前,读请求在后,虽然数据库此时没有更新成功,但是一旦网络恢复就会更新成功,与之前读到的是一致的,那么我们暂且认为这种情况也可以行得通。那么来看看该方案下的另一种情况,如果此时有大量的写请求,每次写请求都需要更新缓存,然后更新数据库,假设10ms中有10个写请求,但是只有一个读请求,需要更新10次缓存和10次数据库。这样在高并发场景下会给系统带来很大的延迟。那么,这种方案真的可行吗?真的是更新吗?这里要强调删除,而不是更新,我们可以看到上面一种情况在高并发场景下根本不适用,先删除缓存,之前需要更新10次缓存,10次数据库,我们优化为只需要删除一次缓存,更新10次数据库,当有一个读请求过来只是没有命中,去数据库读取一下,这样对性能的影响也不是很大。那么,再次思考一下,这样做在高并发情况下真的可以保证数据库和缓存中数据一致吗?在高并发场景下,当一个写请求过来之后,我们删除了缓存,还没有更新数据库,紧接着来了一个读请求,发现缓存中的数据被删除了,去数据库中读取数据后返回给用户,同时也更新到缓存。在这一系列请求结束之后,写请求才将数据库的数据更新到最新值,此时数据不一致性的问题。在上面,我们主要发现最主要的问题是数据库没有更新成功,读请求就直接读数据库了。那么我们是否可以让读请求在写请求完成之后再去读数据库呢?该方案的主要思路是在后台进程中我们可以创建多个队列,然后根据hash算法将写请求路由到不同的队列中,当来读请求的时候,就加入队列中,当写请求处理完毕后,再去处理读请求。1)可能会有大量读请求,这样读请求不就串行化了?因此只需要将第一个读请求加入队列中,其他读请求阻塞在cache。2)需要将同一份数据的写请求和读请求路由到同一个队列中。这种情况下,如果对于同一份数据有多个写请求同时在队列中,那么来一个读请求中加入队列中之后,一般写请求耗时比较久,那么读请求会需要很久才能返回。也许是缓存中根本没有,我们只需直接去数据库中读取即可,但是加入队列中却需要等待这么长时间。因此,我们可以设置读请求在队列中的等待超时时间,当达到一定时间时还在等待,那么直接去数据库读取返回即可。以上是本人对缓存数据库不一致情况的理解,本人能力有限,如有问题还望包含,也欢迎指正。谢谢!作者:不清不慎
blog.csdn.net/qq_37142346/article/details/89463081