<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          大廠都在用EhCache,它到底比Redis強(qiáng)在哪里?

          共 6806字,需瀏覽 14分鐘

           ·

          2021-12-18 17:49

          故事背景

          隨著硬件價格的走低,大家對硬件的依賴越來越高。甚至聽說,代碼不重要,不行就加機(jī)器唄。比如緩存的使用,通常有基于虛擬機(jī)內(nèi)存、基于磁盤存儲、基于中間件(Redis內(nèi)存)等方式,我們都知道,最適合的才是最好的,但實(shí)踐中,往往是動不動就直接上Redis。

          那么,Redis一定是最好的選擇嗎?單不說對內(nèi)存的要求,從效率和性能上來說,也未必是最優(yōu)的。所以,不同的場景使用不同的緩存策略才是高手應(yīng)該追求的。

          這篇文章就帶大家認(rèn)識除Redis之外的另一種緩存框架:EhCache。之所以要寫寫,也是因?yàn)轫?xiàng)目中運(yùn)用了此框架,同時又遇到點(diǎn)問題,于是決定深入研究一下。研究之后,發(fā)現(xiàn)還真有點(diǎn)意思~

          EhCache簡介

          EhCache是一個純Java的進(jìn)程內(nèi)緩存框架,具有快速、精干的特點(diǎn)。注意的這里的關(guān)鍵字進(jìn)程,基于進(jìn)程的緩存直覺告訴我們效率肯定要高一些,因?yàn)樗苯釉谶M(jìn)程之內(nèi)進(jìn)行操作,但不同應(yīng)用之間緩存的共享可能就會有問題。

          EhCache是Hibernate中默認(rèn)的CacheProvider,Spring Boot也對其進(jìn)行了支持,Spring中提供的緩存抽象也支持對EhCache緩存框架的綁定,而且支持基于注解的方式來使用。因此,EhCache是一款被廣泛使用的基于Java的高速緩存框架,使用起來也非常方便。

          EhCache提供了多種緩存策略,主要分為內(nèi)存和磁盤兩級,是一款面向通用緩存、Java EE和輕量級容器的緩存框架。

          EhCache的特點(diǎn)

          簡單說一下該框架的特點(diǎn):

          • 簡單、快速,擁有多種緩存策略;
          • 緩存數(shù)據(jù)有兩級:內(nèi)存和磁盤,無需擔(dān)心容量問題;
          • 緩存數(shù)據(jù)會在虛擬機(jī)重啟的過程中寫入磁盤;
          • 可以通過RMI、可插入API等方式進(jìn)行分布式緩存;
          • 具有緩存和緩存管理器的偵聽接口;
          • 支持多緩存管理器實(shí)例,以及一個實(shí)例的多個緩存區(qū)域,并提供Hibernate的緩存實(shí)現(xiàn);

          EhCache可以單獨(dú)使用,但通常會與Mybatis、Shiro等三方類庫結(jié)合使用。本人項(xiàng)目中使用EhCache就是結(jié)合Shiro來使用的。

          除了優(yōu)點(diǎn),EhCache也還有一些缺點(diǎn)。比如,非常占用磁盤空間,這是因?yàn)镈iskCache的算法簡單,只是對元素直接追加存儲。這樣雖然可以提高效率,但在使用頻繁的系統(tǒng)中,磁盤很快會滿。

          另外就是不能保證數(shù)據(jù)安全,當(dāng)然突然kill掉Java進(jìn)程時,可能會產(chǎn)生沖突。EhCache解決沖突的方法是重建Cache,這對Cache數(shù)據(jù)需要保持時可能會產(chǎn)生影響。Cache只是簡單的加速,不能保證數(shù)據(jù)的安全。

          EhCache與Redis

          EhCache直接在JVM中進(jìn)行緩存,速度快,效率高。與Redis相比,操作簡單、易用、高效,雖然EhCache也提供有緩存共享的方案,但對分布式集群的支持不太好,緩存共享實(shí)現(xiàn)麻煩。

          Redis是通過Socket訪問到緩存服務(wù),效率比EhCache低,比數(shù)據(jù)庫要快很多,處理集群和分布式緩存方便,有成熟的方案。

          所以,如果是單體應(yīng)用,或?qū)彺嬖L問要求很高,可考慮采用EhCache;如果是大型系統(tǒng),存在緩存共享、分布式部署、緩存內(nèi)容很大時,則建議采用Redis

          EhCache架構(gòu)圖

          看一下EhCache的架構(gòu)圖,大概了解一下它由幾部分組成。

          Ehcache-architecture

          Cache Replication部分提供了緩存復(fù)制的機(jī)制,用于分布式環(huán)境。EhCache最初是獨(dú)立的本地緩存框架組件,在后期的發(fā)展中,結(jié)合Terracotta服務(wù)陣列模型,可以支持分布式緩存集群,主要有RMI、JGroups、JMS和Cache Server等傳播方式進(jìn)行節(jié)點(diǎn)間通信。

          In-process APIs則提供了基于JSR、JMX等標(biāo)準(zhǔn)的支持,能夠較好的兼容和移植,同時對各類對象有較完善的監(jiān)控管理機(jī)制。

          Network APIs則對外提供了基于RESTful API、JMS API、Cache Server等方式的支持。

          在使用過程中,需要關(guān)注的核心部分便是中間的Core部分了。它包含了核心的API和概念:

          • CacheManager:緩存管理器,可以通過單例或者多例的方式創(chuàng)建,也是Ehcache的入口類。
          • Cache:每個CacheManager可以管理多個Cache,每個Cache可以采用hash的方式管理多個Element。所有cache都實(shí)現(xiàn)了Ehcache接口;
          • Element:單條緩存數(shù)據(jù)的組成單位,用于存放真正緩存內(nèi)容的。

          三者的管理可以用下圖表示:

          CacheManager

          緩存過期策略

          在架構(gòu)圖中還可以看到Memory Store LRU、Memory Store LFU、Memory Store FIFO等內(nèi)存存儲算法。也就是當(dāng)緩存占用空間接近臨界值時,會采用上面的淘汰策略來清理掉一部分?jǐn)?shù)據(jù)。

          EhCache提供了三種淘汰算法:

          • FIFO:First In First Out,先進(jìn)先出。判斷被存儲的時間,離目前最遠(yuǎn)的數(shù)據(jù)優(yōu)先被淘汰。
          • LRU:Least Recently Used,最近最少使用。判斷最近被使用的時間,目前最遠(yuǎn)的數(shù)據(jù)優(yōu)先被淘汰。
          • LFU:Least Frequently Used,最不經(jīng)常使用。在一段時間內(nèi),數(shù)據(jù)被使用次數(shù)最少的,優(yōu)先被淘汰。

          Ehcache采用的是懶淘汰機(jī)制,每次往緩存放入數(shù)據(jù)時,都會存一個時間,在讀取時要和設(shè)置的時間做TTL比較來判斷是否過期。

          EhCache實(shí)戰(zhàn)解析

          了解了上面的基礎(chǔ)知識之后,來實(shí)驗(yàn)一下EhCache如何使用。其中EhCache2.x和EhCache3.x的使用差距較大。

          這里采用比較新的3.9.6版本,不同的版本在API的使用上會有所差異。

          基于API使用EhCache

          EhCache提供了基于API和xml兩種形式創(chuàng)建CacheManger和Cache。先來看基于API的形式:

          在pom文件中引入EhCache依賴:


          ??????org.ehcache
          ??????ehcache
          ??????3.9.6
          ?

          創(chuàng)建并使用的代碼如下:

          public?class?EhCacheTest?{

          ?@Test
          ?public?void?test()?{
          ??// 1、先創(chuàng)建一個CacheManagerBuilder;
          ??// 2、使用CacheManagerBuilder創(chuàng)建一個預(yù)配置(pre-configured)緩存:第一個參數(shù)為別名,第二個參數(shù)用來配置Cache;
          ??// 3、build方法構(gòu)建并初始化;build中true參數(shù)表示進(jìn)行初始化。
          ??CacheManager?cacheManager?=?CacheManagerBuilder.newCacheManagerBuilder()
          ????.withCache("preConfigured",
          ??????CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class,?String.class,
          ????????ResourcePoolsBuilder.heap(100)).build())
          ????.build(true);

          ??//?取回在設(shè)定的pre-configured,對于key和value值類型,要求是類型安全的,否則將拋出ClassCastException異常。
          ??Cache?preConfigured?=?cacheManager.getCache("preConfigured",?Long.class,?String.class);

          ??System.out.println("從緩存中獲取key為preConfigured:"?+?preConfigured);

          ??//?根據(jù)需求,通過CacheManager創(chuàng)建出新的Cache。實(shí)例化和完整實(shí)例化的Cache將通過CacheManager.getCache API返回。
          ??Cache?myCache?=?cacheManager.createCache("myCache",
          ????CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class,?String.class,
          ??????ResourcePoolsBuilder.heap(100)).build());
          ??//?使用put方法存儲數(shù)據(jù)
          ??myCache.put(1L,?"da?one!");
          ??//?使用get方法獲取數(shù)據(jù)
          ??String?value?=?myCache.get(1L);
          ??System.out.println("從緩存中獲取key為1L:"?+?value);
          ??//?close方法將釋放CacheManager所管理的緩存資源
          ??cacheManager.close();
          ?}
          }

          上述代碼基于API的形式演示了如何創(chuàng)建CacheManager及Cache,并對Cache進(jìn)行設(shè)置和獲取。

          基于XML使用EhCache

          依賴Jar包不變,在src/main/resources/目錄下創(chuàng)建配置文件 ehcache.xml。

          ????????xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
          ????????xmlns='http://www.ehcache.org/v3'
          ????????xsi:schemaLocation="http://www.ehcache.org/v3?http://www.ehcache.org/schema/ehcache-core.xsd">

          ????alias="foo">
          ????????java.lang.String
          ????????java.lang.String
          ????????
          ????????????"entries">20
          ????????????"MB">10
          ????????

          ????

          ????"myDefaults">
          ????????java.lang.Long
          ????????java.lang.String
          ????????"entries">200
          ????

          ????alias="bar"?uses-template="myDefaults">
          ????????java.lang.Number
          ????

          ????alias="simpleCache"?uses-template="myDefaults"?/>


          3.x版本與2.x版本有所區(qū)別,在xml配置文件上非常明顯。2.x中以ehcache元素為根節(jié)點(diǎn),而3.x則以config為根節(jié)點(diǎn)。

          在上述xml中包含三部分:

          • 普通緩存cache-foo:別名為foo的緩存,緩存的Key-Value值類型均為String。如果沒有指定,默認(rèn)就是Object類型。
          • 緩存模板cache-template:實(shí)現(xiàn)一個配置抽象,以便在未來可以進(jìn)行擴(kuò)展;
          • 基于緩存模板的cache-bar:使用了cache-template模板myDefaults,并且覆蓋了key-type類型,myDefaults的key-type是Long類型,覆蓋后成了Number類型;

          cache中其他屬性及元素:

          • name為名稱;
          • alias為別名;
          • key-type為key的類型;
          • value-type為value的類型;
          • heap指定堆中可創(chuàng)建的實(shí)體格式,其中unit="entries",表示后面的20是實(shí)體;
          • offheap表示在開始淘汰過期緩存項(xiàng)之前,可以分配多達(dá)10M的堆內(nèi)存;
          • uses-template表示使用模板的名稱;

          當(dāng)然,也可以通過persistence元素來配置緩存的目錄等。其他屬性的使用,大家可以慢慢探索。

          基于Spring Boot使用EhCache

          前面已經(jīng)提到,Spring對緩存進(jìn)行了支持,Spring Boot也對緩存進(jìn)行了自動配置的支持。下面就基于Spring Boot來完成EhCache的集成以及使用案例演示。

          在Spring Boot中引入對應(yīng)的starter:



          ?org.springframework.boot
          ?spring-boot-starter-cache


          ?org.ehcache
          ?ehcache
          ?3.9.6

          在application.properties中配置添加如下配置:

          spring.cache.ehcache.config=ehcache.xml

          在Spring Boot啟動類上添加@EnableCaching注解:

          @EnableCaching
          @SpringBootApplication
          @MapperScan("com.secbro.mapper")
          public?class?SpringBootMainApplication?{
          ?public?static?void?main(String[]?args)?{
          ??SpringApplication.run(SpringBootMainApplication.class,?args);
          ?}
          }

          創(chuàng)建一個用戶緩存的實(shí)體類Person:

          @Data
          public?class?Person?{

          ?public?Person(int?id,String?name){
          ??this.id?=?id;
          ??this.name?=?name;
          ?}

          ?private?int?id;

          ?private?String?name;
          }

          對應(yīng)的Service方法實(shí)現(xiàn):

          public?interface?PersonService?{
          ?Person?getById(int?id);
          }

          @Slf4j
          @Service("personService")
          public?class?PersonServiceImpl?implements?PersonService?{

          ?@Cacheable(value?=?"personCache",?key?=?"#id")
          ?@Override
          ?public?Person?getById(int?id)?{
          ??log.info("查詢id={}的用戶",?id);
          ??if?(id?==?1)?{
          ???return?new?Person(1,?"Tom");
          ??}?else?if?(id?==?2)?{
          ???return?new?Person(2,?"Jim");
          ??}
          ??return?new?Person(3,?"Other");
          ?}
          }

          通過Spring提供@Cacheable注解指定了緩存的名稱為personCache,key為id。在方法內(nèi)打印日志,如果調(diào)用到方法內(nèi),則會打印。

          編寫單元測試類:

          @Slf4j
          @SpringBootTest
          @TestMethodOrder(MethodOrderer.OrderAnnotation.class)
          class?PersonServiceTest?{

          ?@Resource
          ?private?PersonService?personService;

          [email protected](1)
          ?@Test
          ?void?testCache()?throws?InterruptedException?{
          ??log.info("第1次查詢id=1的數(shù)據(jù)");
          ??personService.getById(1);
          ??log.info("第2次查詢id=1的數(shù)據(jù)");
          ??personService.getById(1);
          ??Thread.sleep(3000);
          ?}
          }

          兩次調(diào)用對應(yīng)的方法,打印日志如下:

          c.s.s.PersonServiceTest??????????????????:?第1次查詢id=1的數(shù)據(jù)
          c.s.s.i.PersonServiceImpl????????????????:?查詢id=1的用戶
          c.s.s.PersonServiceTest??????????????????:?第2次查詢id=1的數(shù)據(jù)

          可以看到,第一進(jìn)入方法內(nèi)進(jìn)行查詢,第二次便走了緩存。

          關(guān)于Spring提供的cache注解的使用還有很多使用方法和場景,這里就不再展開了。

          小結(jié)

          因?yàn)楣ぷ髑『糜玫皆摷夹g(shù),就鉆研并寫成文章帶大家領(lǐng)略了EhCache的基本知識、技術(shù)架構(gòu)、使用場景、API使用以及基于Spring Boot的集成。整體而言,算是入門級別的,大家可以在此基礎(chǔ)上進(jìn)一步學(xué)習(xí)擴(kuò)展。至于EhCache對分布式的支持部分,本文并未涉及,主要原因是使用起來并沒那么好用,如果感興趣的話可自行研究。



          往期推薦



          Dao,Service,Controller,Util,Model代表著什么,為什么這么劃分?

          Log4j史詩級漏洞,從原理到實(shí)戰(zhàn),只用3個實(shí)例就搞明白!

          Log4j史詩級漏洞,我們這些小公司能做些什么?

          實(shí)踐了5千萬的數(shù)據(jù)表和重建索引,學(xué)到了!

          并行Stream與Spring事務(wù)相遇?不是冤家不聚頭~

          數(shù)據(jù)庫時間慢了14個小時,Mybatis說,這個鍋我不背!




          如果你覺得這篇文章不錯,那么,下篇通常會更好。添加微信好友,可備注“加群”(微信號:zhuan2quan)。

          一篇文章就看透技術(shù)本質(zhì)的人,
          ? 和花一輩子都看不清的人,
          ? 注定是截然不同的搬磚生涯。
          ▲?按關(guān)注”程序新視界“,洞察技術(shù)內(nèi)幕
          瀏覽 49
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  波多野结衣在线成人视频 | 秘 看片黄全部免费 | 无码AV免费观看 | 亚洲蜜臀AV乱码久久精品蜜桃图片 | 无码日本精品久久久久久蜜桃 |