旁路缓存模式(cache aside pattern)
旁路缓存中服务端需要同时更新数据库与缓存,并以数据库结果为准。适合读多写少的场景。
写:
- 更新数据库
- 删除缓存
读:
- 从缓存中读取数据
- 如果读取不到,就从数据库中读取
- 并将结果写入缓存
问题
在写的过程中,更新数据库后,为什么删除缓存,而不是更新缓存?
- 服务端资源浪费:缓存中存放的数据可能需要经过计算才能得出,如果在这个过程中缓存没有被读过,而又频繁的写,会造成资源的浪费。
- 数据不一致问题:并发场景下,更新缓存数据产生数据不一致的可能性更大。
在写时,为什么先更新数据库,后删除缓存?
首先,在速度上更新缓存速度 > 更新数据库,无论是先更新数据库还是先更新缓存,都会存在数据库与缓存数据不一致的情况。
先删除缓存,后更新数据库,那么数据库与缓存不一致的时间是是更新数据库的时间;
先更新数据库,后删除缓存,数据不一致的时间是删除缓存的时间;
因此,先更新数据库,后删除缓存,最小化了数据不一致时间
在数据强一致场景下,为了保证数据库与缓存数据的一致性,可以在更新时加锁来保证。
模式缺陷
写操作过多,会导致缓存频繁被删除,影响缓存命中率,需要导致频繁的从数据库中读取数据,影响读取效率。
业务场景
适用场景:
- 高读低写场景:数据读取频繁但更新不频繁,例如社交媒体用户资料、电子商务网站的商品详情页面等。用户会频繁查看这些数据,但数据的实际更改不频繁。
- 数据对一致性要求不高的场景:对数据的一致性要求不严格,允许在短时间内缓存和数据库之间存在数据不一致的情况。
- 缓存命中率不高的场景:对于一些查询频率较低的数据,使用旁路缓存可以避免在缓存中存储大量不常用的数据。
典型应用:
- 内容管理系统(CMS)
- 商品详情页、博客文章等不经常更新的数据
读写穿透模式(read/write through pattern)
在读写穿透模式下,服务端中将缓存视为主要存储点,从缓存中读取数据并写入,缓存服务写入数据库。
写:
- 读取缓存,如果缓存不存在,直接更新至数据库
- 如果缓存存在,更新缓存,缓存服务更新数据库
读:
- 从缓存中读取数据
- 如果缓存不存在,缓存服务从数据库中读取数据写入缓存,缓存服务返回数据
对应用程序来说,缓存与数据库的交互是透明的,应用程序只负责跟数据库交互,减轻应用程序责任。
业务场景
适用场景:
- 读多写少场景:数据读取操作远多于写入操作
- 数据一致性要求较高的场景:对数据的实时性和一致性要求高,不能容忍缓存和数据库之间存在不一致的情况,例如金融系统中的账户余额查询和更新。
- 缓存和数据库有统一管理需求的场景:需要简化应用程序代码,让缓存系统负责数据加载和持久化。
典型应用:
- 金融交易系统(如银行系统的账户余额)
- 电商库存管理
- 实时统计系统(如实时分析用户行为数据)
异步缓存写入模式(write behind pattern)
异步缓存写入与读写穿透模式相似,读写穿透模式是同步更新,异步缓存模式是异步批量更新数据库。
这种情况下读写性能高,适合经常变化且对数据一致性要求不高的场景,例如点赞数、播放数等。
模式缺陷
数据一致性差,存在还未更新至数据库,缓存服务直接挂掉的情况。