前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Cache-Aside Pattern

Cache-Aside Pattern

作者头像
张申傲
发布2020-09-03 15:55:54
7330
发布2020-09-03 15:55:54
举报
文章被收录于专栏:漫漫架构路漫漫架构路

Cache-Aside Pattern

一. 背景和问题

缓存已经成为了几乎所有应用系统的必备要素。使用缓存可以有效提高系统的读性能,相比于直接读取数据库,吞吐量有了很大的提高。但是,在实际生产环境中,很难保证缓存与数据库中数据的完全一致。程序应采取某种策略,尽可能地保证缓存中的数据是最新的,并且可以检测到缓存中数据失效,并提供相应的解决方案。

简单来说,Cache-Aside Pattern的提出是为了尽可能地解决缓存与数据库的数据不一致问题。

二. 解决方案

大多数的商用缓存系统都提供了下面的功能:

  1. 访问数据时,首先尝试从缓存中获取。如果缓存命中,则直接返回。
  2. 如果缓存未命中,则查询数据库。
  3. 将从数据库中查询到的结果放入缓存中,并返回。
  4. 缓存中任何数据的更新,都会自动同步到数据库。

如果所使用的缓存没有提供这些功能,则需要应用系统自己去实现,实现时就可以基于Cache-Aside Pattern。

三. Cache-Aside Pattern

Cache-Aside Pattern分为读操作和写操作两种。

  1. 读操作 原理如下图:
在这里插入图片描述
在这里插入图片描述

流程:

  1. 首先从缓存中查询数据,如果缓存命中则直接返回。
  2. 缓存未命中,则去数据库中读取。
  3. 将从数据库中读取的结果的副本放入到缓存中,并返回。
  4. 写操作 流程:
    1. 首先更新数据库。
    2. 然后删除缓存中的数据

四. 一些思考

  1. 为什么是删除缓存,而不是更新缓存?主要基于以下两点考量:
    1. 数据更新后,可能不会有大量的访问。如果每次更新数据后都更新缓存,可能会造成大量不必要的计算开销。因此,这里采用一种lazy的思想,每次更新数据时仅仅是删除缓存,只有在真正读请求到来时才进行缓存的更新。
    2. 在高并发场景下,并发地更新缓存可能会造成缓存可数据库中数据不一致的问题。
  2. 写操作的流程十分关键!一定要先更新数据库,再删除缓存。如果先删除缓存,就会存在一个很小的窗口期,使得客户端查询时无法命中缓存,而去读数据库,然而此时数据库中的数据还未更新,就会从数据库中加载到旧的数据并放入缓存中,最终导致缓存数据被污染。
  3. 缓存的过期策略 许多缓存系统都会对缓存数据设置一定的过期策略。使用Cache-Aside Pattern时,一定要合理地设置过期策略。如果过期时间太短,可能导致大量请求涌入数据库。相反,如果过期时间太长,有可能导致缓存中数据的大量失效。使用缓存的一个原则,就是尽量缓存那些相对静态的、频繁被读取的数据。
  4. **Cache-Aside Pattern并无法完全保证数据库和缓存的数据一致性。**当某条数据被修改时,在数据库中会立即更新,但是缓存中的更新会在下次读取数据时才会发生,

五. 应用场景

  1. 适用场景:
    1. 应用程序所使用的缓存系统并没有提供前文所述的缓存系统的那些功能。
    2. 加载资源的需求是不可预测的。该模式使得系统可以按需加载数据,而不需提前预设哪些数据可能需要被获取。
  2. 不适用场景: 所缓存的数据集是静态的。

六. 使用示例

代码语言:javascript
复制
/**
 * @Author: ZhangShenao
 * @Date: 2019/5/15 11:07
 * @Description:演示Cache-Aside Pattern
 */
@Service
public class CacheAsidePatternService {
  @Autowired
  private CacheService cacheService;

  @Autowired
  private DataDao dataDao;

  //读操作
  public Data getData(String key) {
    //1. 读缓存,如果命中则直接返回
    Data data = cacheService.loadDataFromCache(key);
    if (data != null) {
      return data;
    }

    //2. 缓存未命中,读数据库
    data = dataDao.loadDataFromDB(key);

    //3. 将读取到的数据放入缓存
    cacheService.putData(key,data);

    return data;
  }

  //写操作
  public void updateData(String key,Data data){
    //1. 更新数据库
    dataDao.updateData(key, data);

    //2. 删除缓存
    cacheService.evictData(key);
  }
}

七. 参考资料

  1. https://docs.microsoft.com/en-us/azure/architecture/patterns/cache-aside
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019-05-15 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Cache-Aside Pattern
    • 一. 背景和问题
      • 二. 解决方案
        • 三. Cache-Aside Pattern
          • 四. 一些思考
            • 五. 应用场景
              • 六. 使用示例
                • 七. 参考资料
                相关产品与服务
                数据库
                云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
                领券
                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档