近段时间在学习缓存相关知识的时候,看到了缓存更新策略,于是就根据自己的理解,写下这篇文章
分类
- Cache Aside
- Read / Write Though
- Write Behind
Cache Aside
步骤
- 读请求未命中缓存,取数据库数据,并回写缓存
- 写请求先更新数据库,再让缓存失效
优点
- 实现简单,调用者可控制数据持久化的细节
缺点
- 上层需要同时管理缓存与持久化,调用较复杂
- 写请求与读请求并发,读请求持续时间比写请求长,可能会覆盖旧数据到缓存中
使用场景
- 允许缓存数据不准确的场景
- 因为并发情况下,可能造成脏数据的情况,所以 QPS 较低场景也可以适用
代码示例
1 | public class CacheAside<T, K> implements CacheUpdate<T, K>{ |
- 调用示例
1 | public class CacheAsideClient<T, K> implements CacheUpdateClient<T, K>{ |
Read / Write Though
步骤
- 读/写请求都只依赖缓存
- 缓存数据同步持久化
优点
- 上层对数据是否持久化/持久化实现无感
缺点
- 同步持久化性能较低,但能有效保证数据一致性
使用场景
- 性能要求不高的场景
代码示例
1 | public class ReadOrWriteThough<T, K> implements CacheUpdate<T, K>{ |
- 调用示例
1 | public class ReadOrWriteThoughClient<T, K> implements CacheUpdateClient<T, K>{ |
Write Behind
步骤
- 读/写请求都只依赖缓存
- 缓存数据异步批量持久化
优点
- 上层对数据是否持久化/持久化实现无感
- 异步持久化,性能较 Read /Write Though 提高
缺点
- 异步持久化可能会导致数据丢失
使用场景
- 性能要求较高的场景
- 允许持久化数据丢失场景
代码示例
1 | public class WriteBehind<T, K> implements CacheUpdate<T, K> { |
- 调用示例
1 | public class WriteBehindClient<T, K> implements CacheUpdateClient<T, K>{ |
总结
分类 | 优点 | 缺点 | 使用场景 |
---|---|---|---|
Cache Aside | 1. 实现简单,调用者可控制数据持久化的细节 | 1. 写请求与读请求并发,读请求持续时间比写请求长,可能会覆盖旧数据到缓存中 2. 上层需要同时管理缓存与持久化,调用较复杂 |
1. 允许缓存数据不准确的场景 2. 因为并发情况下,可能造成脏数据的情况,所以 QPS 较低场景也可以适用 |
Read / Write Though | 1. 上层对数据是否持久化/持久化实现无感 | 1. 同步持久化性能较低,但能有效保证数据一致性 | 1. 性能要求不高的场景 |
Write Behind | 1. 上层对数据是否持久化/持久化实现无感 2. 异步持久化,性能较 Read /Write Though 提高 |
1. 异步持久化可能会导致数据丢失 | 1. 性能要求较高的场景 2. 允许持久化数据丢失场景 |
本文首发于cartoon的博客
转载请注明出处:https://cartoonyu.github.io