近段时间在学习缓存相关知识的时候,看到了缓存更新策略,于是就根据自己的理解,写下这篇文章
分类
- Cache Aside
- Read / Write Though
- Write Behind
Cache Aside
-
步骤
- 读请求未命中缓存,取数据库数据,并回写缓存
- 写请求先更新数据库,再让缓存失效
-
优点
- 实现简单,调用者可控制数据持久化的细节
-
缺点
- 上层需要同时管理缓存与持久化,调用较复杂
- 写请求与读请求并发,读请求持续时间比写请求长,可能会覆盖旧数据到缓存中
-
使用场景
- 允许缓存数据不准确的场景
- 因为并发情况下,可能造成脏数据的情况,所以 QPS 较低场景也可以适用
-
代码示例
public class CacheAside<T, K> implements CacheUpdate<T, K>{
private Map<K, T> map;
@Override
public T getData(K key) {
//if cache has data, return
return map.get(key);
}
@Override
public boolean updateData(K key, T data) {
map.remove(key, data);
return true;
}
@Override
public boolean addData(K key, T data) {
return Objects.nonNull(map.put(key, data));
}
@Override
public boolean removeData(K key) {
map.remove(key);
return true;
}
public CacheAside() {
map = new HashMap<>();
}
}
- 调用示例
public class CacheAsideClient<T, K> implements CacheUpdateClient<T, K>{
public CacheUpdateFactory<T, K> factory = CacheUpdateFactory.getInstance();
private CacheUpdate<T, K> cacheUpdate;
private DatabaseOperation<T, K> databaseOperation;
@Override
public T getData(K key){
//get data from cache
T dataFromCache = cacheUpdate.getData(key);
//if cache haven't, get from database and put to cache
if(Objects.nonNull(dataFromCache)){
return dataFromCache;
}
T dataFromDatabase = databaseOperation.getData(key);
cacheUpdate.addData(key, dataFromDatabase);
return dataFromDatabase;
}
@Override
public boolean updateData(K key, T data){
//update data to database
boolean updateToDatabaseRes = databaseOperation.updateData(key, data);
if(updateToDatabaseRes){
//invalid cache data
return cacheUpdate.removeData(key);
}
return false;
}
@Override
public boolean addData(K key, T data){
//add data to database
return databaseOperation.addData(key, data);
}
@Override
public boolean removeData(K key){
//remove from database
boolean removeFromDatabaseRes = databaseOperation.removeData(key);
if(removeFromDatabaseRes){
//invalid cache data
return cacheUpdate.removeData(key);
}
return false;
}
public CacheAsideClient() {
cacheUpdate = factory.getObject(CacheUpdateEnum.CACHE_ASIDE);
databaseOperation = (DatabaseOperation<T, K>) new MockDatabaseOperation<T>();
}
}
Read / Write Though
-
步骤
- 读/写请求都只依赖缓存
- 缓存数据同步持久化
-
优点
- 上层对数据是否持久化/持久化实现无感
-
缺点
- 同步持久化性能较低,但能有效保证数据一致性
-
使用场景
- 性能要求不高的场景
-
代码示例
public class ReadOrWriteThough<T, K> implements CacheUpdate<T, K>{
private DatabaseOperation<T, K> databaseOperation;
private Map<K, T> map;
@Override
public T getData(K key) {
//if cache has data, return
if(map.containsKey(key)){
return map.get(key);
}
//get data from database and write to cache
T data = databaseOperation.getData(key);
map.put(key, data);
return data;
}
@Override
public boolean updateData(K key, T data) {
map.put(key, data);
return databaseOperation.updateData(key, data);
}
@Override
public boolean addData(K key, T data) {
map.put(key, data);
return databaseOperation.addData(key, data);
}
@Override
public boolean removeData(K key) {
map.remove(key);
return databaseOperation.removeData(key);
}
public ReadOrWriteThough() {
databaseOperation = (DatabaseOperation<T, K>) new MockDatabaseOperation<>();
map = new HashMap<>();
}
}
- 调用示例
public class ReadOrWriteThoughClient<T, K> implements CacheUpdateClient<T, K>{
private CacheUpdateFactory<T, K> factory = CacheUpdateFactory.getInstance();
private CacheUpdate<T, K> cacheUpdate;
@Override
public T getData(K key) {
return cacheUpdate.getData(key);
}
@Override
public boolean updateData(K key, T data) {
return cacheUpdate.updateData(key, data);
}
@Override
public boolean addData(K key, T data) {
return cacheUpdate.addData(key, data);
}
@Override
public boolean removeData(K key) {
return cacheUpdate.removeData(key);
}
public ReadOrWriteThoughClient() {
cacheUpdate = factory.getObject(CacheUpdateEnum.READ_WRITE_THOUGH);
}
}
Write Behind
-
步骤
- 读/写请求都只依赖缓存
- 缓存数据异步批量持久化
-
优点
- 上层对数据是否持久化/持久化实现无感
- 异步持久化,性能较 Read /Write Though 提高
-
缺点
- 异步持久化可能会导致数据丢失
-
使用场景
- 性能要求较高的场景
- 允许持久化数据丢失场景
-
代码示例
public class WriteBehind<T, K> implements CacheUpdate<T, K> {
private Map<K, T> map;
private DatabaseOperation<T, K> databaseOperation;
private ThreadPoolExecutor threadPoolExecutor;
@Override
public T getData(K key) {
if(map.containsKey(key)){
return map.get(key);
}
T data = databaseOperation.getData(key);
map.put(key, data);
return data;
}
@Override
public boolean updateData(K key, T data) {
map.put(key, data);
threadPoolExecutor.execute(() -> databaseOperation.updateData(key, data));
return true;
}
@Override
public boolean addData(K key, T data) {
map.put(key, data);
threadPoolExecutor.execute(() -> databaseOperation.addData(key, data));
return true;
}
@Override
public boolean removeData(K key) {
map.remove(key);
threadPoolExecutor.execute(() -> databaseOperation.removeData(key));
return true;
}
public WriteBehind() {
map = new HashMap<>();
databaseOperation = (DatabaseOperation<T, K>) new MockDatabaseOperation<>();
threadPoolExecutor = new ThreadPoolExecutor(5, 10, 1000, TimeUnit.SECONDS, new ArrayBlockingQueue<>(1000), new ThreadPoolExecutor.CallerRunsPolicy());
}
}
- 调用示例
public class WriteBehindClient<T, K> implements CacheUpdateClient<T, K>{
private CacheUpdateFactory<T, K> cacheUpdateFactory = CacheUpdateFactory.getInstance();
private CacheUpdate<T, K> cacheUpdate;
@Override
public T getData(K key) {
return cacheUpdate.getData(key);
}
@Override
public boolean updateData(K key, T data) {
return cacheUpdate.updateData(key, data);
}
@Override
public boolean addData(K key, T data) {
return cacheUpdate.addData(key, data);
}
@Override
public boolean removeData(K key) {
return cacheUpdate.removeData(key);
}
public WriteBehindClient() {
cacheUpdate = cacheUpdateFactory.getObject(CacheUpdateEnum.WRITE_BEHIND);
}
}
总结
分类 | 优点 | 缺点 | 使用场景 |
---|---|---|---|
Cache Aside | 1. 实现简单,调用者可控制数据持久化的细节 | 1. 写请求与读请求并发,读请求持续时间比写请求长,可能会覆盖旧数据到缓存中<br />2. 上层需要同时管理缓存与持久化,调用较复杂 | 1. 允许缓存数据不准确的场景<br />2. 因为并发情况下,可能造成脏数据的情况,所以 QPS 较低场景也可以适用 |
Read / Write Though | 1. 上层对数据是否持久化/持久化实现无感 | 1. 同步持久化性能较低,但能有效保证数据一致性 | 1. 性能要求不高的场景 |
Write Behind | 1. 上层对数据是否持久化/持久化实现无感<br />2. 异步持久化,性能较 Read /Write Though 提高 | 1. 异步持久化可能会导致数据丢失 | 1. 性能要求较高的场景<br />2. 允许持久化数据丢失场景 |
本文首发于cartoon的博客
转载请注明出处:https://cartoonyu.github.io
网友评论