当前位置: 首页 > news >正文

CoAlbum:多级缓存与性能对比

目录

Target

1.多级缓存生效注解

2.缓存上下文

3.责任链

Hander接口

责任链初始化

5.切面Aop

Coalbum项目

使用缓存

性能对比

Jmeter tips


Target

Caffeine+Redis构建多级缓存,采用责任链模式,使用aop+注解的方式增强目标方法。若缓存命中,返回命中值。若没命中,执行目标方法,将目标方法返回值依次存入缓存链。

1.多级缓存生效注解

/*** 多级缓存生效注解*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface CacheableMultiLevel {String keyPrefix() default "";// key 前缀String key() default "";  // 缓存key,空key则计算hashint localExpireSeconds() default 60; // 本地缓存过期时间(秒)int redisExpireSeconds() default 300; // redis缓存过期时间(秒)}

2.缓存上下文

/*** 通用缓存上下文:CacheContext*/
@Data
public class CacheContext {private final String cacheKey;  // 当前查询的缓存 keyprivate String cachedValue;     // 当前 handler 返回的缓存值,命中则填充private boolean hit = false;    // 是否命中缓存public void setCachedValue(String cachedValue) {this.cachedValue = cachedValue;this.hit = true;}
}

3.责任链

Hander接口

Caffeine忽略expireSeconds,无法指定各key的过期时间

RedisCacheHandler 设置expireSeconds+ RandomUtil.randomInt(0, 300) 防止缓存雪崩

put方法中 应链式调用 下级缓存的 put 方法

/*** 责任链接口:CacheHandler*/
public interface CacheHandler {/*** 尝试从当前缓存层获取数据* @param context 缓存上下文,包含 key 和结果* @return 如果命中缓存,设置 context.cachedValue 并返回 true;否则返回 false*/boolean handle(CacheContext context);void setNext(CacheHandler next);void put(String key, String jsonValue, int expireSeconds);
}

责任链初始化

@Component
public class CacheHandlerChain {@Autowired(required = false)private LocalCacheHandler localCacheHandler;@Autowired(required = false)private RedisCacheHandler redisCacheHandler;@Autowired(required = false)private DefaultCacheHandler defaultCacheHandler;@Getterprivate CacheHandler chain;@PostConstructpublic void init() {List<CacheHandler> handlers = new ArrayList<>();if (localCacheHandler != null) handlers.add(localCacheHandler);if (redisCacheHandler != null) handlers.add(redisCacheHandler);if (defaultCacheHandler != null) handlers.add(defaultCacheHandler);for (int i = 0; i < handlers.size() - 1; i++) {handlers.get(i).setNext(handlers.get(i + 1));}this.chain = handlers.isEmpty() ? defaultCacheHandler : handlers.get(0);}}

5.切面Aop

优先使用注解中指定的key,为指定则计算方法参数的hash 作为key

  1. 命中,将json字符串反序列化为returnType类型的对象
  2. 未命中,目标方法执行后,将返回对象转为json字符串存入链中的各级缓存

TODO:解决缓存击穿,避免缓存突然失效导致 ES 压力飙升

@Aspect
@Component
public class CacheableAspect {@Autowiredprivate CacheHandlerChain cacheHandlerChain;@Around("@annotation(cacheableMultiLevel)")public Object around(ProceedingJoinPoint joinPoint, CacheableMultiLevel cacheableMultiLevel) throws Throwable {String key = cacheableMultiLevel.key();if(StrUtil.isBlank(key)){//未指定key,使用hash值作为keyObject[] args = joinPoint.getArgs();String argJson = JSON.toJSONString(args);key = DigestUtils.md5DigestAsHex(argJson.getBytes());}String cacheKey = cacheableMultiLevel.keyPrefix()+key;CacheContext context = new CacheContext(cacheKey);CacheHandler chain = cacheHandlerChain.getChain();boolean hit = chain.handle(context);// 获取方法签名MethodSignature signature = (MethodSignature) joinPoint.getSignature();// 获取目标方法对象java.lang.reflect.Method method = signature.getMethod(); // 或 getDeclaredMethod()Class<?> returnType = method.getReturnType();if (hit) {System.out.println("[AOP] 缓存命中,直接返回");return JSON.parseObject(context.getCachedValue(),returnType); // 命中则直接返回}// 未命中,放行目标方法,由方法自己查数据源并写入缓存System.out.println("[AOP] 缓存未命中,放行目标方法");Object res = joinPoint.proceed();String json = JSON.toJSONString(res);chain.put(cacheKey,json,cacheableMultiLevel.redisExpireSeconds());return res;}}

Coalbum项目

使用缓存

主页图片分页查询

    /*** ES作为数据源*/@PostMapping("/list/page/vo/search")@SaSpaceCheckPermission(value = SpaceUserPermissionConstant.PICTURE_VIEW)@CacheableMultiLevel(keyPrefix = "coalbum:listPictureVOByPage:",redisExpireSeconds =300)public BaseResponse<Page<PictureVO>> listPictureVOByPageFromES(@RequestBody PictureQueryRequest pictureQueryRequest) {try {//TODO 权限校验//TODO 解决缓存击穿,避免缓存突然失效导致 ES 压力飙升return ResultUtils.success(pictureSearchService.searchPicture(pictureQueryRequest));} catch (IOException e) {throw new BusinessException(ErrorCode.SYSTEM_ERROR);}}

性能对比

线程数:50 ;second:1

ES直查:平均响应时间 30 ms

使用多级缓存:平均接口响应时间 14 ms

性能提升50%

Jmeter tips

请求头 携带cookies

http://www.dtcms.com/a/520538.html

相关文章:

  • 【算法专题训练】27、树的层序遍历
  • 网站导入wordpress基层建设是哪个网站的
  • 第6章—手动移植创建STM32工程
  • Android Bluetooth 蓝牙通信
  • 简述一般网站开发方式广州三合一企业网站哪家好
  • 网站建设邀标函专业的外贸建站公司
  • C++ STL(标准模板库)深度解析:从基础到实践
  • 压缩与缓存调优实战指南:从0到1根治性能瓶颈(二)
  • Linux小课堂: SSH 配置文件详解之全局与局部 Config 文件的语义梳理与技术深化
  • 6-2〔O҉S҉C҉P҉ ◈ 研记〕❘ 客户端攻击▸利用WORD宏让客户端执行命令
  • 网站页面设计报价xampp做网站设置
  • 制作 网站 盈利怎么看网站到期时间
  • Qt6.10 | Qt Bluetooth 蓝牙
  • 网站自动化开发无极官方网站下载
  • 基于 docker compose 进行部署PandaWiki
  • 哪里建设网站设计服务
  • Python - 100天从新手到大师:第五十八天 Python中的并发编程(1-3)
  • C语言-动态内存分配
  • 多个PDF文档如何批量删除页眉处的多余信息
  • 网站服务器空间大小网站自适应宽度
  • 静态网站什么样做个简单的网站
  • EtherCAT转EtherNet/IP工业PLC网关:实现PLC与底层设备的无缝协同控制
  • 群晖边缘存储方案,让数据更近、更快、更安全
  • Python电力负荷预测:LSTM、GRU、DeepAR、XGBoost、Stacking、ARIMA结合多源数据融合与SHAP可解释性的研究
  • 做网站送的小程序有什么用多多进宝怎么推广赚钱
  • 做彩票类网站用什么服务器图片生成二维码软件
  • 机器学习(7)逻辑回归及其成本函数
  • 计算机视觉六大前沿创新方向
  • 加网络网站建设工作室医院网站规划方案
  • 流量型网站 cms西安网站建设高端