三种常见的缓存读写策略

旁路缓存模式(cache aside pattern)

旁路缓存中服务端需要同时更新数据库与缓存,并以数据库结果为准。适合读多写少的场景。

写:

  1. 更新数据库
  2. 删除缓存

读:

  1. 从缓存中读取数据
  2. 如果读取不到,就从数据库中读取
  3. 并将结果写入缓存

问题

在写的过程中,更新数据库后,为什么删除缓存,而不是更新缓存?

  1. 服务端资源浪费:缓存中存放的数据可能需要经过计算才能得出,如果在这个过程中缓存没有被读过,而又频繁的写,会造成资源的浪费。
  2. 数据不一致问题:并发场景下,更新缓存数据产生数据不一致的可能性更大。

在写时,为什么先更新数据库,后删除缓存?

首先,在速度上更新缓存速度 > 更新数据库,无论是先更新数据库还是先更新缓存,都会存在数据库与缓存数据不一致的情况。

先删除缓存,后更新数据库,那么数据库与缓存不一致的时间是是更新数据库的时间;

先更新数据库,后删除缓存,数据不一致的时间是删除缓存的时间;

因此,先更新数据库,后删除缓存,最小化了数据不一致时间

在数据强一致场景下,为了保证数据库与缓存数据的一致性,可以在更新时加锁来保证。

模式缺陷

写操作过多,会导致缓存频繁被删除,影响缓存命中率,需要导致频繁的从数据库中读取数据,影响读取效率。

业务场景

适用场景:

  • 高读低写场景:数据读取频繁但更新不频繁,例如社交媒体用户资料、电子商务网站的商品详情页面等。用户会频繁查看这些数据,但数据的实际更改不频繁。
  • 数据对一致性要求不高的场景:对数据的一致性要求不严格,允许在短时间内缓存和数据库之间存在数据不一致的情况。
  • 缓存命中率不高的场景:对于一些查询频率较低的数据,使用旁路缓存可以避免在缓存中存储大量不常用的数据。

典型应用:

  • 内容管理系统(CMS)
  • 商品详情页、博客文章等不经常更新的数据

读写穿透模式(read/write through pattern)

在读写穿透模式下,服务端中将缓存视为主要存储点,从缓存中读取数据并写入,缓存服务写入数据库。

写:

  1. 读取缓存,如果缓存不存在,直接更新至数据库
  2. 如果缓存存在,更新缓存,缓存服务更新数据库

读:

  1. 从缓存中读取数据
  2. 如果缓存不存在,缓存服务从数据库中读取数据写入缓存,缓存服务返回数据

对应用程序来说,缓存与数据库的交互是透明的,应用程序只负责跟数据库交互,减轻应用程序责任。

业务场景

适用场景:

  • 读多写少场景:数据读取操作远多于写入操作
  • 数据一致性要求较高的场景:对数据的实时性和一致性要求高,不能容忍缓存和数据库之间存在不一致的情况,例如金融系统中的账户余额查询和更新。
  • 缓存和数据库有统一管理需求的场景:需要简化应用程序代码,让缓存系统负责数据加载和持久化。

典型应用:

  • 金融交易系统(如银行系统的账户余额)
  • 电商库存管理
  • 实时统计系统(如实时分析用户行为数据)

异步缓存写入模式(write behind pattern)

异步缓存写入与读写穿透模式相似,读写穿透模式是同步更新,异步缓存模式是异步批量更新数据库。

这种情况下读写性能高,适合经常变化且对数据一致性要求不高的场景,例如点赞数、播放数等。

模式缺陷

数据一致性差,存在还未更新至数据库,缓存服务直接挂掉的情况。