综合技术交流
直播中

ss

7年用户 8762经验值
擅长:电源/新能源 制造/封装 RF/无线
私信 关注
[经验]

缓存的作用和设计模式

1、缓存的作用在业务系统中,查询时最容易出现性能问题的模块,查询面对的数据量大,筛选条件复杂,所以在系统架构中引入缓存层,则是非常必要的,用来缓存热点数据,达到快速响应的目的。
缓存使用的基本原则:
  • 所有缓存数据,必须设置过期时间;
  • 核心业务流程不通过缓存层;
  • 缓存层移除,不影响现有流程;
  • 系统各个端首页数据不实时查询;
  • 报表数据不实时查询加载;
  • 归档数据(定时统计的结果数据)不实时查询;
这里是业务架构中常用的缓存策略,缓存通过牺牲强一致性来提高性能,所以并不是所有的业务都适合用缓存,实际考量都会针对具体的业务,比如用户相关维度的数据修改频率低,会使用缓存,但是用户权限数据(比如:免费次数)会考虑实时校验,缓存层使用的相对较少。
2、缓存设计模式Cache-Aside模式
业务中最常用的缓存层设计模式,基本实现逻辑和相关概念如下:
1.png
  • 缓存命中:直接查询缓存且命中,返回数据;
  • 缓存加载:查询缓存未命中,从数据库中查询数据,获取数据后并加载到缓存;
  • 缓存失效:数据更新写到数据库,操作成功后,让缓存失效,查询时候再重新加载;
  • 缓存穿透:查询数据库不存在的对象,也就不存在缓存层的命中;
  • 缓存击穿:热点key在失效的瞬间,高并发查询这个key,击穿缓存,直接请求数据库;
  • 缓存雪崩:缓存Key大批量到过期时间,导致数据库压力过大;
  • 命中率:缓存设计的是否合理要看命中率,命中率高说明缓存有效抗住了大部分请求,命中率可以通过Redis监控信息计算,一般来说命中率在(70-80)%都算合理。
    并发问题
执行读操作未命中缓存,然后查询数据库中取数据,数据已经查询到还没放入缓存,同时一个更新写操作让缓存失效,然后读操作再把查询到数据加载缓存,导致缓存的脏数据。
在遵守缓存使用原则下出现该情况概率非常低,可以通过复杂的Paxos协议保证一致性,一般情况是不考量该场景的处理,如果缓存管理过于复杂,会和缓存层核心理念相悖。
基本描述代码:
  • @Service
  • public class KeyValueServiceImpl extends ServiceImpltity> implements KeyValueService {
  •     @Resource
  •     private RedisService redisService ;
  •     @Override
  •     public KeyValueEntity select(Integer id) {
  •         // 查询缓存
  •         String redisKey = RedisKeyUtil.getObectKey(id) ;
  •         String value = redisService.get(redisKey) ;
  •         if (!StringUtils.isEmpty(value) && !value.equals("null")){
  •             return JSON.parseObject(value,KeyValueEntity.class);
  •         }
  •         // 查询库
  •         KeyValueEntity keyValueEntity = this.getById(id) ;
  •         if (keyValueEntity != null){
  •             // 缓存写入
  •             redisService.set(redisKey,JSON.toJSONString(keyValueEntity)) ;
  •         }
  •         // 返回值
  •         return keyValueEntity ;
  •     }
  •     @Override
  •     public boolean update(KeyValueEntity keyValueEntity) {
  •         // 更新数据
  •         boolean updateFlag = this.updateById(keyValueEntity) ;
  •         // 清除缓存
  •         if (updateFlag){
  •             redisService.delete(RedisKeyUtil.getObectKey(keyValueEntity.getId()));
  •         }
  •         return updateFlag ;
  •     }
  • }
Read-Throug模式
当应用系统向缓存系统请求数据时,如果缓存中并没有对应的数据存在,缓存系统将向底层数据源的读取数据。如果数据在缓存中存在,则直接返回缓存中存在的数据。把更新数据库的操作由缓存层代劳了。
Write-Through模式
更新写数据时,如果没有命中缓存,则直接更新数据库,如果命中了缓存,则先更新缓存,然后由缓存系统自行更新数据库。
Write-Behind模式
应用系统对缓存中的数据进行更新时,只更新缓存,不更新数据库,缓存系统会异步批量向底层数据源更新数据。

更多回帖

发帖
×
20
完善资料,
赚取积分