返回

数据更新了,缓存该怎么处理?

闲谈

缓存是否是我们开发应用程序的必选方案呢?我们应该如何利用好缓存呢?在什么情况下才需要使用缓存呢?以下的场景是否需要缓存呢?

我们有一个接口:GetUserInfo(UserId),返回一个用户详情信息。用户访问这个接口的频率很高,其中有80%都是重复数据。在这种情况下,应该使用缓存来优化用户体验。

缓存中最基础的问题:缓存是否更新一致。什么情况下需要担心缓存不一致?那就是缓存系统和数据库存在并发的写入场景。场景如下:

1. 用户请求接口:GetUserInfo(UserId),缓存系统中命中数据,因此直接返回结果,接口返回成功
2. 另一个用户修改了UserId对应的数据,更新了数据库,此时缓存系统没有收到通知
3. 用户再次请求接口:GetUserInfo(UserId),缓存系统中命中数据,返回结果,接口返回成功。此时缓存数据已经被污染了

上面这种情况,导致的结果就是用户读取到了脏数据。当然解决这个问题也非常简单,我们确保在数据库每次更新后,都发送一个通知到缓存系统,让缓存系统根据通知删除或更新对应的缓存数据。

但是这样还会导致另一个问题,性能瓶颈。每一次更新数据,我们都需要通知缓存系统,缓存系统也需要查找对应的缓存数据并删除。对于高并发的场景,可能导致数据库和缓存系统都成为系统的瓶颈。

先删缓存,后更新库

我们可以在用户请求的时候删除缓存数据,然后调用数据库接口更新数据,在返回结果给用户之前,重新加载缓存数据。但是这会导致并发问题,多个用户同时请求这个接口,同一个用户的数据会被多次更新。

先更新库,后删缓存

我们可以在数据库更新完数据后,再发送一个通知到缓存系统,让缓存系统删除对应的缓存数据。这种方式可以保证数据的正确性,但是延时会比较高。

解决方案:延时双删

我们可以在缓存系统中设置一个缓存过期时间,当缓存数据过期后,缓存系统会自动删除该缓存数据。这样可以保证数据的正确性,同时降低延时。

解决方案:消息队列

我们可以使用消息队列来解决这个问题。当数据库更新完数据后,我们把更新数据的操作放到消息队列中,缓存系统订阅这个消息队列,然后从消息队列中获取更新数据的操作,并更新对应的缓存数据。这种方式可以保证数据的正确性,同时降低延时。

缓存坑爹三剑客

最后给大家介绍几个缓存的坑。

1. 缓存雪崩

当缓存系统发生故障时,所有缓存数据都失效了,此时所有的请求都会直接访问数据库,导致数据库负载过高,甚至宕机。

2. 缓存穿透

当用户请求一个不存在的缓存数据时,缓存系统会直接从数据库中加载数据,然后返回给用户。但是,如果用户多次请求同一个不存在的缓存数据,就会导致数据库负载过高。

3. 缓存击穿

当缓存中的数据过期时,多个用户同时请求同一个数据,就会导致所有的请求都直接访问数据库,导致数据库负载过高。