共计 5393 个字符,预计需要花费 14 分钟才能阅读完成。
近段时间在学习缓存相干常识的时候,看到了缓存更新策略,于是就依据本人的了解,写下这篇文章
分类
- 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. 写申请与读申请并发,读申请持续时间比写申请长,可能会笼罩旧数据到缓存中 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
正文完