EHCache学习

孙承
2023-12-01

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

  • https://documentation.softwareag.com/onlinehelp/Rohan/tc-ehcache_10-2/webhelp/index.html#page/tc-ehcache-webhelp/co-srv_cluster_architecture.html
  • Clustered Cache由Terracotta提供Cache服务
  • Terracotta Server通过off-heap实现Cache存储

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

转载于:https://www.cnblogs.com/judesheng/p/10622248.html

 类似资料: