• 我的订阅
  • 科技

基于Spring Cache实现Caffeine、jimDB多级缓存实战

类别:科技 发布时间:2023-01-31 11:00:00 来源:京东云企业管家

作者: 京东零售 王震

背景

在早期参与涅槃氛围标签中台项目中,前台要求接口性能999要求50ms以下,通过设计Caffeine、ehcache堆外缓存、jimDB三级缓存,利用内存、堆外、jimDB缓存不同的特性提升接口性能,

内存缓存采用Caffeine缓存,利用W-TinyLFU算法获得更高的内存命中率;同时利用堆外缓存降低内存缓存大小,减少GC频率,同时也减少了网络IO带来的性能消耗;利用JimDB提升接口高可用、高并发;后期通过压测及性能调优999性能<20ms

基于Spring Cache实现Caffeine、jimDB多级缓存实战

当时由于项目工期紧张,三级缓存实现较为臃肿、业务侵入性强、可读性差,在近期场景化推荐项目中,为B端商家场景化资源投放推荐,考虑到B端流量相对C端流量较小,但需保证接口性能稳定。采用SpringCache实现caffeine、jimDB多级缓存方案,实现了低侵入性、可扩展、高可用的缓存方案,极大提升了系统稳定性,保证接口性能小于100ms;

Spring Cache实现多级缓存

多级缓存实例MultilevelCache

/**

* 分级缓存

* 基于Caffeine + jimDB 实现二级缓存

* @author wangzhen520

* @date 2022/12/9

*/

public class MultilevelCache extends AbstractValueAdaptingCache {

/**

* 缓存名称

*/

private String name;

/**

* 是否开启一级缓存

*/

private boolean enableFirstCache = true;

/**

* 一级缓存

*/

private Cache firstCache;

/**

* 二级缓存

*/

private Cache secondCache;

@Override

protected Object lookup(Object key) {

Object value;

recordCount(getUmpKey(this.getName(), UMP_GET_CACHE, UMP_ALL));

if(enableFirstCache){

//查询一级缓存

value = getWrapperValue(getForFirstCache(key));

log.info("{}#lookup getForFirstCache key={} value={}", this.getClass().getSimpleName(), key, value);

if(value != null){

return value;

}

}

value = getWrapperValue(getForSecondCache(key));

log.info("{}#lookup getForSecondCache key={} value={}", this.getClass().getSimpleName(), key, value);

//二级缓存不为空,则更新一级缓存

boolean putFirstCache = (Objects.nonNull(value) || isAllowNullValues()) && enableFirstCache;

if(putFirstCache){

recordCount(getUmpKey(this.getName(), UMP_FIRST_CACHE, UMP_NO_HIT));

log.info("{}#lookup put firstCache key={} value={}", this.getClass().getSimpleName(), key, value);

firstCache.put(key, value);

}

return value;

}

@Override

public void put(Object key, Object value) {

if(enableFirstCache){

checkFirstCache();

firstCache.put(key, value);

}

secondCache.put(key, value);

}

/**

* 查询一级缓存

* @param key

* @return

*/

private ValueWrapper getForFirstCache(Object key){

checkFirstCache();

ValueWrapper valueWrapper = firstCache.get(key);

if(valueWrapper == null || Objects.isNull(valueWrapper.get())){

recordCount(getUmpKey(this.getName(), UMP_FIRST_CACHE, UMP_NO_HIT));

}

return valueWrapper;

}

/**

* 查询二级缓存

* @param key

* @return

*/

private ValueWrapper getForSecondCache(Object key){

ValueWrapper valueWrapper = secondCache.get(key);

if(valueWrapper == null || Objects.isNull(valueWrapper.get())){

recordCount(getUmpKey(this.getName(), UMP_SECOND_CACHE, UMP_NO_HIT));

}

return valueWrapper;

}

private Object getWrapperValue(ValueWrapper valueWrapper){

return Optional.ofNullable(valueWrapper).map(ValueWrapper::get).orElse(null);

}

}

多级缓存管理器抽象

/**

* 多级缓存实现抽象类

* 一级缓存

* @see AbstractMultilevelCacheManager#getFirstCache(String)

* 二级缓存

* @see AbstractMultilevelCacheManager#getSecondCache(String)

* @author wangzhen520

* @date 2022/12/9

*/

publicabstractclassAbstractMultilevelCacheManagerimplementsCacheManager {

private final ConcurrentMap cacheMap = newConcurrentHashMap<>(16);

/**

* 是否动态生成

* @see MultilevelCache

*/

protected boolean dynamic = true;

/**

* 默认开启一级缓存

*/

protected boolean enableFirstCache = true;

/**

* 是否允许空值

*/

protected boolean allowNullValues = true;

/**

* ump监控前缀 不设置不开启监控

*/

privateString umpKeyPrefix;

protectedMultilevelCachecreateMultilevelCache(String name) {

Assert.hasLength(name, "createMultilevelCache name is not null");

MultilevelCache multilevelCache = newMultilevelCache(allowNullValues);

multilevelCache.setName(name);

multilevelCache.setUmpKeyPrefix(this.umpKeyPrefix);

multilevelCache.setEnableFirstCache(this.enableFirstCache);

multilevelCache.setFirstCache(getFirstCache(name));

multilevelCache.setSecondCache(getSecondCache(name));

return multilevelCache;

}

@Override

publicCachegetCache(String name) {

MultilevelCache cache = this.cacheMap.get(name);

if (cache == null && dynamic) {

synchronized (this.cacheMap) {

cache = this.cacheMap.get(name);

if (cache == null) {

cache = createMultilevelCache(name);

this.cacheMap.put(name, cache);

}

return cache;

}

}

return cache;

}

@Override

publicCollection getCacheNames() {

returnCollections.unmodifiableSet(this.cacheMap.keySet());

}

/**

* 一级缓存

* @param name

* @return

*/

protectedabstractCachegetFirstCache(String name);

/**

* 二级缓存

* @param name

* @return

*/

protectedabstractCachegetSecondCache(String name);

public boolean isDynamic() {

return dynamic;

}

public void setDynamic(boolean dynamic) {

this.dynamic = dynamic;

}

public boolean isEnableFirstCache() {

return enableFirstCache;

}

public void setEnableFirstCache(boolean enableFirstCache) {

this.enableFirstCache = enableFirstCache;

}

publicStringgetUmpKeyPrefix() {

return umpKeyPrefix;

}

public void setUmpKeyPrefix(String umpKeyPrefix) {

this.umpKeyPrefix = umpKeyPrefix;

}

}

基于jimDB Caffiene缓存实现多级缓存管理器

/**

* 二级缓存实现

* caffeine + jimDB 二级缓存

* @author wangzhen520

* @date 2022/12/9

*/

publicclassCaffeineJimMultilevelCacheManagerextendsAbstractMultilevelCacheManager {

private CaffeineCacheManager caffeineCacheManager;

private JimCacheManager jimCacheManager;

public CaffeineJimMultilevelCacheManager(CaffeineCacheManager caffeineCacheManager, JimCacheManager jimCacheManager) {

this.caffeineCacheManager = caffeineCacheManager;

this.jimCacheManager = jimCacheManager;

caffeineCacheManager.setAllowNullValues(this.allowNullValues);

}

/**

* 一级缓存实现

* 基于caffeine实现

* @see org.springframework.cache.caffeine.CaffeineCache

* @param name

* @return

*/

@Override

protected Cache getFirstCache(String name) {

if(!isEnableFirstCache()){

return null;

}

return caffeineCacheManager.getCache(name);

}

/**

* 二级缓存基于jimDB实现

* @see com.jd.jim.cli.springcache.JimStringCache

* @param name

* @return

*/

@Override

protected Cache getSecondCache(String name) {

return jimCacheManager.getCache(name);

}

}

缓存配置

/**

* @author wangzhen520

* @date 2022/12/9

*/

@Configuration

@EnableCaching

public class CacheConfiguration {

/**

* 基于caffeine + JimDB 多级缓存Manager

* @param firstCacheManager

* @param secondCacheManager

* @return

*/

@Primary

@Bean(name = "caffeineJimCacheManager")

public CacheManager multilevelCacheManager(@Param("firstCacheManager") CaffeineCacheManager firstCacheManager,

@Param("secondCacheManager") JimCacheManager secondCacheManager){

CaffeineJimMultilevelCacheManagercacheManager = newCaffeineJimMultilevelCacheManager(firstCacheManager, secondCacheManager);

cacheManager.setUmpKeyPrefix(String.format("%s.%s", UmpConstants.Key.PREFIX, UmpConstants.SYSTEM_NAME));

cacheManager.setEnableFirstCache(true);

cacheManager.setDynamic(true);

returncacheManager;

}

/**

* 一级缓存Manager

* @return

*/

@Bean(name = "firstCacheManager")

publicCaffeineCacheManagerfirstCacheManager(){

CaffeineCacheManagerfirstCacheManager = newCaffeineCacheManager();

firstCacheManager.setCaffeine(Caffeine.newBuilder()

.initialCapacity(firstCacheInitialCapacity)

.maximumSize(firstCacheMaximumSize)

.expireAfterWrite(Duration.ofSeconds(firstCacheDurationSeconds)));

firstCacheManager.setAllowNullValues(true);

returnfirstCacheManager;

}

/**

* 初始化二级缓存Manager

* @param jimClientLF

* @return

*/

@Bean(name = "secondCacheManager")

publicJimCacheManagersecondCacheManager(@Param("jimClientLF") Cluster jimClientLF){

JimDbCachejimDbCache = newJimDbCache<>();

jimDbCache.setJimClient(jimClientLF);

jimDbCache.setKeyPrefix(MultilevelCacheConstants.SERVICE_RULE_MATCH_CACHE);

jimDbCache.setEntryTimeout(secondCacheExpireSeconds);

jimDbCache.setValueSerializer(new JsonStringSerializer(ServiceRuleMatchResult.class));

JimCacheManagersecondCacheManager = newJimCacheManager();

secondCacheManager.setCaches(Arrays.asList(jimDbCache));

returnsecondCacheManager;

}

接口性能压测

压测环境

廊坊4C8G * 3

压测结果

1、50并发时,未开启缓存,压测5min,TP99: 67ms,TP999: 223ms,TPS:2072.39笔/秒,此时服务引擎cpu利用率40%左右;订购履约cpu利用率70%左右,磁盘使用率4min后被打满;

2、50并发时,开启二级缓存,压测10min,TP99: 33ms,TP999: 38ms,TPS:28521.18.笔/秒,此时服务引擎cpu利用率90%左右,订购履约cpu利用率10%左右,磁盘使用率3%左右;

缓存命中分析

总调用次数:1840486/min 一级缓存命中:1822820 /min 二级缓存命中:14454/min

一级缓存命中率:99.04%

二级缓存命中率:81.81%

压测数据

未开启缓存

基于Spring Cache实现Caffeine、jimDB多级缓存实战

开启多级缓存

基于Spring Cache实现Caffeine、jimDB多级缓存实战

监控数据

未开启缓存

下游应用由于4分钟后磁盘打满,性能到达瓶颈

接口UMP

基于Spring Cache实现Caffeine、jimDB多级缓存实战

服务引擎系统

基于Spring Cache实现Caffeine、jimDB多级缓存实战

订购履约系统

基于Spring Cache实现Caffeine、jimDB多级缓存实战

开启缓存

上游系统CPU利用率90%左右,下游系统调用量明显减少,CPU利用率仅10%左右

接口UMP

基于Spring Cache实现Caffeine、jimDB多级缓存实战

服务引擎系统

基于Spring Cache实现Caffeine、jimDB多级缓存实战

订购履约系统:

基于Spring Cache实现Caffeine、jimDB多级缓存实战

返回搜狐,查看更多

责任编辑:

以上内容为资讯信息快照,由td.fyun.cc爬虫进行采集并收录,本站未对信息做任何修改,信息内容不代表本站立场。

快照生成时间:2023-01-31 12:45:17

本站信息快照查询为非营利公共服务,如有侵权请联系我们进行删除。

信息原文地址:

可超高频,可降延迟!金百达银爵DDR5内存ZEN4平台超频实战!
...EL”,工艺为5NM,规格为8核心16线程,频率4.5-5.4GHz,二级缓存8MB,三级缓存32MB,热设计功耗105W
2022-12-21 06:00:00
谁是电竞网游最强U?锐龙9 7950X3D制霸全场
采用AMD3DV-Cache缓存技术的锐龙7000X3D系列终于上市,其中的旗舰锐龙97950X3D以当前最强的综合游戏性能超越了竞品酷睿i913900KS
2023-03-16 11:46:00
intel造了一颗“算力存力核弹”
...模扩展方面收益的任务,以追求更高的能效、更高的机架利用率。而现在发布的至强6性能核更适合大数据、建模仿真等计算密集型和人工智能任务,为高性能优化,单颗处理器的功耗直飚500W
2024-09-27 11:45:00
Lunar Lake工程样品性能参数曝光
...超线程技术,为8核心8线程外,非常值得注意的就是其L1缓存达到了832KB,L2缓存的容量更是比L3缓存还要大,达到了14MB
2024-02-20 10:02:00
AMD锐龙9 7000X3D正式登场:两大神级优化
...果游戏的同时还在执行其他任务,比如直播什么的,线程利用率足够高,超过了一个CCX的承载能力,就会自动启动休眠的第二个CCX,兼顾多任务性能。驱动安装成功后,就可以在设备管理的
2023-03-01 20:54:00
瑞昱展示其PCIe 5.0 SSD主控 支持缓存旗舰性能
.../s的闪存接口,支持4KLDPCECC纠错,可采用DDR4、LPDDR3/4x作为缓存,性能方面也是相当顶级的,连续读取速度高达14000MB/s
2024-06-16 12:27:00
西部数据红盘wdredsn700nvme硬盘展示
...,在使用了2块最新的8TB红盘的同时增加了SN700NVMeSSD作为缓存盘已提升数据访问的命中率,具体相关操作文章中会有过程
2023-01-28 22:49:00
旧电脑加装固态硬盘后,系统运行依旧卡顿的原因是什么
...足,更不用说其他的了。在加装固态时,我们要分清楚:缓存速度和介质速度!很多固态SSD测评文章中,都会提及跑分测试速度达到了多少,这个数值一般是指缓存速度。而SSD的整体速度取
2023-01-10 11:05:00
华硕13600k配置单推荐
...5-12490F拥有6核心12线程,CPU主频3GHz,最高睿频4.5GHz,三级缓存20MB,PBP功耗65W,支持DDR5内存
2023-11-06 09:16:00
更多关于科技的资讯:
都市丽人——加拿大鹅绒保暖衣背后的战略咨询公司
当都市丽人的加拿大鹅绒保暖衣在冬日市场中掀起热潮,新品订货会上取得经销商5亿订单销量的数据。这个经典内衣品牌的华丽转身背后
2025-10-17 13:41:00
秋补正当红|邂逅秋补热潮,抖音生活服务一站式解锁多元滋补新体验
转眼秋意渐浓,中秋、国庆双节余温未散,团圆出游的热潮与“应季而食、适时而补”的传统饮食文化相互交织,共同点燃了金秋时节的滋补消费热情
2025-10-17 13:56:00
江西热敏灸机器人获批上市 赋能百亿产业链提速
本报讯(全媒体记者李芳)10月9日,省药监局正式批准热敏灸机器人第二类医疗器械上市。这标志着江西热敏灸产业进入数智化时代
2025-10-17 07:10:00
厦门网讯 (厦门日报记者 薛尧)无人机、运动相机迎来降价潮!近日有市民发现相关热门产品价格跳水,记者走访了解到,我市多家大疆授权体验店中
2025-10-16 08:38:00
助力视弱群体畅行 公交视弱辅助系统“喊”您上车
视弱人士庄先生在公交视弱辅助系统的帮助下乘车。厦门网讯(文/图 厦门日报记者 林钦圣 通讯员 江安娜) “我们先找到并打开公交App
2025-10-16 08:38:00
10月15日晚,福州金融街商务区“亮灯”,迎接2025世界航海装备大会。
2025-10-16 08:59:00
近日,中石化石油工程设计有限公司自主研发的“管道环焊缝射线检测缺陷智能辅助评判系统”,顺利完成准确率测试。本次测试中,该系统总计检查了210张油气长输管道环焊缝射线检测底片
2025-10-16 09:03:00
当“遇到问题先到社交媒体上搜索”成为一代青少年的本能反应,当班级群、兴趣圈与直播平台深度嵌入他们的日常生活,社交网络正构成这代“数字原住民”成长的基本环境
2025-10-16 09:16:00
在人工智能技术飞速发展的今天,大模型以其强大的信息处理与泛化能力,正深刻改变医学领域的科研与临床实践。与此同时,以聚类分析
2025-10-16 09:57:00
人去世了朋友圈会消失吗?微信:对长时间不使用账号已不再回收
10月15日,“微信派”微信公众号发布最新一期播客,聊到了“真的很多人不发朋友圈了吗?”“人去世后,朋友圈会被回收吗?”等话题
2025-10-16 10:13:00
日日佳携手企知道,共同推动智能显示技术科技创新
近日,深圳日日佳显示技术有限公司(以下简称“日日佳”或“公司”)正式签约入驻企知道科创空间。作为专注于TFT-LCD模组制造的细分领域的国家高新技术企业和深圳市专精特新中小企业
2025-10-16 10:18:00
汽车测评 全球协同 | 解码C-NCAP——护航公众出行安全
当汽车从单纯的“交通工具”升级为承载多元需求的“出行载体”,是什么力量在守护这场变革的安全底线?2025世界NCAP大会即将在中国上海启幕
2025-10-16 10:50:00
花田玑密入选“2025山东省优秀兴农电商企业案例”
2025年10月16日,由山东省商务厅主办的“数商兴农庆丰收暨九九网购节”电商促消费活动在青岛莱西市人民广场隆重启动。花田玑密品牌创始人
2025-10-16 10:53:00
香港金管局公布生成式AI沙盒名单,蚂蚁数科入选技术合作伙伴
10月15日,香港金融管理局(HKMA)与香港数码港管理有限公司联合公布第二期生成式AI沙盒参与者名单。蚂蚁银行、中银香港
2025-10-16 11:24:00
卢伟冰官宣REDMI K90系列明天见!不排斥和小米直接竞争
10月16日,小米集团合伙人、总裁卢伟冰微博正式官宣,REDMI K90系列明天见。他发文透露,本次发布会是小米手机业务在旗舰新品发布季的第二篇章
2025-10-16 12:00:00