一个高频面试题:怎么保证缓存与数据库的双写一致性?

国内新闻 浏览(960)

面试问题分析Cache Aside Pattern的缓存不一致的初始水平和解决更复杂的数据不一致性分析

只要使用缓存,它可能涉及数据库的双重存储和双重存储。只要你双写,就会出现数据一致性问题。你如何解决一致性问题?

一般来说,如果你允许缓存与数据库略有不一致,也就是说,如果你的系统没有严格要求“cache + database”必须是一致的,最好不要这样做,即:read request Serialize the写请求并将其串入内存队列。

序列化保证不会出现不一致,但它也会导致系统吞吐量显着降低,从而支持具有比正常情况大几倍的在线订单的机器。

解决方案:首先删除缓存,然后修改数据库。如果数据库修改失败,数据库是旧数据,缓存为空,则数据不会不一致。由于缓存在读取时不可用,因此将读取数据库中的旧数据,然后将其更新到缓存中。

比较复杂的数据不一致问题分析

数据已更改,首先删除缓存,然后修改数据库。它尚未修改。请求过来,读取缓存,发现缓存为空,查询数据库,在修改之前查找旧数据,并将其放入缓存中。后续数据更改过程完成数据库的修改。

完成后,数据库和缓存中的数据是不同的。

为什么在数亿个高流量并发场景的情况下存在缓存问题?

只有在同时读取和写入一段数据时才会出现此问题。实际上,如果你的并发性非常低,特别是阅读并发性非常低,那么每天的访问次数就是10,000次。在极少数情况下,将出现刚才描述的不一致场景。但问题是,如果每天有数亿个流量,每秒并发读取的数量是数万个,并且只要每秒都有数据更新请求,就可能发生上述数据库+缓存不一致。

解决方案如下:

更新数据时,根据数据的唯一标识符,操作被路由并发送到jvm内部队列。在读取数据时,如果发现数据不在缓存中,则会重新读取数据+更新缓存操作,并在根据唯一标识符发送路由后,还会发送相同的jvm内部队列。

这里有一个优化点。事实上,在队列中,将多个更新缓存请求序列化在一起是没有意义的,因此您可以进行过滤。如果您发现已有请求更新队列中的缓存,则无需再发出其他更新请求。操作进入并直接等待先前的更新操作请求完成。

在对应于队列的工作线程完成对先前操作的数据库的修改之后,它将执行下一个操作,即缓冲更新的操作。此时,从数据库中读取最新值,然后将其写入缓存。

如果请求仍在等待时间范围内,并且轮询发现可以获取该值,则直接返回;如果请求等待超过一段时间,则此时直接从数据库中读取当前旧值。

1、读请求长时阻塞

由于读取请求非常轻微异步,因此必须注意读取超时问题,并且必须在超时期限内返回每个读取请求。

此解决方案的最大风险点是数据可能经常更新,导致队列中的大量更新操作,然后读取请求将有大量超时,最后大量的请求直接进入数据库。请务必查看测试的实际频率,以了解数据的更新频率。

件进行测试。您可能需要部署多个服务,并且每个服务将共享一些数据更新操作。如果存储器队列实际上挤压了100个项目的库存修改操作,则库存修改操作需要10ms才能完成,然后最后一个项目的读取请求可以等待10 * 100=1000ms=1s才能获得数据。这次,它会导致读取请求的长期阻塞。

确保根据实际业务系统操作进行一些压力测试,并模拟在线环境,以查看在最繁忙时间内可能会在内存队列中挤压多少更新操作,这可能导致上次更新操作。读取请求需要多长时间,如果读取请求以200ms返回,如果您已经计算,即使是最繁忙的时间,积压10次更新操作,等待最多200ms,那也没关系。

如果存在大量可能在内存队列中积压的更新操作,则需要添加计算机,以便在每台计算机上部署的服务实例处理的数据更少,因此每个内存队列中的更新积压更少。

实际上,根据以前的项目经验,一般来说,数据写入的频率非常低,所以实际上,一般来说,队列中的备份更新操作应该非常小。像这种用于读取高并发和读缓存架构的项目,写请求通常非常小,每秒的QPS可以达到几百。

实际上粗略计算

如果在一秒内有500次写操作,如果它被分成5个时间片,每200ms写100次,放入20个存储器队列,每个存储器队列可能有5个写操作的积压。每次写操作性能测试后,一般在大约20ms内完成,然后每个内存队列的数据读取请求将暂停一段时间,并且肯定会在200ms内返回。

经过简单的计算,我们知道单个机器支持的写QPS几百没问题。如果QPS扩展了10倍,那么机器将扩展为将机器扩展10倍,每台机器将有20个队列。

2、读请求并发量过高

还必须进行压力测试,以确保当碰巧遇到上述情况时,仍然存在突然大量读取请求将在数十毫秒内延迟服务的风险,以查看服务是否可以存在没有它。有多少台机器可以保持最高限制情况的峰值。

但由于并非所有数据同时更新,缓存不会同时到期,因此每次可能是少量数据缓存失效,那么对应的那些数据读取请求,并发卷不应该特别大。

3、多服务实例部署的请求路由

此服务可能部署了多个实例,因此必须保证数据更新操作和执行缓存更新操作的请求通过Nginx服务器路由到同一服务实例。

例如,对同一项目的读取和写入请求都将路由到同一台计算机。您可以根据服务之间的请求参数进行哈希路由,也可以使用Nginx的哈希路由功能等。

4、热点商品的路由问题,导致请求的倾斜

如果对特定产品的读写请求特别高,则所有这些请求都转到同一台机器的同一队列,这可能会对某台机器造成过大的压力。也就是说,因为只有在更新产品数据时才会清除缓存,然后读取和写入将是并发的,因此有必要查看业务系统。如果更新频率不是太高,则该问题的影响不是特别大。但确实有些机器可能有更高的负载。

http://www.whgcjx.com/bdse