• 我的订阅
  • 科技

基于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

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

信息原文地址:

...EL”,工艺为5NM,规格为8核心16线程,频率4.5-5.4GHz,二级缓存8MB,三级缓存32MB,热设计功耗105W
2022-12-21 06:00
采用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
...果游戏的同时还在执行其他任务,比如直播什么的,线程利用率足够高,超过了一个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
...,在使用了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
更多关于科技的资讯:
兰研荣登2024年度泉州创新企业十强
3月20日,由泉州市委宣传部、市委金融办、市发改委、市工信局、市住建局、市商务局、市退役军人事务局、市数据管理局、市工商联
2025-04-02 14:01:00
SU7事故遇难者家属回应雷军:鲜活生命已离世 车企应对事故有足够的敬畏之心
快科技4月2日消息,昨晚雷军在其个人微博发文对小米SU7近日事故回应,而这也被冲上了热搜。他表示,我代表小米,表示最深切的哀悼
2025-04-02 14:10:00
3月20日,金融科技公司小赢科技发布了其截至2024年12月31日的第四季度及年度未经审计的财务业绩。财务数据显示:截至2024年12月31日的在贷余额为523
2025-04-02 14:26:00
汤臣倍健:跨越性价比,用户爱上“质价比”
鲁网4月2日讯过去几年,流量红利降临,众多低质低价的白牌迎风而起。然而如今流量红利退潮,消费者更加清醒,“性价比”策略也逐渐陷入困境
2025-04-02 14:30:00
传小米汽车内测“安全分Beta”:可评估驾驶行为 降低事故风险
快科技4月2日消息,近日,有媒体报道,小米汽车App正在内测“安全分Beta”系统。该系统将为车主提供全方位的安全评估与优化建议
2025-04-02 14:40:00
李斌回应沈斐接手乐道:首要任务是做好销售基本功
快科技4月2日消息,今日,乐道汽车总裁艾铁成宣布离职,不再担任乐道汽车总裁和蔚来高级副总裁。蔚来还对乐道汽车进行新的人事任命
2025-04-02 14:40:00
宁德时代中国石化达成合作协议:要建10000座换电站
快科技4月2日消息,宁德时代官宣,近日,其与中国石化在北京签署合作框架协议。根据协议,双方将全面深化长期战略合作关系,共同建设覆盖全国的换电生态网络
2025-04-02 14:40:00
Etsy开店的优劣势分析
Etsy作为一个专注于手工艺品、古董以及独特商品的电子商务平台,为创作者和小型企业提供了一个展示和销售产品的机会。开设Etsy店铺可以带来许多好处
2025-04-02 14:42:00
CMEF医疗器械展必看!富丽康液态镜头如何破解手术光学难题?
2025年中国国际医疗器械展览会(CMEF)即将于4月8日-11日在上海国家会展中心震撼启幕!作为全球医疗行业的顶级盛会
2025-04-02 14:45:00
海信空调易省电Pro空调预售:AI省电41%!告别“电费刺客”
3月31日,海信空调正式发布易省电E370Pro,以APF值5.5、AI省电41%的创新突破将空调节能标准提升至全新维度
2025-04-02 14:46:00
近日,作为2025中关村论坛年会的重要组成部分,中关村国际技术交易大会“全球高校科技成果转化促进大会”在北京工业大学举行
2025-04-02 14:54:00
泸州老窖携手《三体》推出联名白酒 开启科幻与传统文化跨界新纪元
2025年3月31日,北京,当千年酒香邂逅宇宙星辰,一场跨越时空的文化碰撞在北京首钢园香格里拉酒店璀璨上演。泸州老窖与科幻巨作《三体》联袂打造的“泸州老窖|三体”与“国窖1573|三体”全球发布会盛大启幕
2025-04-02 15:05:00
智元机器人与顶尖具身智能公司Pi合作:加速具身智能技术落地
快科技4月2日消息,据报道,智元机器人宣布与国际顶尖具身智能公司Physical Intelligence(Pi)建立深度合作伙伴关系
2025-04-02 15:10:00
君乐宝加速科研成果转化,为全球消费者提供科学健康方案
在健康食品产业蓬勃发展的今天,科研创新无疑是推动行业进步的关键力量。以“科学营养”为核心理念的君乐宝乳业集团,始终站在科研创新的前沿
2025-04-02 15:14:00
携手广州领矿,开启多元商业机遇
在广州天河区的商业浪潮中,广州领矿化工产品有限公司宛如一颗闪耀的明星,自2013年扬帆起航以来,不断拓展业务版图,凭借多元产品与优质服务
2025-04-02 15:31:00