本地缓存Ehcache的应用实践 | 京东云技术团队

java本地缓存包含多个框架,其中常用的包括:Caffeine、Guava Cache和Ehcache, 其中Caffeine号称本地缓存之王,也是近年来被众多程序员推崇的缓存框架,同时也是SpringBoot内置的本地缓存实现。但是除了Caffeine之外,还有一款也不错的本地缓存框架Ehcache,具有快速、灵活,并支持内存和磁盘缓存,且提供了丰富的配置选项和缓存策略,接下来一起了解下Ehcache。

一、Ehcache****是什么

Ehcache是一个开源的Java本地缓存框架,它提供了快速、灵活的缓存解决方案。Ehcache支持内存和磁盘缓存,并且可以与各种Java应用程序集成,包括基于Spring框架的应用程序。它提供了丰富的配置选项和缓存策略,可以帮助开发人员提高应用程序的性能和响应速度。Ehcache还支持分布式缓存,可以与其他缓存系统集成,如Terracotta集群。

二、Ehcache特点

1、 分层存储:

堆内存储: 利用 Java 的堆上 RAM 内存来存储缓存数据。该层使用与 Java 应用程序相同的堆内存,所有这些内存由 JVM 垃圾收集器扫描(GC)。JVM 使用的堆空间越多,垃圾收集暂停对应用程序性能的影响就越大。该存储速度非常快,但通常资源有限。

堆外存储: 大小受可用 RAM 的限制。不受 Java 垃圾收集 (GC) 的影响。速度相当快,但比堆上存储慢,因为在存储和重新访问数据时必须将数据移入和移出 JVM 堆。

磁盘存储: 利用磁盘(文件系统)来存储缓存数据。这种类型的存储资源通常非常丰富,但比基于 RAM 的存储慢一些。对于所有使用磁盘存储的应用程序,建议使用快速且专用的SSD磁盘来优化吞吐量。

集群存储(分布式): 此数据存储是远程服务器上的缓存。由于网络延迟以及建立客户端/服务器一致性等因素,集群存储会带来额外的性能损耗,性能上会更低一些。

2、 灵活有效期:

**没有期限:**缓存映射在应用存在下永远不会过期;

**生存周期:**缓存映射将在创建后的固定时间后过期;

**空闲时间:**缓存映射将在上次访问后的固定持续时间后过期;

**定制有效期:**通过重载ExpiryPolicy接口实现个性化的过期判断;

接口如下:

返回值定义:

Duration.ZERO: 表示立即过期

Duration.INFINITE: 映射永远不会过期

Duration.设置具体时间: 设置对应的时间后过期

Duration.设置时间周期: 设置对应的周期后过期

Duration设置null:之前的过期时间保持不变

3、淘汰策略

**LFU:**访问频率值小的缓存淘汰。

**LRU:**基于最近访问时间来进行淘汰。

**FIFO:**数据项最早进入缓存的时间来进行淘汰。

三、缓存原理

以三层为例:堆内存,堆外存储,本地磁盘存储。

架构图:

说明:cache-manager、cache、element为Ehcache本地缓存的核心,通过数据写入的事务操作保证个层间的一致性。同时基于存储变更监听程序,针对变更的数据以及满足淘汰策略数据进行清理,亦或持久化至本地磁盘;

流程图(基于源码整理):

待补充

四、实际应用

1、pom引入:

<dependency>    <groupId>org.ehcache</groupId>    <artifactId>ehcache</artifactId>    <version>3.10.0</version>
</dependency>
<dependency>    <groupId>javax.cache</groupId>    <artifactId>cache-api</artifactId>
</dependency>

2、创建实例:

    /*************************** 1.纯内存操作 *****************************/// 1.1 创建缓存 preConfigured 基于 内存CacheManager cacheManager = CacheManagerBuilder.newCacheManagerBuilder().withCache("preConfigured",CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class, ResourcePoolsBuilder.heap(10))).build(true);// 1.2 获取缓存实例Cache<Long, String> preConfigured = cacheManager.getCache("preConfigured", Long.class, String.class);/*************************** 2.新增实例 *****************************/// 2.1 创建新的实例 并获取实例Cache<Long, String> myCache = cacheManager.createCache("myCache",CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class, ResourcePoolsBuilder.heap(10)));/*************************** 3.三层存储-持久化磁盘 *****************************/// 3.1 创建缓存 myData 基于 内存->堆外存储->本地磁盘PersistentCacheManager persistentCacheManager = CacheManagerBuilder.newCacheManagerBuilder().with(CacheManagerBuilder.persistence(new File("/home/export/App/conf/", "myData"))).withCache("threeTieredCache",CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class,ResourcePoolsBuilder.newResourcePoolsBuilder().heap(10, EntryUnit.ENTRIES).offheap(1, MemoryUnit.MB).disk(20, MemoryUnit.MB, true))).build(true);// 3.2 获取存储实例 threeTieredCacheCache<Long, String> threeTieredCache = persistentCacheManager.getCache("threeTieredCache", Long.class, String.class);/*************************** 4.一个manager管理多个缓存 - 持久化磁盘 *****************************/// 4.1 一个实例管理多个缓存 并且每个缓存都可持久化到本地磁盘PersistentCacheManager persistentCacheManager1 = CacheManagerBuilder.newCacheManagerBuilder().with(CacheManagerBuilder.persistence(new File("/path/to/persistent/directory1").getAbsoluteFile())).withCache("cache1",CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class,ResourcePoolsBuilder.newResourcePoolsBuilder().heap(10, EntryUnit.ENTRIES).offheap(1, MemoryUnit.MB).disk(20, MemoryUnit.MB, true))).with(CacheManagerBuilder.persistence(new File("/path/to/persistent/directory2").getAbsoluteFile())).withCache("cache2",CacheConfigurationBuilder.newCacheConfigurationBuilder(String.class, Integer.class,ResourcePoolsBuilder.newResourcePoolsBuilder().heap(20, EntryUnit.ENTRIES).offheap(2, MemoryUnit.MB).disk(30, MemoryUnit.MB, true))).build(true);

说明:

a. 上述常见缓存实例的方法有多个,其中第一种为纯内存操作,第三种为三层存储并持久化磁盘实例,下面以第三种方式进行测试验证;

日常应用可以进行组合使用,例如:

•堆内存 + 堆外存储 + 本地磁盘

•堆内存 + 堆外存储

•堆内存 + 本地磁盘

b. 如果选择本地磁盘存储(系统退出前需要使用persistentCacheManager.close();释放资源,方可保证磁盘数据准确),后续系统重启后会加载磁盘内数据至缓存中,使得缓存在有效期内依然有效,可减少应用启动对后端DB的压力;

3、用例

4、结果:

持久化磁盘:

5、结论:

缓存+磁盘测试OK;

有效期数据,失效后不返回;

系统重启加载磁盘数据正常;

👉其他说明:

Ehcache可结合Terracotta插件实现分布式存储,对该部分感兴趣的同学可一起探讨。但是对于线上系统而言,若需分布式存储,建议直接使用redis。Ehcache的分布式实现并不可靠,核心还是采用广播集群方式,实现数据的同步及更新,并且性能受机器IO,磁盘,网络等影响,在实际应用情况下,不会比redis更好。

6、以下为完成测试代码

package com.jx.jxreserve.groupbuy.manager;import com.jd.flash.commons.exception.BaseBusinessException;
import com.jx.jxreserve.groupbuy.common.enums.ErrorCode;
import lombok.extern.slf4j.Slf4j;
import org.ehcache.Cache;
import org.ehcache.CacheManager;
import org.ehcache.PersistentCacheManager;
import org.ehcache.config.builders.CacheConfigurationBuilder;
import org.ehcache.config.builders.CacheManagerBuilder;
import org.ehcache.config.builders.ExpiryPolicyBuilder;
import org.ehcache.config.builders.ResourcePoolsBuilder;
import org.ehcache.config.units.EntryUnit;
import org.ehcache.config.units.MemoryUnit;
import org.springframework.stereotype.Component;import java.io.File;
import java.time.Duration;import static org.ehcache.Status.AVAILABLE;/*** @author zhangpengfei9* @version V1.0* Ehcache的测试管理类*/
@Slf4j
@Component
public class EhcacheTestManager {/*************************** 1.纯内存操作 *****************************/// 1.1 创建缓存 preConfigured 基于 内存CacheManager cacheManager = CacheManagerBuilder.newCacheManagerBuilder().withCache("preConfigured",CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class, ResourcePoolsBuilder.heap(10))).build(true);// 1.2 获取缓存实例Cache<Long, String> preConfigured = cacheManager.getCache("preConfigured", Long.class, String.class);/*************************** 2.新增实例 *****************************/// 2.1 创建新的实例 并获取实例Cache<Long, String> myCache = cacheManager.createCache("myCache",CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class, ResourcePoolsBuilder.heap(10)));/*************************** 3.三层存储 *****************************/// 3.1 创建缓存 myData 基于 内存->堆外存储->本地磁盘PersistentCacheManager persistentCacheManager = CacheManagerBuilder.newCacheManagerBuilder().with(CacheManagerBuilder.persistence(new File("/home/export/App/conf/", "groupData"))).withCache("testDiskCache",CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class,ResourcePoolsBuilder.newResourcePoolsBuilder().heap(10, EntryUnit.ENTRIES).offheap(1, MemoryUnit.MB).disk(20, MemoryUnit.MB, true)).withExpiry(ExpiryPolicyBuilder.timeToLiveExpiration(Duration.ofSeconds(600))) // 设置缓存有效期).build(true);/*************************** 4.多个缓存 - 三层存储 *****************************/// 4.1 一个实例管理多个缓存 并且每个缓存都可持久化到本地磁盘PersistentCacheManager persistentCacheManager1 = CacheManagerBuilder.newCacheManagerBuilder().with(CacheManagerBuilder.persistence(new File("/home/export/App/conf/").getAbsoluteFile())).withCache("cache1",CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class,ResourcePoolsBuilder.newResourcePoolsBuilder().heap(10, EntryUnit.ENTRIES).offheap(1, MemoryUnit.MB).disk(20, MemoryUnit.MB, true))).with(CacheManagerBuilder.persistence(new File("/home/export/App/conf/").getAbsoluteFile())).withCache("cache2",CacheConfigurationBuilder.newCacheConfigurationBuilder(String.class, Integer.class,ResourcePoolsBuilder.newResourcePoolsBuilder().heap(20, EntryUnit.ENTRIES).offheap(2, MemoryUnit.MB).disk(30, MemoryUnit.MB, true))).build(true);/*** 设置缓存*/public void setEhCache(Long key, String values) throws BaseBusinessException {try {// 获取存储实例 threeTieredCachelog.info("setEhCache.value:{},{}", values, key);Cache<Long, String> testDiskCache = getManagerCache("testDiskCache");testDiskCache.put(key, values);} catch (Exception e) {log.error("setEhCache failure! Exception:", e);throw new BaseBusinessException(ErrorCode.SYSTEM_DB_ERROR.getCode(), ErrorCode.SYSTEM_DB_ERROR.getMessage());}}/*** 查询缓存*/public String getEhCache(Long key) throws BaseBusinessException {try {// 获取存储实例 threeTieredCachelog.info("getEhCache.key:{}", key);Cache<Long, String> testDiskCache = getManagerCache("testDiskCache");return testDiskCache.get(key);} catch (Exception e) {log.error("setEhCache failure! Exception:", e);throw new BaseBusinessException(ErrorCode.SYSTEM_DB_ERROR.getCode(), ErrorCode.SYSTEM_DB_ERROR.getMessage());}}/*** 设置缓存*/public void closeEhCache() throws BaseBusinessException {try {// 获取存储实例 threeTieredCachelog.info("closeEhCache.persistentCacheManager.close1:{}", persistentCacheManager.getStatus());persistentCacheManager.close();log.info("closeEhCache.persistentCacheManager.close2:{}", persistentCacheManager.getStatus());} catch (Exception e) {log.error("setEhCache failure! Exception:", e);throw new BaseBusinessException(ErrorCode.SYSTEM_DB_ERROR.getCode(), ErrorCode.SYSTEM_DB_ERROR.getMessage());}}private Cache<Long, String> getManagerCache(String cache) {// 3.1 创建缓存 myData 基于 内存->堆外存储->本地磁盘log.info("persistentCacheManager.getStatus():{}", persistentCacheManager.getStatus());if (AVAILABLE != persistentCacheManager.getStatus()) {persistentCacheManager = CacheManagerBuilder.newCacheManagerBuilder().with(CacheManagerBuilder.persistence(new File("/home/export/App/conf/", "groupData"))).withCache("testDiskCache",CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class,ResourcePoolsBuilder.newResourcePoolsBuilder().heap(10, EntryUnit.ENTRIES).offheap(1, MemoryUnit.MB).disk(20, MemoryUnit.MB, true))).build(true);log.info("persistentCacheManager.getStatus1:{}", persistentCacheManager.getStatus());}Cache<Long, String> testDiskCache = persistentCacheManager.getCache(cache, Long.class, String.class);return testDiskCache;}
}

作者:京东零售 张鹏飞

来源:京东云开发者社区 转载请注明来源

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/253174.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Cocos creator 3.x 刚体组件碰撞无效

Cocos creator 3.x 刚体组件碰撞无效 问题描述&#xff1a;只有一个circleCollider2D时&#xff0c;可以在碰撞时正确输出结果&#xff0c;但是当我在外围加了一个circle之后&#xff0c;期望character进入圆圈范围时就触发方法&#xff0c;此时原代码失效 import { _decorat…

Kubernetes基础(十四)-k8s网络通信

1 k8s网络类型 2 Pod网络 2.1 同一pod内不同容器通信 Pod是Kubernetes中最小的可部署单元&#xff0c;它是一个或多个紧密关联的容器的组合&#xff0c;这些容器共享同一个网络命名空间和存储卷&#xff0c;因此Pod中的所有容器都共享相同的网络命名空间和IP地址——PodIP&a…

JVM 性能调优 - 四种引用(4)

为什么会有四种引用 我们先回顾下在 Java 虚拟机内存体系(1) 中提到了的垃圾回收算法 1、引用计数法 原理:给对象添加一个引用计数器,每当有一个地方引用它,计数器的值就加一。每当有一个引用失效,计数器的值就减一。当计数器值为零时,这个对象被认为没有其他对象引用,…

【Java安全】ysoserial-URLDNS链分析

前言 Java安全中经常会提到反序列化&#xff0c;一个将Java对象转换为字节序列传输&#xff08;或保存&#xff09;并在接收字节序列后反序列化为Java对象的机制&#xff0c;在传输&#xff08;或保存&#xff09;的过程中&#xff0c;恶意攻击者能够将传输的字节序列替换为恶…

24.云原生ArgoCD高级之钩子

云原生专栏大纲 文章目录 Argo CD钩子如何定义钩子钩子删除策略 Argo CD钩子 Argo CD 是一个用于部署和管理 Kubernetes 应用程序的工具&#xff0c;它提供了一种声明式的方式来定义和自动化应用程序的部署过程。Argo CD 钩子&#xff08;Hooks&#xff09;是一种机制&#x…

ctfshow-web11~20-WP

web11 根据提示,查询对ctfshow域名进行dns查询,查看TXT记录 阿里云查询链接:阿里云网站运维检测平台 获取flag成功 web12 根据题目提示,我们访问robots.txt,获取到后台地址 然后我们访问一下后台

SQL--DQL

DQL英文全称是Data Query Language(数据查询语言)&#xff0c;数据查询语言&#xff0c;用来查询数据库中表的记 录。 查询关键字: SELECT 在一个正常的业务系统中&#xff0c;查询操作的频次是要远高于增删改的&#xff0c;当我们去访问企业官网、电商网站&#xff0c; 在这…

Linux内核与驱动面试经典“小”问题集锦(4)

接前一篇文章&#xff1a;Linux内核与驱动面试经典“小”问题集锦&#xff08;3&#xff09; 问题5 问&#xff1a;Linux内核中内存分配都有哪些方式&#xff1f;它们之间的使用场景都是什么&#xff1f; 备注&#xff1a;这个问题是笔者近期参加蔚来面试时遇到的一个问题。这…

Maven构建OSGI+HttpServer应用

Maven构建OSGIHttpServer应用 官网&#xff08;https://eclipse.dev/equinox/server/http_in_equinox.php&#xff09;介绍有两种方式&#xff1a; 一种是基于”org.eclipse.equinox.http”包的轻量级实现&#xff0c;另一种是基于”org.eclipse.equinox.http.jetty”包&#…

『 C++ - STL 』unordered_xxx系列关联式容器及其封装(万字)

文章目录 &#x1f3a1; unordered系列关联式容器&#x1f3a1; 哈希表的改造&#x1f3a2; 节点的设置与总体框架&#x1f3a2; 迭代器的封装&#x1f3a0; 迭代器的框架&#x1f3a0; operator()运算符重载&#x1f3a0; 其余成员函数/运算符重载 &#x1f3a2; 迭代器begin(…

ORM模型类

模型 创建两个表 创建模型类 from django.db import models# Create your models here. class BookInfo(models.Model):name models.CharField(max_length10, uniqueTrue) # 书名pub_date models.DateField(nullTrue) # 发布时间read_count models.IntegerField(default…

【TCP/IP】用户访问一个购物网站时TCP/IP五层参考模型中每一层的功能

当用户访问一个购物网站时&#xff0c;网络上的每一层都会涉及不同的协议&#xff0c;具体网络模型如下图所示。 以下是每个网络层及其相关的协议示例&#xff1a; 物理层&#xff1a;负责将比特流传输到物理媒介上&#xff0c;例如电缆或无线信号。所以在物理层&#xff0c;可…

ElastAlert 错误日志告警

文章目录 前言一、ElastAlert 概览1.1 简介1.2 ElastAlert 特性 二、ElastAlert 下载部署2.1 安装 Python3 环境2.2 下载 ElastAlert2.3 部署 ElastAlert 三、接入平台3.1 对外接口层3.2 服务层 前言 ElastAlert 是 Yelp 公司基于 python 开发的 ELK 日志告警插件&#xff0c;…

vue electron应用调exe程序

描述 用Python写了一个本地服务编译成exe程序&#xff0c;在electron程序启动后&#xff0c;自动执行exe程序 实现 1. 使用node的child_process模块可以执行windows执行&#xff0c;通过指令调exe程序 // electron/index.js var cp require("child_process"); /…

C++泛编程(3)

类模板基础 1.类模板的基本概念2.类模板的分文件编写3.类模板的嵌套 在往节内容中&#xff0c;我们详细介绍了函数模板&#xff0c;这节开始我们就来聊一聊类模板。C中&#xff0c;类的细节远比函数多&#xff0c;所以这个专题也会更复杂。 1.类模板的基本概念 和函数模板一样…

AES算法:数据传输的安全保障

在当今数字化时代&#xff0c;数据安全成为了一个非常重要的问题。随着互联网的普及和信息技术的发展&#xff0c;我们需要一种可靠的加密算法来保护我们的敏感数据。Advanced Encryption Standard&#xff08;AES&#xff09;算法应运而生。本文将介绍AES算法的优缺点、解决了…

【调试】pstore原理和使用方法总结

什么是pstore pstore最初是用于系统发生oops或panic时&#xff0c;自动保存内核log buffer中的日志。不过在当前内核版本中&#xff0c;其已经支持了更多的功能&#xff0c;如保存console日志、ftrace消息和用户空间日志。同时&#xff0c;它还支持将这些消息保存在不同的存储…

H5 简约四色新科技风引导页源码

H5 简约四色新科技风引导页源码 源码介绍&#xff1a;一款四色切换自适应现代科技风动态背景的引导页源码&#xff0c;源码有主站按钮&#xff0c;分站按钮2个&#xff0c;QQ联系站长按钮一个。 下载地址&#xff1a; https://www.changyouzuhao.cn/11990.html

适合龙年春节的SVG模版

宝藏模版 往期推荐&#xff08;点击阅读&#xff09;&#xff1a; 趣味效果&#xff5c;高大上&#xff5c;可爱风&#xff5c;年终总结&#xff08;一&#xff09;&#xff5c;年终总结&#xff08;二&#xff09;&#xff5c;循环特效&#xff5c;情人节&#xff08;一&…

Quartus IP 之mif与hex文件创建与使用

一、mif与hex概述 ROM IP的数据需要满足断电不丢失的要求&#xff0c;ROM IP数据的文件格式一般有三种文件格式&#xff1a;.mif、.hex、.coe&#xff0c;Xilinx与Intel Altera支持的ROM IP数据文件格式如下&#xff1a; Xilinx与Altera支持的ROM文件格式 Alterahex、mifAM&am…