EHCache學習


EhCache 基礎知識

吐嘈

  • clusteredShared的size會直接占用內存,而不是像redis那用動態的增大
  • clusteredDedicated能夠動態增大,但是還是必須指定每個cache的大小,不但造成浪費,還增加開發難度

Getting Start

  • http://www.ehcache.org/documentation/3.5
  • EHCache支持兩種創建方式:代碼創建,XML配置文件創建
  • EHCache支持分布式的Cache集群,Cache的服務由Terracotta提供
  • Maven dependency
    1. org.ehcache : ehcache
      1. ehcache.3.5.2.jar
    2. org.ehcache : ehcache-clustered
      1. ehcache-clustered.3.5.2.jar

EHCache的分層架構

  • heap : 最快最小
  • offheap : 大而快
  • disk :磁盤持久化,當CacheManager在close()之后,會把所有數據持久化,下次重啟后會恢復

Tiering 分層架構

heap

  • 堆內存,無需序列化所以最快,但是容量有限
  • 可以指定Entry個數,或者內存大小,默認為Entry個數
  • heap層在多層Cache架構中是必須的,分層架構的Cache大小應該是金字塔式的
  • 只有heap能在運行時改變大小,通過ResourcePools的updateResourcePools()

offheap

  • 堆外內存,需要序列化和反序列化,容量大但是比較慢
  • 通過DirectByteBuffer的native方法分配堆外內存,通過c來分配,對外內存不受JVM管理,無法垃圾回收
  • 必須指定資源池大小,當資源池滿了之后會觸發淘汰策略
  • 大緩存,命中率低的緩存都可以放在off-heap
  • -XX:MaxDirectMemorySize,設置JVM堆外內存大小,和offheap大小對應
  • 使用offheap可以減小JVM垃圾回收壓力,提高性能

disk

  • 可以設置是否Persistence ,Persistence 意思是重啟JVM時cache會被還原
  • 一個disk/persistence directory只能被一個cache managers使用
  • 當CacheManager在close()之后,會把所有數據持久化,JVM down機不管用
  • 持久化的過程是一個分段的並發操作,默認16個線程並發,可以通過減少段落來減少並發

Clustered

  • Terracotta服務提供遠程分布式Cache服務
  • Clustered和disk無法共存
  • PersistentCacheManager的destroy()可以刪除所有disk或者clustered的cache,這個方法必須在cache manager關閉close()之后
  • destroyCache(String cacheName)清除指定cache,必須保證沒有其他cache manager在使用此manager
  • put cache首先put到底層tier,上層通過get獲取底層cache,get cache則相反,所以底層越慢,put越慢

附加設置

  • withSizeOfMaxObjectSize:設置單個Entry的大小限制
  • withSizeOfMaxObjectGraph
  • withDefaultSizeOfMaxObjectSize/withDefaultSizeOfMaxObjectGraph:在CacheManager 層設置而不一定要每個Cache都指定

疑問

  • Manage the CacheManager/Cahce/Entity

  • load balance

  • Thread Pools線程池

  • 在不指定的時候server resource的時候,是否從defaultServerResource分配

  • get cache的thread pool

  • cache sync的時間間隔

  • 重新啟動是否還有pre-active的信息

  • ClentReconnectWindow 到時間后 exp...()是否連接的上

  • 在reconnect期間clinet是否重復發送請求,直到連接成功

  • SimpleKey/String key /Key Gernorator規則

  • EhCache和Terrcotta官網剩余部分

EhCache高級配置

Cluster server配置

  • CacheManager通過terracotta://168.72.230.65:9411/app-name連接cluster server
  • 創建CacheManager實例
    1. clusteredDedicated的大小必須比heap大,但是clusteredShared沒有這種檢查,但是也需要遵守金字塔原則
    2. getCache必須要有withCache或者createCache將cluster server的cache同步到本地CacheManager實例
    3. withCache或者createCache的ClusteredResourcePoolBuilder可以用.clustered()來繼承cluster server已有的cache的配置
  • 連接同名CacheManager實例
    1. 一個cluster server只有一個同名(app-name名字相同)的CacheManager實例與之連接,其他的同名CacheManager必須連接已有的這個CacheManager
    2. with的ClusteringServiceConfigurationBuilder的配置必須相同
    3. withCache的ClusteredResourcePoolBuilder的配置必須相同,但其他與cluster無關的配置不需要相同
    4. withCache的ClusteredResourcePoolBuilder寫defaultServerResource與不寫是不同的配置,不能連接
    5. withCache有新增的cache,或者是有新的createCache時,無法鏈接,必須用autoCreate,在原來的CacheManager實例里創建新的cache並且連接
    6. withCache不需要with所有cluster的cache
    7. 不申明autoCreate或者expecting的時候,可以省略ClusteringServiceConfigurationBuilder的配置,cache 消費者使用這種方式
    8. 使用autoCreate或者expecting的時候,配置必須保持一致,維護麻煩
      1. 可以用單例模式全局變量等方式配置ClusteringServiceConfigurationBuilder
      2. 不同的項目可以用common.jar,但是麻煩
      3. 約定,但是維護麻煩

Cache配置的繼承

  • clustered() : cache會繼承server端已有的cache的配置
  • 第一個client的CacheManager用autoCreate,並且必須有Dedicated或者Shared pool配置
  • 第二個client的CacheManager用expecting,並且用clustered不申明pool的配置
  • createCache名字和第一個相同
  • 好處:
    1. 簡化cache配置
    2. 減少分配pool的錯誤
    3. sizing計算只需要在一個client端進行
    4. 不必擔心配置匹配

EhCache的數據刷新機制采用Expiry機制

  • timeToLiveExpiration:從創建cache entry開始計算,一段時間后過期
  • timeToIdleExpiration : 從最后一次訪問cache entry開始計算,只有heap里的cache entry生效,訪問clustered cache不會被認為是對cache的一次access,這絕對是個bug
  • noExpiration : 永不過期
  • 還可以實現自定義的過期機制
  • 過期的Entry會被從當前cache刪除,同時刪除clustered的Entry,過期並不會刪除cache

Consistency 一致性

  • Eventual一致性模式下,任何對cluster的cache的修改,並不一定會及時反映到client端
  • Strong一致性模式下,任何對cluster的cache的修改,都會及時的反應到client端,由於需要操作所有client端,所以put等操作可能會比較耗時

淘汰策略

Cache模式

  • Cache-aside
    1. 先從cache拿,如果沒有,從SoR(比如數據庫)拿,然后存Cache,然后返回結果
    2. 寫入SoR的時候,可以同時寫入Cache
  • Cache-as-SoR
    1. Read-through : 先從cache拿,如果沒有,cache調用loader從SoR拿,然后存cache,然后返回cache
    2. Write-through : 寫入cache請求來的時候,cache調用writer存SoR,同時存cache
    3. Write-behind : 與Write-through的區別在於寫入SoR是一個異步的操作,先寫cache,然后結束,令一個線程去寫SoR,writer-behind不支持retry,需要自己實現
    4. Cluster不支持Cache-as-SoR
    5. 需要實現接口CacheLoaderWriter
    6. 好處
      1. application端代碼簡單,可維護性高
      2. 使得消費者與SoR隔離
      3. 提高性能
    7. 壞處
      1. cache端代碼復雜
      2. 不同的CacheLoaderWriter實行需要創建不同的cache

事務管理

Thread Pools線程池

  • OnDemandExecutionService : 在任務不指定線程池時使用的默認方式,每次都會創建一個新的線程池來執行任務,新的線程池對不同任務有對應的默認線程個數
  • PooledExecutionService :自定義線程池,用PooledExecutionServiceConfiguration 來配置
  • 自定義線程池用於惡劣環境下提高性能

EhCache類型詳解

CacheManager

CacheManagerBuilder

  • 用於創建CacheManager
  • with(Builder[CacheManagerConfiguration]) : 用於配置CacheManager,比如disk的路徑或者cluster的URL等
  • using(ServiceCreationConfiguration)
  • withCache("cahceName", Builder[CacheConfiguration]) : 定義/配置一個cache
  • build(boolean init) : 創建一個初始化/未初始化的CacheManager實例
  • withDefaultDiskStoreThreadPool(alias) : 默認磁盤化線程池
  • withDefaultWriteBehindThreadPool(alias) :默認寫Cache線程池
  • withDefaultEventListenersThreadPool(alias) :默認事件監聽線程池

ClusteringServiceConfigurationBuilder : with

  • 用於配置CacheManager,從哪個cluster的哪些resource分配多少pool給CacheManager
  • cluster(URI) : 創建cluster服務連接,設置CacheManager實例名字
  • autoCreate() : 如果不存在一個cluster層的同名CacheManager實例,則創建一個,如果存在並且配置相同,便會建立連接,如果配置不同則CacheManager init會失敗
  • expecting() : 如果存在並且配置相同,那么便會建立連接,否則CacheManager init會失敗
  • autoCreate/expecting不申明,如果存在,不管配置相同不相同都會建立連接,否則CacheManager init會失敗
  • defaultServerResource("server-resource-name") : 設置默認的tc offheap resource,供CacheManager使用
  • resourcePool("pool-a", 28, MemoryUnit.MB, "secondary-server-resource") : 從tc的名字為secondary-server-resource的resource分配一個28MB的pool,如果不指定resource,從默認resource創建

PooledExecutionServiceConfigurationBuilder : using

  • defaultPool(alias, minSize, maxSize) : 不指定thread pool時使用
  • pool(alias, minSize, maxSize) : 添加一個thread pool,供任務使用

CacheManager

  • init()
  • close()
  • destroy() : PersistentCacheManager的destroy()可以刪除所有disk或者clustered的cache,這個方法必須在所有連接此配置的cache manager close()之后
  • createCache("cache-name",Builder[CacheConfiguration]) : 與CacheManagerBuilder的withCache一樣
  • getCache("cache-name", String.class, String.class)
  • removeCache("cache-name") : 刪除本地CacheManager里的cache對象,不會銷毀clustered的cache entry
  • destroyCache("cache-name") : 刪除本地CacheManager里的cache對象,同時銷毀clustered的cache entry,但是不能有其他cache manager在使用這個cache

Cache

CacheConfigurationBuilder : withCache/crateCache

  • 用於配置Cache
  • newCacheConfigurationBuilder(Long.class, String.class, Builder[ResourcePools])
  • withSizeOfMaxObjectSize(1, MemoryUnit.MB) : 設置單個Entry的最大size,超過大小的將無法存到cache
  • withDefaultSizeOfMaxObjectGraph(2000) : ?
  • add(Builder[ServiceConfiguration])
  • add(new OffHeapDiskStoreConfiguration(2)) : disk的持久化的過程是一個分段的並發操作,默認16個線程並發,可以通過減少段落來減少並發
  • withExpiry(ExpiryPolicy) : 過期策略
  • withDiskStoreThreadPool(threadPoolAlias, concurrency) : 使用指定線程池和指定並發數來寫磁盤,與add(new OffHeapDiskStoreConfiguration(2)) 功能相似
  • withEventListenersThreadPool(threadPoolAlias) :使用指定線程池給事件監聽任務,等同於add(new DefaultCacheEventDispatcherConfiguration(threadPoolAlias))
  • withLoaderWriter(CacheLoaderWriter) : 實現CacheLoaderWriter來實現Cache-throught模式

ResourcePoolsBuilder : CacheConfigurationBuilder

  • heap(10, EntryUnit.ENTRIES) : 最多10個entry
  • heap(10, MemoryUnit.MB) : 最多10MB
  • offheap(10, MemoryUnit.MB) :只能是MemoryUnit
  • disk(20, MemoryUnit.MB, true) :只能是MemoryUnit,Persistence=true 意思是重啟JVM時cache會被還原,默認false
  • with(ResourcePool) : 添加一個ResourcePool,與ClusteredResourcePoolBuilder合用,定義cluster層

ClusteredResourcePoolBuilder : with

  • 所有方法都是返回一個ResourcePool,而不是返回Builder
  • clusteredDedicated("primary-server-resource", 128, MemoryUnit.MB) : 為Cache從指定server resource分配一個專用的resource pool
  • clusteredShared("pool-b") : 為Cache指定一個可分享的resource pool,這個resource pool能被其他Cache使用,當一個Cache從一個shared pool中分配了一定內存空間后,這些空間不會被釋放也無法分配給其他Cache
  • clustered() : cache會繼承server端已有的cache的配置
    1. 第一個client的CacheManager用autoCreate,並且必須有Dedicated或者Shared pool配置
    2. 第二個client的CacheManager用expecting,並且用clustered不申明pool的配置
    3. createCache名字和第一個相同
    4. 好處: 簡化cache配置,減少分配pool的錯誤,sizing計算只需要在一個client端進行,不必擔心配置匹配

ClusteredStoreConfigurationBuilder : add

  • 與CacheConfigurationBuilder 的add合用
  • withConsistency(Consistency.EVENTUAL) : Eventual一致性模式下,任何對cluster的cache的修改,並不一定會及時反映到client端
  • withConsistency(Consistency.STRONG) : Strong一致性模式下,任何對cluster的cache的修改,都會及時的反應到client端,由於需要操作所有client端,所以put等操作可能會比較耗時

ExpiryPolicyBuilder : withExpiry

  • timeToLiveExpiration(Duration) :從創建cache entry開始計算,一段時間后過期
  • timeToIdleExpiration(Duration) : 從最后一次訪問cache entry開始計算
  • noExpiration() : 永不過期,默認設置

WriteBehindConfigurationBuilder :add

  • newBatchedWriteBehindConfiguration(2, TimeUnit.SECONDS, 5) :批處理滿5個后執行,最多延遲2秒,2秒后批處理不滿5個也執行
  • queueSize(3) :單個隊列最多積壓3個write-behind的bathcing操作,否則無法進行其他cache操作
  • concurrencyLevel(2) :最多2個並發,並且有兩個隊列, 所以最多積壓bathcing操作數=concurrencyLevelqueueSize=23=6,最多積壓writhe數=concurrencyLevelqueueSizebatchSize=235=30
  • enableCoalescing() : 開啟合並操作,使得對單個cache entry的update在一次批處理中只執行一次,只有最晚的一次會發給CacheLoaderWriter
  • write-behind提高write cache和write SoR的性能

CacheEventListenerConfigurationBuilder : add

Ehcache

  • cache的key,value必須implements Serializable
  • forEach()/iterator()方法沒有被實現,也就是無法遍歷cache里的所有Entry

Terracotta Server

Getting Start

Terracotta Server Array (TSA)的三種拓撲模式

  • Single-server cluster
  • High-availability cluster
    1. 只有一個stripe包含至少一個active和多個possive服務器
    2. 把所有server配到servers
    3. server name 不能相同
    4. 把所有server啟動
  • Multi-stripe cluster
    1. 多個相互獨立的stripe,通過增加stripes可增加存儲容量
    2. stripe與stripe之間沒有聯系,緩存不同步,無法實現load balance

Active and Passive Servers

  • Active server的職責
    1. Active 負責直接與client交互,當沒有active的時候client默認無限等待,沒有默認的time-out
    2. Active 負責傳遞數據給Passive用於同步數據
    3. Active 負責同步請加入的server的狀態,使其能STANDBY,表示數據完全同步
  • Active的選舉規則
    1. 第一個啟動的為Active,其他只是Passive
    2. 當Active下線,會通過以下情況打分決定
      1. 只有State[ PASSIVE-STANDBY ]的server有資格成為active
      2. server處理的交易量
      3. server啟動時間
      4. 隨機選擇一個,如果兩個server達成平局
  • Client如何連接到Active server
    1. 除非出現網絡異常等情況,所有server之間都相互保持着溝通的通道
    2. 連接stripe的任意一台server1的時候,client會通過這些通道遍歷的嘗試連接所有的server,直到找到會給出回應的active server
    3. 隨后client會保持連接這台server,直到server下線,並且client會保存這台active server的信息
    4. 當active server下線,client會繼續通過這些通道尋找下一台active server,並且保存這台active server的信息
    5. 如果client最開始連接的server1出現問題,無法通過它的通道尋找active server的時候,client會通過所有保存過的pre-active server的通道去尋找
    6. 這樣的機制就決定了client最好使用最后啟動的passive作為嘗試連接的server,決不要用active的server,當active下線的時候,最好能馬上充啟
  • 多個stripe之間不能共用Passive

Failover Tuning故障轉移策略(參考CAP定理)

  • Client Reconnect Window
    1. 當發生故障, client需要重新連接到新的active server,轉換成功之前,client拿不到連接
    2. 在全部client重新連接或者Reconnect Window time-out之前,新的active server會暫停所有響應,即使一個用戶發生問題,所以用戶都需要等待至Reconnect Window time-out
    3. Client Reconnect Window默認120s, 之后會清除所有沒有重連的client
    4. 在Client Reconnect Window之后連接的client,都會以新用戶的方式重新創建一個新的連接
    5. tc-config.xml配置servers:client-reconnect-window
    6. 在重新連接之后,active server第一次會重新發送client上次請求的數據
  • availability / consistency
    1. 當stripe的server由於網絡等異常被分割成兩個set,選擇availability 或者consistency之一會產生不一樣的策略
    2. availability
      1. 沒有active的部分,會選舉一台passive成為active,這時候兩個set獨立開來,都可能為client提供服務,造成數據不一致
      2. 由於連接任意set服務器的client都能找到active,所以不會阻塞client的請求,但是不保證數據一致性
    3. consistency
      1. 擁有更多數的server的set會選舉一台active,其他set都變成passive
      2. 這樣會造成連接passive的set的client無法找到active,某些client請求無法保證
      3. 但是這樣能保證數據的一致性
      4. 只有兩台的strape的TSA沒有任何一台會被認為是多數的,所以不會有active,建議consistency使用奇數服務器
      5. 也可以使用第三方vote開完成active選舉
      6. 可以自己實現循環所有server來尋找active,保證可用性

啟動Terracotta Server

  • config/tc-config.xml
    1. 同一個stripe的server共用同一個tc-config.xml,不同的stripe需要不同的tc-config.xml
    2. offheap-resources
    3. tsa-port : 默認9410
    4. tsa-group-port : 默認9430,如果不指定,會根據tsa-port自動設置,比如tsa-port=9411,那么tsa-group-port=9431
  • ./bin/start-tc-server.sh -n server-name -f ../config/tc-config.xml

Terracotta 實現load balance

Terracotta Management and Monitoring

JCache using Ehache as Provider

Getting Start

  • Maven Dependency
    1. javax.cache : cache-api
  • classpath 下有JCache和EhCache jar包
  • classpath 下其他JCache Provider需要清除
  • Caching.getCachingProvider();會自動去classpath 尋找Provider
  • 如果還有其他JCache Provider,可以使用Caching.getCachingProvider(org.ehcache.jsr107.EhcacheCachingProvider)來指定
  • 當使用EhCache Cluster的時候,無法使用EhCache的Cache對象鏈接JCache的Cache對象

Sample Code

//JCache CachingProvider and EhcacheCachingProvider 
CachingProvider cachingProvider = Caching.getCachingProvider();
EhcacheCachingProvider ehcacheProvider = (EhcacheCachingProvider) cachingProvider; 

//EhCache ServiceCreationConfiguration setting
ServiceCreationConfiguration<ClusteringService> clusteringServiceConfiguration = ClusteringServiceConfigurationBuilder
    .cluster(URI.create("terracotta://168.72.230.65:9412/rates-ehcache"))
    .build();

//EhCache CacheConfigurationsetting
CacheConfiguration<SimpleKey, String> cacheConfiguration = CacheConfigurationBuilder
        .newCacheConfigurationBuilder(
                SimpleKey.class, String.class,
                ResourcePoolsBuilder.newResourcePoolsBuilder()
                    .heap(64, MemoryUnit.MB)
                    .with(ClusteredResourcePoolBuilder.clustered())
        )
        .build();

//the same as withCache in EhCache
Map<String, CacheConfiguration<?, ?>> caches = new HashMap<String, CacheConfiguration<?, ?>>();
caches.put("cache-bond", cacheConfiguration);

//Use EhCache Config to create JCache CacheManager 
DefaultConfiguration configuration = new DefaultConfiguration(caches, ehcacheProvider.getDefaultClassLoader(), clusteringServiceConfiguration);

CacheManager cacheManager = ehcacheProvider.getCacheManager(ehcacheProvider.getDefaultURI(), configuration);

// User EhCache Cache config to create cache by JCache CacheManager 
Configuration<String, String> conf = Eh107Configuration.fromEhcacheCacheConfiguration(cacheConfiguration);
cacheManager.createCache("cache-test", conf);

Differences

  • heap-only 的cache存儲默認by-reference or by-value
    1. JCache默認by-value,只能使用Serializable 的key和value
    2. Ehcache默認by-reference
  • Cache-through and compare-and-swap operations
    1. putIfAbsent(K, V)等compare-and-swap操作下,JCache默認在put成功后才會

    2. EhCache默認總是調用CacheLoaderWriter 去更新SoR,可以使用以下配置設置EhCache使用JCache一樣的設置

       <service>
         <jsr107:defaults jsr-107-compliant-atomics="true"/>
       </service>
      

Spring Cache整合EhCache by JCache

Getting Start

  • https://spring.io/guides/gs/caching/
  • Maven Dependency
    1. org.springframework.boot : spring-boot-starter-cache
  • CacheManager
    1. 默認使用ConcurrentHashMap
  • @EnableCaching,@Cacheable, @CachePut and @CacheEvict
  • 建議不要將Spring Cache annotation和JCache annotation混合使用

Spring Cache整合EhCache原理

  • SpringCache按以下順序在classpath尋找CacheManager提供者
    1. Generic
    2. JCache (JSR-107)
    3. EhCache 2.x
    4. Hazelcast
    5. Infinispan
    6. Redis
    7. Guava
    8. Simple
  • 除了按順序尋找,也可以用spring.cache.type指定
  • 用JCache作為Spring Cache的CacheManager Provider
    1. 如果有javax.cache.CacheManager的Bean被定義,將被自動封裝在一個默認的org.springframework.cache.CacheManager的實現里面
    2. 這個功能由org.springframework.boot.autoconfigure.cache.JCacheCacheConfiguration的cacheManager方法實現
    3. 使用@Bean定義javax.cache.CacheManager, bean名字不能使cacheManager
    4. 不支持多個javax.cache.CacheManager的Bean存在
    5. 但它並不是一個org.springframework.cache.CacheManager,無法使用在@Cachable(cacheManager)上面
    6. @Cachable(cacheManager="cacheManager") : 這里的cacheManager就是JCacheCacheConfiguration的cacheManager方法的Bean
  • 使用multiple CacheManager
    1. 創建javax.cache.CacheManager : jCacheManager
    2. 創建JCacheCacheManager Bean : new JCacheCacheManager(jCacheManager);
    3. new CacheManagerCustomizers(null).customize(cacheManager);
  • 如果EhCache的cache配置中key,value的value不適String,而是自定義對象,會造成序列化問題
    1. producer使用Ehcache默認使用PlainJavaSerializer序列化方式
    2. web應用整合spring cache默認使用CompactJavaSerializer序列化方式
    3. 需要指定其中一種CacheConfiguration : .withValueSerializer(new PlainJavaSerializer (ClassLoading.getDefaultClassLoader()))

Spring Cache和EhCache的使用

  • 可以使用SpringCache創建Cache,用EhCache獲取Cache
  • 也可以使用EhCache創建Cache,用SpringCache獲取Cache

Spring Cache詳解

Manager the Cache


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM