Cache Aside(旁路缓存)策略

读策略为:

  • 从缓存中读取数据,命中则直接返回
  • 缓存未命中,则从数据库查询,然后写入缓存,并返回给用户

写策略为:

  • 更新数据库中的数据
  • 删除缓存的数据

先删除缓存再删数据或者先删数据库再删除缓存都会导致一定的问题,分析比较简单,不做具体说明。

存在的问题

如果新注册了一个用户,然后立刻发起了查询(此时缓存无法命中),如果查询走的是从库,而且存在一定的时延,那么会有可能查询不到个人信息。

解决办法就是在特定的场景下,我们可以修改后将修改的信息写入缓存当中,而不是删除。

而且该策略对于频繁的修改会导致缓存中的数据被频繁的清理,造成缓存命中率低。

两种解决办法:

  1. 一种做法是在更新数据时也更新缓存,只是在更新缓存前先加一个分布式锁,因为这样在同一时间只允许一个线程更新缓存,就不会产生并发问题了。当然这么做对于写入的性能会有一些影响;

  2. 另一种做法同样也是在更新数据时更新缓存,只是给缓存加一个较短的过期时间,这样即使出现缓存不一致的情况,缓存的数据也会很快过期,对业务的影响也是可以接受。

Read/Write Through(读穿 / 写穿)策略

这个策略的核心原则是用户只与缓存打交道,由缓存和数据库通信,写入或者读取数据。

Write Through 的策略是这样的:先查询要写入的数据在缓存中是否已经存在,如果已经存在,则更新缓存中的数据,并且由缓存组件同步更新到数据库中,如果缓存中数据不存在,我们把这种情况叫做“Write Miss(写失效)”。

如果发生写失效,则解决办法有以下两种:

  • Write Allocate(按写分配):写入缓存相应位置,再由缓存组件同步更新到数据库中;
  • No-write allocate(不按写分配):不写入缓存中,而是直接更新到数据库中。

Read Through 策略就简单一些,它的步骤是这样的:先查询缓存中数据是否存在,如果存在则直接返回,如果不存在,则由缓存组件负责从数据库中同步加载数据。

Write Back(写回)策略

这个策略的核心思想是在写入数据时只写入缓存,并且把缓存块儿标记为“脏”的。而脏块儿只有被再次使用时才会将其中的数据写入到后端存储中。

image-20230430194034299

如果使用 Write Back 策略的话,读的策略也有一些变化了。

我们在读取缓存时如果发现缓存命中则直接返回缓存数据。

如果缓存不命中则寻找一个可用的缓存块儿,如果这个缓存块儿是“脏”的,就把缓存块儿中之前的数据写入到后端存储中,并且从后端存储加载数据到缓存块儿。

如果不是脏的,则由缓存组件将后端存储中的数据加载到缓存中,最后我们将缓存设置为不是脏的,返回数据就好了。

这个策略一般不直接在生产环境中使用,往往是计算机结构中使用,比如说操作系统层面的 Page Cache,日志的异步刷盘,消息队列中消息的异步写入磁盘等。

参考

《高并发系统设计》