大厂都在用EhCache,它到底比Redis强在哪里?
5月17日 蚀肉堂投稿 故事背景
随着硬件价格的走低,大家对硬件的依赖越来越高。甚至听说,代码不重要,不行就加机器呗。比如缓存的使用,通常有基于虚拟机内存、基于磁盘存储、基于中间件(Redis内存)等方式,我们都知道,最适合的才是最好的,但实践中,往往是动不动就直接上Redis。
那么,Redis一定是最好的选择吗?单不说对内存的要求,从效率和性能上来说,也未必是最优的。所以,不同的场景使用不同的缓存策略才是高手应该追求的。
这篇文章就带大家认识除Redis之外的另一种缓存框架:EhCache。之所以要写写,也是因为项目中运用了此框架,同时又遇到点问题,于是决定深入研究一下。研究之后,发现还真有点意思EhCache简介
EhCache是一个纯Java的进程内缓存框架,具有快速、精干的特点。注意的这里的关键字进程,基于进程的缓存直觉告诉我们效率肯定要高一些,因为它直接在进程之内进行操作,但不同应用之间缓存的共享可能就会有问题。
EhCache是Hibernate中默认的CacheProvider,SpringBoot也对其进行了支持,Spring中提供的缓存抽象也支持对EhCache缓存框架的绑定,而且支持基于注解的方式来使用。因此,EhCache是一款被广泛使用的基于Java的高速缓存框架,使用起来也非常方便。
EhCache提供了多种缓存策略,主要分为内存和磁盘两级,是一款面向通用缓存、JavaEE和轻量级容器的缓存框架。EhCache的特点
简单说一下该框架的特点:简单、快速,拥有多种缓存策略;缓存数据有两级:内存和磁盘,无需担心容量问题;缓存数据会在虚拟机重启的过程中写入磁盘;可以通过RMI、可插入API等方式进行分布式缓存;具有缓存和缓存管理器的侦听接口;支持多缓存管理器实例,以及一个实例的多个缓存区域,并提供Hibernate的缓存实现;
EhCache可以单独使用,但通常会与Mybatis、Shiro等三方类库结合使用。本人项目中使用EhCache就是结合Shiro来使用的。
除了优点,EhCache也还有一些缺点。比如,非常占用磁盘空间,这是因为DiskCache的算法简单,只是对元素直接追加存储。这样虽然可以提高效率,但在使用频繁的系统中,磁盘很快会满。
另外就是不能保证数据安全,当然突然kill掉Java进程时,可能会产生冲突。EhCache解决冲突的方法是重建Cache,这对Cache数据需要保持时可能会产生影响。Cache只是简单的加速,不能保证数据的安全。EhCache与Redis
EhCache直接在JVM中进行缓存,速度快,效率高。与Redis相比,操作简单、易用、高效,虽然EhCache也提供有缓存共享的方案,但对分布式集群的支持不太好,缓存共享实现麻烦。
Redis是通过Socket访问到缓存服务,效率比EhCache低,比数据库要快很多,处理集群和分布式缓存方便,有成熟的方案。
所以,如果是单体应用,或对缓存访问要求很高,可考虑采用EhC如果是大型系统,存在缓存共享、分布式部署、缓存内容很大时,则建议采用Redis。EhCache架构图
看一下EhCache的架构图,大概了解一下它由几部分组成。
Ehcachearchitecture
CacheReplication部分提供了缓存复制的机制,用于分布式环境。EhCache最初是独立的本地缓存框架组件,在后期的发展中,结合Terracotta服务阵列模型,可以支持分布式缓存集群,主要有RMI、JGroups、JMS和CacheServer等传播方式进行节点间通信。
InprocessAPIs则提供了基于JSR、JMX等标准的支持,能够较好的兼容和移植,同时对各类对象有较完善的监控管理机制。
NetworkAPIs则对外提供了基于RESTfulAPI、JMSAPI、CacheServer等方式的支持。
在使用过程中,需要关注的核心部分便是中间的Core部分了。它包含了核心的API和概念:CacheManager:缓存管理器,可以通过单例或者多例的方式创建,也是Ehcache的入口类。Cache:每个CacheManager可以管理多个Cache,每个Cache可以采用hash的方式管理多个Element。所有cache都实现了Ehcache接口;Element:单条缓存数据的组成单位,用于存放真正缓存内容的。
三者的管理可以用下图表示:
CacheManager缓存过期策略
在架构图中还可以看到MemoryStoreLRU、MemoryStoreLFU、MemoryStoreFIFO等内存存储算法。也就是当缓存占用空间接近临界值时,会采用上面的淘汰策略来清理掉一部分数据。
EhCache提供了三种淘汰算法:FIFO:FirstInFirstOut,先进先出。判断被存储的时间,离目前最远的数据优先被淘汰。LRU:LeastRecentlyUsed,最近最少使用。判断最近被使用的时间,目前最远的数据优先被淘汰。LFU:LeastFrequentlyUsed,最不经常使用。在一段时间内,数据被使用次数最少的,优先被淘汰。
Ehcache采用的是懒淘汰机制,每次往缓存放入数据时,都会存一个时间,在读取时要和设置的时间做TTL比较来判断是否过期。EhCache实战解析
了解了上面的基础知识之后,来实验一下EhCache如何使用。其中EhCache2。x和EhCache3。x的使用差距较大。
这里采用比较新的3。9。6版本,不同的版本在API的使用上会有所差异。基于API使用EhCache
EhCache提供了基于API和xml两种形式创建CacheManger和Cache。先来看基于API的形式:
在pom文件中引入EhCache依赖:dependencygroupIdorg。ehcachegroupIdehcacheartifactIdversion3。9。6versiondependency
创建并使用的代码如下:publicclassEhCacheTest{Testpublicvoidtest(){1、先创建一个CacheManagerB2、使用CacheManagerBuilder创建一个预配置(preconfigured)缓存:第一个参数为别名,第二个参数用来配置C3、build方法构建并初始化;build中true参数表示进行初始化。CacheManagercacheManagerCacheManagerBuilder。newCacheManagerBuilder()。withCache(preConfigured,CacheConfigurationBuilder。newCacheConfigurationBuilder(Long。class,String。class,ResourcePoolsBuilder。heap(100))。build())。build(true);取回在设定的preconfigured,对于key和value值类型,要求是类型安全的,否则将抛出ClassCastException异常。CacheLong,StringpreConfiguredcacheManager。getCache(preConfigured,Long。class,String。class);System。out。println(从缓存中获取key为preConfigured:preConfigured);根据需求,通过CacheManager创建出新的Cache。实例化和完整实例化的Cache将通过CacheManager。getCacheAPI返回。CacheLong,StringmyCachecacheManager。createCache(myCache,CacheConfigurationBuilder。newCacheConfigurationBuilder(Long。class,String。class,ResourcePoolsBuilder。heap(100))。build());使用put方法存储数据myCache。put(1L,daone!);使用get方法获取数据StringvaluemyCache。get(1L);System。out。println(从缓存中获取key为1L:value);close方法将释放CacheManager所管理的缓存资源cacheManager。close();}}
上述代码基于API的形式演示了如何创建CacheManager及Cache,并对Cache进行设置和获取。基于XML使用EhCache
依赖Jar包不变,在srcmainresources目录下创建配置文件ehcache。xml。configxmlns:xsihttp:www。w3。org2001XMLSchemainstancexmlnshttp:www。ehcache。orgv3xsi:schemaLocationhttp:www。ehcache。orgv3http:www。ehcache。orgschemaehcachecore。xsdcachealiasfookeytypejava。lang。Stringkeytypevaluetypejava。lang。Stringvaluetyperesourcesheapunitentries20heapoffheapunitMB10offheapresourcescachecachetemplatenamemyDefaultskeytypejava。lang。Longkeytypevaluetypejava。lang。Stringvaluetypeheapunitentries200heapcachetemplatecachealiasbarusestemplatemyDefaultskeytypejava。lang。NumberkeytypecachecachealiassimpleCacheusestemplatemyDefaultsconfig
3。x版本与2。x版本有所区别,在xml配置文件上非常明显。2。x中以ehcache元素为根节点,而3。x则以config为根节点。
在上述xml中包含三部分:普通缓存cachefoo:别名为foo的缓存,缓存的KeyValue值类型均为String。如果没有指定,默认就是Object类型。缓存模板cachetemplate:实现一个配置抽象,以便在未来可以进行扩展;基于缓存模板的cachebar:使用了cachetemplate模板myDefaults,并且覆盖了keytype类型,myDefaults的keytype是Long类型,覆盖后成了Number类型;
cache中其他属性及元素:name为名称;alias为别名;keytype为key的类型;valuetype为value的类型;heap指定堆中可创建的实体格式,其中unitentries,表示后面的20是实体;offheap表示在开始淘汰过期缓存项之前,可以分配多达10M的堆内存;usestemplate表示使用模板的名称;
当然,也可以通过persistence元素来配置缓存的目录等。其他属性的使用,大家可以慢慢探索。基于SpringBoot使用EhCache
前面已经提到,Spring对缓存进行了支持,SpringBoot也对缓存进行了自动配置的支持。下面就基于SpringBoot来完成EhCache的集成以及使用案例演示。
在SpringBoot中引入对应的starter:!ehcache依赖dependencygroupIdorg。springframework。bootgroupIdspringbootstartercacheartifactIddependencydependencygroupIdorg。ehcachegroupIdehcacheartifactIdversion3。9。6versiondependency
在application。properties中配置添加如下配置:spring。cache。ehcache。configehcache。xml
在SpringBoot启动类上添加EnableCaching注解:EnableCachingSpringBootApplicationMapperScan(com。secbro。mapper)publicclassSpringBootMainApplication{publicstaticvoidmain(String〔〕args){SpringApplication。run(SpringBootMainApplication。class,args);}}
创建一个用户缓存的实体类Person:DatapublicclassPerson{publicPerson(intid,Stringname){this。this。}privateS}
对应的Service方法实现:publicinterfacePersonService{PersongetById(intid);}Slf4jService(personService)publicclassPersonServiceImplimplementsPersonService{Cacheable(valuepersonCache,keyid)OverridepublicPersongetById(intid){log。info(查询id{}的用户,id);if(id1){returnnewPerson(1,Tom);}elseif(id2){returnnewPerson(2,Jim);}returnnewPerson(3,Other);}}
通过Spring提供Cacheable注解指定了缓存的名称为personCache,key为id。在方法内打印日志,如果调用到方法内,则会打印。
编写单元测试类:Slf4jSpringBootTestTestMethodOrder(MethodOrderer。OrderAnnotation。class)classPersonServiceTest{ResourceprivatePersonServicepersonSorg。junit。jupiter。api。Order(1)TestvoidtestCache()throwsInterruptedException{log。info(第1次查询id1的数据);personService。getById(1);log。info(第2次查询id1的数据);personService。getById(1);Thread。sleep(3000);}}
两次调用对应的方法,打印日志如下:c。s。s。PersonServiceTest:第1次查询id1的数据c。s。s。i。PersonServiceImpl:查询id1的用户c。s。s。PersonServiceTest:第2次查询id1的数据
可以看到,第一进入方法内进行查询,第二次便走了缓存。
关于Spring提供的cache注解的使用还有很多使用方法和场景,这里就不再展开了。小结
因为工作恰好用到该技术,就钻研并写成文章带大家领略了EhCache的基本知识、技术架构、使用场景、API使用以及基于SpringBoot的集成。整体而言,算是入门级别的,大家可以在此基础上进一步学习扩展。至于EhCache对分布式的支持部分,本文并未涉及,主要原因是使用起来并没那么好用,如果感兴趣的话可自行研究。
作者:二师兄来源:https:mp。weixin。qq。comsdSs94d2iiAkrOlpkQIJag
投诉 评论
灵性的存在身为灵性的存在,一开始让我们迷失的,不是我们的心智,情绪,身体没有问题,这些都不是最初的原因,而是在我们身为神圣形式存在时,心里有一些错误的想法,而你相信了这些想法,又因你有与……
新诗采撷高洪刚秋,凉了(外一首)秋,凉了秋,凉了,树叶黄了,秋风吹起,片片金黄。叶落归根,拥抱大地。雁叫声声,叫凉了秋水,要流向冰清玉洁的世界。寒露……
乌克兰切尔诺贝利的野外早已是人间禁区却处处皆是美景冬天的时候,大雪覆盖了乌克兰切尔诺贝利的禁区。当春天终于来临之时,所有的雪都开始融化了许多地方被洪水淹没,无法通行。2013年的春天,一名乌克兰摄影师来到了切尔诺贝利,拍摄了这……
3款新品电动车,造型漂亮,最高续航143公里,价格2800起您在阅读前请点击上面的关注二字,后续会为您提供更多有价值的相关内容,感谢您的支持。现在电动车市场主要以90、00后为主,大家买车主要看的还是颜值,高颜值的电动车第一印象就……
这是影响深远的律师工作求解西藏无律师县2022年8月,西藏加查县,王成(左二)在接待前来咨询的民众。(受访者供图图)正如许多初次进藏的旅行者会缺氧、头疼、有高原反应,律师事务所在西藏无律师县落地扎根,开始时也……
遛娃圈小有名气的六个新晋乐园太有创意,第一个就堪称重量级不得不说帝都的资源是真豪,一有新开必属精品,这不小爱又给大家报喜讯来啦!各种新开遛娃地直戳老母亲的心巴,尤其第一个户外乐园,终于在万众期待中落户帝都。顶流面前,其他……
尴尬境地?C罗为首发而战,无人对他报价TheAthletic记者AdamCrafton透露,C罗将留队,曼联没有收到任何能踢欧冠的俱乐部为这名葡萄牙球星开出的报价。任何球队要签C罗必须要解决3个难题,1。7号球衣问……
活好今天,别让幸福过期有人说人生在世,不过短短三万多天。其实说白了,这三万多天,也不过就是昨天、今天和明天。昨天已逝,明天还远,我们只有照管好今天,才能尽享生活的美好!每个清晨,当我们睁开惺松……
卡塔尔世界杯B组,这是一个很特别的小组,政治味道浓厚头条创作挑战赛第22届世界杯还有不到1个月的时间就要开幕,这一届世界杯比较有意思,卡塔尔作为赛事举办方,但他们的国家足球队在以前却从未杀入过世界杯正赛,这一次……
红毯路透,金晨穿丑衣娜扎绿色高定变公主,刘雯黑裙轻松出圈最近,vogue举办了一场非公开的展览活动,没有公开的红毯,但是到场的明星嘉宾们都盛装出席,这场活动的造型生图输出全靠记者们的场外蹲守抓拍,我们一起来看看各位明星们的造型。金晨……
周星驰玩水枪弄湿嫩模?林允为其停经4月?已婚?星爷被造谣太惨星爷最近晒出了自己和爱宠的日常,他给小狗狗戴上了墨镜,狗子超级酷。话说狗子的代号还是凌凌玖,狗生着实让人羡慕。最近几年星爷动态不多,但总是人在家中坐,锅从天上来,被港媒各……
周三A股重要投资机会万亿市场华为正研发下一代卫星通讯技术在北斗卫星消息硬件的加持下,华为Mate50系列成为业界首款支持北斗卫星消息的大众智能手机。据报道,华为正在研发下一代卫星通讯技术,共……