美文网首页
缓冲更新策略

缓冲更新策略

作者: cartoony | 来源:发表于2022-06-06 22:52 被阅读0次

近段时间在学习缓存相关知识的时候,看到了缓存更新策略,于是就根据自己的理解,写下这篇文章

分类
  • Cache Aside
  • Read / Write Though
  • Write Behind
Cache Aside
  1. 步骤

    1. 读请求未命中缓存,取数据库数据,并回写缓存
    2. 写请求先更新数据库,再让缓存失效
  2. 优点

    1. 实现简单,调用者可控制数据持久化的细节
  3. 缺点

    1. 上层需要同时管理缓存与持久化,调用较复杂
    2. 写请求与读请求并发,读请求持续时间比写请求长,可能会覆盖旧数据到缓存中
  4. 使用场景

    1. 允许缓存数据不准确的场景
    2. 因为并发情况下,可能造成脏数据的情况,所以 QPS 较低场景也可以适用
  5. 代码示例

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<>();
    }
}
  1. 调用示例
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
  1. 步骤

    1. 读/写请求都只依赖缓存
    2. 缓存数据同步持久化
  2. 优点

    1. 上层对数据是否持久化/持久化实现无感
  3. 缺点

    1. 同步持久化性能较低,但能有效保证数据一致性
  4. 使用场景

    1. 性能要求不高的场景
  5. 代码示例

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<>();
    }
}
  1. 调用示例
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
  1. 步骤

    1. 读/写请求都只依赖缓存
    2. 缓存数据异步批量持久化
  2. 优点

    1. 上层对数据是否持久化/持久化实现无感
    2. 异步持久化,性能较 Read /Write Though 提高
  3. 缺点

    1. 异步持久化可能会导致数据丢失
  4. 使用场景

    1. 性能要求较高的场景
    2. 允许持久化数据丢失场景
  5. 代码示例

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());
    }

}
  1. 调用示例
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

相关文章

  • 缓冲更新策略

    近段时间在学习缓存相关知识的时候,看到了缓存更新策略,于是就根据自己的理解,写下这篇文章 分类 Cache Asi...

  • Android屏幕刷新机制

    3缓冲策略:在android4.1后提供了3缓冲策略。CPU GPU 和display各使用一个buffer。三缓...

  • 策略迭代(Policy Iteration)

    1. 策略迭代算法: 初始化.策略评估:(一般而言,下式中为固定策略由于策略更新)策略更新:如果与上次迭代相比没有...

  • 策略更新

    人民币最高6.97以来,一直强势升值,前天触及6.67,按照目前来看,6.60的时代不远了,甚至到6.51。 黄金...

  • 缓存问题

    一、缓存更新策略 一般情况来说,缓存更新策略有三种: 先删除缓存,后更新数据库 先更新数据库,后更新缓存 先更新数...

  • 播放器缓冲、同步策略

    1、缓冲策略 ffmpeg有自带缓存区,由于不对外暴露,无法很好的控制,经常出现播放花屏问题,当然我们可以修改源码...

  • EGL简介以及窗口初始化

    屏幕上可见的帧缓冲区由一个像素数据的二维数组表示。直接在可显示缓冲区上更新像素由一个严重的问题——用户在部分更新帧...

  • 缓冲区溢出的原因及危害

    这篇文章主要介绍缓冲区溢出的一些问题及应对策略。 什么是缓冲区溢出?大意就是为某特定的数据结构分配内存,然后修改内...

  • 交易策略更新

    今晚,绝地反击,从盘面可以看出,政府对于空头的忍耐极限,而且动作会快准狠,很快出手,有可能今晚到明天,人民币会升值...

  • 2018-10-29交易策略

    10月主推策略盈利: 原油策略获利1000点 黄金策略目前获利300点 磅日策略止盈200点 交易更新: 黄金:1...

网友评论

      本文标题:缓冲更新策略

      本文链接:https://www.haomeiwen.com/subject/pddsmrtx.html