当前位置: 首页 > 后端技术 > Java

面试官:在高并发场景下,你们是如何保证数据一致性的?

时间:2023-04-01 15:50:40 Java

采访的时候,总会有这样的场景。1.场景分析面试官:你们的服务QPS是多少?我:在我们服务的高峰期,访问量还是挺大的,3万左右。面试官:你们的服务器能支持这么大的访问量吗?有没有缓存?我:是的,我们使用Redis作为缓存。接口先查询缓存,缓存不存在才访问数据库。这样可以减轻数据库访问压力,加快查询效率。面试官:一份数据存放在两个地方。更新数据时,如何保证数据的一致性?你看,一个好的面试官一般不会直接问你数据一致性的解决方案,而是结合具体的使用场景,用说服的方式问你解决方案。如果你从来没有做过这个,也没有线上实践经验,一般很难有条不紊、周到地回答。保证数据一致性,一般有四种方法:先更新缓存,再更新数据库。先更新数据库,再更新缓存。先删除缓存,再更新数据库。先更新数据库,再删除缓存。各方案详解:2.方案2.1先更新缓存,再更新数据库如果两个并发的写请求同时到来,执行过程如下:写请求1更新缓存,设置age为1写请求2更新缓存,设置age为2,写请求2更新数据库,设置age为2,写请求1更新数据库,设置age为1,执行结果为缓存中的age为设置为2,而数据库中的age设置为1,导致数据不一致,这个方案不可行。2.2先更新数据库,再更新缓存。如果同时有两个并发的写请求,执行过程如下:写请求1更新数据库,设置age为1,写请求2更新数据库,设置age为2,写请求2更新数据库cache,设置age为2,写入请求1更新缓存,设置age为1,执行结果是数据库中age设置为2,cache中age设置为1,导致不一致数据。该解决方案不可行。2.3先删除缓存,再更新数据库。如果同时有两个并发的读写请求,执行过程如下:写请求删除缓存,读请求查询缓存没有数据,再查询数据库,再将数据写入缓存。写请求更新数据库的结果是缓存中有旧数据,数据库中有新数据,导致数据不一致。该解决方案不可行。2.4先更新数据库再删除缓存的方案,在并发写入时不会出现问题。因为先更新数据库,再删除缓存,所以不会出现不一致的情况。但是在并发读写的时候还是有可能出现数据不一致的情况。读请求查询缓存没有数据,再查询数据库写请求更新数据库,删除缓存读请求写回缓存执行结果是缓存中有旧数据,数据库中有新数据,导致在数据不一致。其实这种情况出现的概率很低。写入缓存比写入数据库快几个数量级。读写缓存都是内存操作,速度很快。遇到这种极端场景,我们也需要做一个自下而上的预案,缓存要设置一个过期时间。该方案属于数据的弱一致性和最终一致性,不属于强一致性。3.总结与思考有的读者可能会好奇,为什么不在更新缓存和数据库方法中加入事务注解来实现强一致性,这样无论哪种方案都不会有问题。是的,当我们的服务只在一台机器上时,添加本地事务是可行的。但是在工作中,我们会将一个服务部署到几十台或者上百台机器上。有时为了应对更极端的查询请求,我们会在Redis缓存中加一层本地缓存。这个时候,我们使用本地事务合适吗?有效的。一份数据存在于多台机器上,存在多个副本。为了实现强一致性,我们还可以使用分布式事务。这样一来,更新缓存操作就会变得非常复杂,得不偿失。但是在其他一些场景,比如更新订单状态,更新用户资产,在这个场景下,无论我们付出多少,我们都必须做到数据强一致。具体的实现方案一般有以下几种:第二阶段提交TCC本地消息表在MQ事务消息分布式事务中间件的下一篇文章中,我们将详细分析这些方案的优缺点。