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

news2024/11/15 11:31:51

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 获取存储实例 threeTieredCache
    Cache<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 {
            // 获取存储实例 threeTieredCache
            log.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 {
            // 获取存储实例 threeTieredCache
            log.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 {
            // 获取存储实例 threeTieredCache
            log.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.coloradmin.cn/o/1431323.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

1893_文本化以及协议的思考

全部学习汇总&#xff1a; g_unix: UNIX系统学习笔记 (gitee.com) 004_文本化以及协议 关于这一点描述的确是很有感触&#xff0c;python等脚本语言中的列表、字典等设计的确是在做数据处理的时候很好的帮手。如果类似的处理需要在C的环境中处理&#xff0c;显然是要麻烦得多。…

React 面试题

1、组件通信的方式 父组件传子组件&#xff1a;通过props 的方式 子组件传父组件&#xff1a;父组件将自身函数传入&#xff0c;子组件调用该函数&#xff0c;父组件在函数中拿到子组件传递的数据 兄弟组件通信&#xff1a;找到共同的父节点&#xff0c;用父节点转发进行通信 …

如何利用 AI 做乘法,制作一款龙年贺卡小程序

2022 年底 AIGC 的出现&#xff0c;让 2023 年成为通用人工智能元年。 这是最好的时代&#xff0c;利用 AI&#xff0c;之前仅能存在幻想中的事物落地成现实。 只需要寥寥几句话&#xff0c;就可以描绘一张斑斓的画&#xff0c;真实而又丰富的画。 目前 AI 生图的大模型不多…

IDEA插件ChatGPT - Easycode安装使用

IDEA插件ChatGPT - Easycode简介 ChatGPT - Easycode 是一个由 OpenAI 开发的 IntelliJ IDEA 插件,它可以利用 ChatGPT 的强大语言生成能力,帮助开发人员提高编码效率。 主要功能: 代码生成:可以根据自然语言描述生成代码,支持多种编程语言,包括 Java、Python、JavaSc…

春节宅家必备!仅需26元/月,与好友共战《幻兽帕鲁》!

开放世界游戏《幻兽帕鲁》1 月 19 日推出抢先体验版之后&#xff0c;热度连日居高不下&#xff0c;其发售仅 6 天销量就突破了 800 万份&#xff0c;在线人数更是突破了 200 万大关。 因为游戏自身优化问题&#xff0c;不少玩家也遭遇了卡顿、闪退、延迟高等问题。针对此&#…

PPT、PDF全文档翻译相关产品调研笔记

主要找一下是否有比较给力的全文档翻译 文章目录 1 百度翻译2 小牛翻译3 腾讯交互翻译4 DeepL5 languagex6 云译科技7 快翻:qtrans8 simplifyai9 officetranslator10 火山引擎翻译-无文档翻译1 百度翻译 地址: https://fanyi.baidu.com/ 配套的比较完善,对于不同行业也有区…

UPCX项目被选为2024多哈世界游泳锦标赛和世联世界杯的官方赞助商

2024年2月2日晚&#xff0c;世界泳联官方针对英国队夺得 2024 年多哈世界游泳锦标赛第一枚奖表示庆祝&#xff01; 据悉&#xff0c;UPCX 项目已被选为 2024 年多哈世界游泳锦标赛和世界泳联游泳世界杯巡回赛的官方区块链支付赞助商。 在两项国际重大赛事期间&#xff0c;运动…

计算机网络第4章(网络层)

4.1、网络层概述 简介 网络层的主要任务是实现网络互连&#xff0c;进而实现数据包在各网络之间的传输 这些异构型网络N1~N7如果只是需要各自内部通信&#xff0c;他们只要实现各自的物理层和数据链路层即可 但是如果要将这些异构型网络互连起来&#xff0c;形成一个更大的互…

云计算概述(云计算类型、技术驱动力、关键技术、特征、特点、通用点、架构层次)(二)

云计算概述&#xff08;二&#xff09; &#xff08;云计算类型、技术驱动力、关键技术、特征、特点、通用点、架构层次&#xff09; 目录 零、00时光宝盒 一、云计算类型&#xff08;以服务的内容或形态来分) 二、云计算的12种技术驱动力 三、云计算的关键技术 四、云计…

HiveSQL题——collect_set()/collect_list()聚合函数

一、collect_set() /collect_list()介绍 collect_set()函数与collect_list()函数属于高级聚合函数&#xff08;行转列&#xff09;&#xff0c;将分组中的某列转换成一个数组返回&#xff0c;常与concat_ws()函数连用实现字段拼接效果。 collect_list&#xff1a;收集并形成lis…

Python 轻量级定时任务调度:APScheduler

简述 APscheduler (Advanced Python Scheduler)&#xff0c;作用为按指定的时间规则执行指定的作业。提供了基于日期date、固定时间间隔interval 、以及类似于Linux上的定时任务crontab类型的定时任务。该框架不仅可以添加、删除定时任务&#xff0c;还可以将任务存储到数据库…

【实证分析】地级市-资本存量测算结果数据集(含计算公式及原始数据)( 2003-2021年)

该数据为地级市资本存量测算&#xff08;2003-2021年&#xff09;&#xff0c;提供了中国地级市在该期间内资本存量的详细测算结果&#xff0c;包括两种基于2011年和2006年基期的测算方式。该数据集利用了从城市统计年鉴和中国统计年鉴获取的固定资产投资数据及其增速&#xff…

布隆过滤器有什么用?什么原理?如何使用?

1 前言 布隆过滤器相信大家没用过的话&#xff0c;也已经听过了。 布隆过滤器主要是为了解决海量数据的存在性问题。对于海量数据中判定某个数据是否存在且容忍轻微误差这一场景&#xff08;比如缓存穿透、海量数据去重&#xff09;来说&#xff0c;非常适合。 2 什么是布隆…

docker elasticsearch8启动失败

docker elasticsearch8.12.0启动后提示这个&#xff0c;并且始终无法访问localhost:9200 received plaintext http traffic on an https channel, closing connection Netty4HttpChannel 解决方案&#xff1a;重新创建 elasticsearch容器&#xff0c;加上 -e xpack.security.…

智能边缘计算网关实现高效数据处理与实时响应-天拓四方

在当今时代&#xff0c;数据已经成为驱动业务决策的关键因素。然而&#xff0c;传统的数据处理方式往往存在延迟&#xff0c;无法满足实时性要求。此时&#xff0c;智能边缘计算网关应运而生&#xff0c;它能够将数据处理和分析的能力从中心服务器转移至设备边缘&#xff0c;大…

26条prompt规则应用于大模型

1、引入动机 llm大模型在回答一些问题上表现出了惊人的能力&#xff0c;例如数学逻辑推理&#xff0c;代码生成&#xff0c;问题答复等。提词工程是和大预言模型交流的一门艺术。 大模型的返回结合和用户的指令和输入直接相关prompts是用户和大模型沟通的一种编码方式 一般地…

5+单基因+免疫浸润+单细胞+实验,思路简单易复现

今天给同学们分享一篇生信文章“HOPX is a tumor-suppressive biomarker that corresponds to T cell infiltration in skin cutaneous melanoma”&#xff0c;这篇文章发表在Cancer Cell Int期刊上&#xff0c;影响因子为5.8。 结果解读&#xff1a; 低HOPX表达表明SKCM预后不…

Ai知识图谱

总结&#xff1a;从AI技术栈全貌来看&#xff0c;基础模型、基础算法&#xff0c;个人及小公司是玩不起的&#xff0c;大公司才有对应人力、财力、算力 去做&#xff0c;个人更多的是要在应用场景上创新&#xff0c;几个关键的技术必须会&#xff1a;编码语言&#xff08;Pytho…

如何使用项目管理工具进行任务分配和进度跟踪

项目管理是一项重要的工作&#xff0c;有效的任务分配和进度跟踪是项目成功的关键因素。 项目经理可以选择合适的项目管理工具来管理项目&#xff0c;在选择项目管理工具时&#xff0c;需要根据项目的特点和需求进行评估。本文将介绍如何使用项目管理工具来进行任务分配和进度…

集成阿里云短信服务

目的是集成阿里云短信服务&#xff0c;完成验证码的发送和接收。 目 录 1、开通阿里云短信服务 2、申请签名 3、申请模板 4、获取AccessKey 5、代码实现 6、代码扩展 7、总结 1、开通阿里云短信服务 去阿里云官网开通 2、申请签名 进行整个步骤时&#xff0c;可以先…