常见缓存读写策略

常见缓存读写策略

leo 817 2021-04-10

缓存读写策略

我们都知道缓存大多数情况下是用来减轻数据库压力的。缓存读写策略就是在进行数据读/写时以何种策略读写缓存和数据库,即:读请求时先读缓存还是数据库,缓存中数据不存在怎么办,写请求时先更新数据库还是缓存,同步更新还是异步更新等一系列问题的方案。

Cache Aside Pattern

Cache Aside Pattern 译为旁路缓存模式。该模式以数据库为主,缓存为辅。主要策略如下:

读请求

在读请求时,先查询缓存:1. 缓存中存在,直接返回;2. 缓存中不存在,查询数据库,然后将结果写入缓存。

旁路缓存模式-读取数据

写请求

在写请求时,先更新数据库,然后直接删除对应缓存。

旁路缓存模式-写入数据

问题:写请求时,可以先删除缓存,后更新数据库吗?

答案:不能。可能会造成数据不一致问题。如:请求 1 对数据 A 发起写请求,先删除数据 A 的缓存,这时请求 2 对数据 A 发起读请求,由于缓存不存在,会先读取数据库中的 A 的值,然后写入缓存;之后请求1 更新数据库(此时数据 A 在缓存中的值和数据库中的值已经不一致了)。那么当下次对数据 A 的读请求来临时,由于缓存中存在数据 A ,直接返回,但是此时缓存中 A 的数据和数据库中 A 的数据不一致。

问题:写请求时,先更新数据库,后删除缓存就一定没有问题吗?

答案:不一定,但大概率没有问题。如:请求 1 对数据 A 发起读请求,缓存中不存在,这时请求 2 对数据 A 发起写请求,先更新数据库中的 A 的值,然后删除缓存;之后请求1 将自己读取到的数据写入缓存。这个时候数据 A 在缓存和数据库中的值也不一致了。但是由于缓存写入速度远高于数据库写入速度,请求 1 写入缓存一般比请求 2 写入数据库然后删除缓存先完成。

该模式适合读多的场景。

旁路缓存模式的缺点

  • 第一次读取时肯定会先读取数据库。

    解决方案:事先将热点数据载入缓存(缓存预热)。

  • 写操作频繁时会频繁删除缓存中的数据,导致缓存命中率较低。

    解决方案:1. 更新数据库的同时更新缓存,注意不是删除缓存,这通常需要加锁来保证这两个操作的原子性。适用于数据强一致性的场景。2. 更新数据库的同时更新缓存,并给缓存设置一个较短的存活时间,并且不需要加锁,但会出现数据不一致的问题。适用于可以接受短暂的数据不一致的场景。

Read/Write Through Pattern

Read/Write Through Pattern 译为读写穿透模式。该模式以缓存为主,数据库为辅。主要策略如下:

读请求

和旁路缓存模式类似,先查询缓存:1. 缓存中存在,直接返回;2. 缓存中不存在,缓存服务自动从数据库中读取数据写入缓存,然后返回。

和旁路缓存模式的区别就是,旁路缓存模式是我们手动写入缓存,而读写穿透模式是自动从数据库中读取数据并写入缓存。

读写穿透模式-读取数据

写请求

在写请求时,先查询缓存中存不存在:1. 不存在,直接写入数据库。2. 存在,先更新缓存,然后同步更新数据库。

读写穿透模式-写入数据

Write Behind Pattern

Write Behind Pattern 又称 Write Back 。类似于前面的 Read/Write Through Pattern,都是以缓存为主,数据库为辅。主要策略如下:

读请求

和 Read/Write Through Pattern 一样。

写请求

在写请求时,先查询缓存中存不存在:1. 不存在,直接写入数据库。2. 存在,先更新缓存,然后异步批量更新数据库。

这种模式写性能非常好,因为都是直接写缓存,但问题是数据不是强一致性的,还可能会导致数据丢失。适合一些数据经常变化又对数据一致性要求没那么高的场景,比如浏览量、点赞量。

回写模式-写入数据