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

Spring-Cache替换Keys为Scan—负优化?

背景

使用ORM工具是往往会配合缓存框架实现三级缓存提高查询效率,spring-cache配合redis是非常常规的实现方案,如未做特殊配置,@CacheEvict(allEntries = true) 的批量驱逐方式,默认使用keys的方式查询历史缓存列表而后delete,而keys是阻塞式的命令,cache的dbsize越大,效率越低进而形成redis慢查询。而使用scan增量式迭代指令,配合自动游标批量扫描缓存匹配的缓存key,是一种非阻塞的方案,一般认为更适合用于大规模数据集的遍历,因为它不会像 keys 那样一次性加载所有的键,可能在性能上更具优势。

现状

某项目线上积累数据缓存80万个key,使用spring-cache(2.7.x)+redis(6.0)作为缓存框架,redis监控中,频繁出现keys慢日志

问题

改造springboot-cache配置,将keys替换为scan,貌似是一种替代keys减少慢日志的最优解,那到底能否提高效率呢,或者能否带来其他改变?

结论

在一定数据量的缓存系统中,如本系统dbsize为80万左右,使用scan替换keys能显著减少redis慢日志,但让redis的cpu骤增。这使得系统应对突发问题时会变得更加脆弱,优化显得入不敷出。

实践

更新方法

多数AI的QA或者线上搜索的"替换springboot-cache keys指令为scan"实现方式都是片面的,为什么呢,也许现实证明确实没有必要这么更新所以答案就更加模糊。当然了,实践是检验真理的唯一标准,我们尝试一下更新。(spring-boot-starter-data-redis version=2.7.x)

@Slf4j
@Configuration
@EnableCaching
@ConditionalOnClass(RedisOperations.class)
@EnableConfigurationProperties(RedisProperties.class)
public class RedisConfig extends CachingConfigurerSupport { //其他@Override和@Bean参考网络或自己实现// ……/*** 配置一个CacheManager才能使用@Cacheable等注解*/@Beanpublic CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {log.info("cacheManager(RedisConnectionFactory redisConnectionFactory):" + redisConnectionFactory);return RedisCacheManager.RedisCacheManagerBuilder.fromConnectionFactory(redisConnectionFactory)// 全局缓存配置.cacheDefaults(redisCacheConfiguration(20 * 60))// 指定特殊缓存过期时间.withCacheConfiguration("sys:config", redisCacheConfiguration(7 * 60))//指定scan匹配key作为驱逐查询方式               .cacheWriter(RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory, BatchStrategies.scan(5000))).transactionAware().build();}}

重点改动就在于这里的nonLockingRedisCacheWriter,至于scan的size=5000,是一个权衡的考虑,设置10000时,实践发现库够大时scan的速度较慢,可能超过20毫秒;设置过小,游标搜索次数又会明显增多,所以没有一个合理的选择。

主要就是定义这个CacheManager然后必须加入cacheWriter,根本不需要单独写Writer复杂实现或者仅写个Writer实现也不在CacheManager中配置(都没配置关联上怎么可能生效)。

验证更新后的指令执行日志如下(观察sys:setting::*):

#之前
1745380521.036415 [2 192.1.5.172:57514] GET aodc:to-client
1745380521.044084 [0 192.1.5.165:49754] GET aodc:to-client
1745380521.118468 [0 192.1.5.145:64743] KEYS sys:setting::*
1745380521.122180 [0 192.1.5.145:64743] DEL sys:setting::get-values-by-name:ces_equipment_code_blacklist sys:setting::get-value-by-name:hex_msg_for_equipment_list
1745380521.130366 [0 192.1.5.145:64743] HGET user:online-info \xe9\x99\x88\xe6\xac\xa3\xe6\xac\xa3
1745380521.134822 [0 192.1.5.145:64743] HGET user:online-info \xe9\x99\x88\xe6\xac\xa3\xe6\xac\xa3
1745380521.140906 [2 192.1.5.172:57514] GET aodc:to-client
#之后
1745381648.269224 [2 192.1.5.172:57514] SCAN 462 MATCH ocpp:to-equip:*
1745381648.270222 [2 192.1.5.172:57514] SCAN 158 MATCH ocpp:to-equip:*
1745381648.271283 [2 192.1.5.172:57514] SCAN 830 MATCH ocpp:to-equip:*
1745381648.273144 [0 192.1.5.165:49673] SCAN 0 match ocpp:to-equip:*
1745381648.273730 [2 192.1.5.172:57514] SCAN 897 MATCH ocpp:to-equip:*
1745381648.271348 [0 192.1.5.145:49669] SCAN 0 match sys:setting::* count 10000
1745381648.274556 [0 192.1.5.145:49669] DEL sys:setting::get-values-by-name:evcs_anhui_monitor_operator sys:setting::get-values-by-name:amap_operator sys:setting::get-values-by-name:evcs_hubei_monitor_operator sys:setting::get-value-by-name:hex_msg_for_equipment_list sys:setting::get-values-by-name:evcs_lianlian_monitor_operator sys:setting::get-values-by-name:evcs_hunan_loudi_operator sys:setting::get-values-by-name:evcs_cqgw_monitor_operator sys:setting::get-values-by-name:evcs_jilin_monitor_operator sys:setting::get-value-by-name:ces_order_curve_period_seconds sys:setting::get-values-by-name:evcs_anhuishenran_operator sys:setting::get-value-by-name:evcs_result_verify_sign_switch sys:setting::get-values-by-name:evcs_guizhou_monitor_operator sys:setting::get-values-by-name:ces_equipment_code_blacklist sys:setting::get-value-by-name:cec102_special_format_operators
1745381648.275050 [2 192.1.5.172:57514] SCAN 993 MATCH ocpp:to-equip:*

看到keys已替换为scan并进行缓存清除操作。
 

更新效果

在更新上线后,这一段时间内,确实未再出现明显多的KEYS慢指令,似乎朝着一个非常完美的方向发展。

但是,千万不要大意,处理监控慢日志,还需要查看其他资源情况,这里就如“结论”中提到的,发布该更新后CPU竟然突增了,而且居高不下。

这里简单做个分析:

keys虽然阻塞,每次几十甚至上百毫秒完成一次key匹配和驱逐,但是流程简单,对系统实质影响不高,对资源占用影响不大;而使用scan后,是非阻塞的游标轮询,缓存系统中,总key越多,游标需要轮询的次数就越多,当scan size越小,可能影响越大,这无形中加大了对资源的占用。

当然,这仅限当前项目,可能基于缓存数量、并发量、驱逐频率、缓存命中率等因素影响,替换keys为scan优化整体效果权衡表现不佳,更多的是需要自行实践,寻找最佳的方案,目前推荐的方案是,禁用@CacheEvict(allEntries = true),指定key来驱逐缓存,这要求查询操作能指定对应key,是业务层的另一种优化方案这里就暂不讨论。

相关文章:

  • HTMLCSS模板实现水滴动画效果
  • 再谈String
  • Python的库
  • 【25软考网工】第三章(4)生成树协议、广播风暴和MAC地址表震荡
  • MySQL表达式之公用表表达式(CTE)的使用示例
  • Windows与CasaOS跨平台文件同步:SyncThing本地部署与同步配置流程
  • springboot2.x升级到3.x 惨痛经验总结
  • 告别 “幻觉” 回答:RAG 中知识库与生成模型的 7 种对齐策略
  • 力扣-hot100(找到字符串中的所有字母异位词)
  • Chromium 134 编译指南 Ubuntu篇:依赖同步与Hooks配置(六)
  • python打印颜色(python颜色、python print颜色、python打印彩色文字、python print彩色、python彩色文字)
  • vue项目前后端分离设计
  • MyBatisPlus文档
  • 大模型时代的深度学习框架
  • uni-app 小程序中的定位问题 以及 页面安全距离
  • 基于DrissionPage的表情包爬虫实现与解析(含源码)
  • 解释一下计算机中的内存对齐
  • 【Django】新增字段后兼容旧接口 This field is required
  • 【防火墙 pfsense】3 portal
  • Docker容器持久化
  • 珠海市香洲区原区长刘齐英落马,此前已被终止省人大代表资格
  • 国务院同意在海南全岛和秦皇岛等15个城市(地区)设立跨境电子商务综合试验区
  • 上海未来亚洲研究会第六届会员大会举行,叶青当选会长
  • 最高法:侵犯著作权罪中的“复制发行”不包括单纯发行行为
  • 百位名人写“茶”字,莫言王蒙贾平凹都写了
  • 上海五五购物节首次推出商圈精品推广节,9个商圈近百个商场参与促销