本章使用backing maps提供信息存储。

 
1.Cache Layers
 
在coherence中,Partitioned(distributed) cache服务有三个明显的层:
  • Client View  这个客户端视图表示了一个虚拟的层,提供对底层分布式数据的访问。这一侧可以使用NamedCache接口来访问。在这个层,你能创建合成的数据结构,如NearCahce或者 ContinuousQueryCache。
  • Storage Manager storage manager是服务端的层,用来处理从客户端层发来的和缓存相关的请求。它管理持有真是缓存数据(primary和backup副本)的锁信息、事件监听器、映射触发器等的数据结构。
  • backing map  backing map是服务端数据结构,持有真实数据。
Coherence允许用户配置一些即用的backing mapo实现和自定的实现。基本上,唯一的限制是所有的映射实现必须知道的是理解Storage Manager提供的所有的key和value的内部形式。为了处理内部数据和对象形式的互相转化,Storage Manager能够用BackingMapManagerContext应用支持Backing Map实现。
 
下图示backing map 概念上的展示

Coherence Step by Step 第三篇 缓存(三)实现Storage和Backing Maps(翻译)

 
2.Local Storage
 
Local storage 引用数据结构,实际上是被Coherence管理的存储和缓存的数据。一个对象要提供local storage,它必须提供相同标准的集合接口,java.util.map。当一个local storage的实现被coherence用来存储replicated 或者distributed数据,这成为backing map,因为Coherence实际上通过local storage 实现来备份的。local storage最常用在distributed cache中的前面和distributed cache的后面作为备份。
 
Coherence 支持下面local storage 实现:
  • Safe HashMap: 这个默认的无损的实现。无损的实现是一个类似java的Hashtable类的,没有大小限制和自动过期。换句话说,它不会从自身中剔除任何缓存条目。这个特殊的HashMap的实现对非常高的线程级别的并发是最佳的。对于默认的实现,用com.tangosol.until.SafehaspMap类;当一个实现需要提供缓存事件时,用com.tangosol.util.ObservalbleHashMap。这些实现是线程安全的。
  • Local Cache: 这是默认的size-limiting和atuo-expiring的实现。local cache下面会详细说,但是重点要记住的是他能够限制缓存的大小,它能够实现在一个确定周期后自动过期。对于默认的实现,使用com.tangosol.net.cache.LocalCache;这个实现是线程安全的,支持缓存事件,con.tangosol.net.CacheLoader,CacheStore和可配置的/插入式的逐出规则。
  • 读/写 Backing map: 这是默认的backing map的实现,当一个缓存没有找到,从数据库中加载。他能配置成read-only cache(消费者模型)或者是一个write-through 或者是write-behind cache(消费者/生产者模型).write-through和write-behind模型专为distributed cache服务所设计。如果使用near cache,near cache必须和distributed cache保持同步,可能结合使用支持Seppuku-based near cache的backing map。对于默认的实现,使用com.tangosol.net.cache.ReadWriteBackingMap类。
  • Binary Map(Java NIO):这个backing map的实现,能够在内存中存储它的信息,而不是在java heap之外或甚至在memory-mapped文件,这意味着它不会影响java 堆的大小,和相关jcm垃圾回收的性能,能够对应用的暂停负责。这个实现也对distributed cache 备份有效,对于read-mostly 和read-only的换取特别有用,尤其要求高可用性的备份,因为这意味着backup不影响java堆的大小,二爷在失效备援时候能够立即可用。
  • Serialization Map:这个backing map的实现转换它的数据位一种能够存储在硬盘上的形式,引用一种序列化的形式。这要求一个独立的的com.tangosol.io.BinaryStore对象,以序列化形式的数据存储;通常,这是内建的LH磁盘的存储实现,但是serialization map支持任何自定义的BinaryStore实现。对于默认的serialization map,shiyongcom.tangosol.net.cache.SerializationMap.
  • Serialization Cache: 这个是SerializationMap的扩展,支持LRU啊逐出规则,使用com.tangosol.net.cache.SerializationCache。
  • Overflow Map:overflow map没有正式的提供存储,但是在这里应该提到,因为它能够结合两种local storage 实现,当第一个填满时候,它填充第二个。对于overflowmap的默认实现,使用com.tangosl.net.cache.OverflowMap。

 

3.Operations
有几种操作类型执行Backing Map
  • 自然访问和更新操作由应用的使用所引起。例如,NamedCache.get()的调用自然的导致了Map.get()的调用,以回应backing map;NamedCache.invoke()调用可能引起一系列的Map.put()和Map.get()操作;NamedCache.keySet(filter)调用可能引起Map.entrySet().iterator循环等等。
  • 移除操作由基于时间的过期或者基于大小的逐出所引起。例如,从客户端层调用NamedCache.get()或者NamedCache.size()可能引起Map.remove()调用,缘由于条目的过期时间到;或者NamedCache.put()调用导致一个Map.Remove()调用,缘由于在backing map中总共的数量达到了water-mark的配置值。
  • 插入操作可能导致一个CacheStore.load()操作。(对于配置了read-through或者read-ahead特性的backing map)
  • 人工访问或者更新是由于partition distribution引起的(这反过来可能是cluster节点失效或者回滚造成的)。这个例子中,没有应用层的调用,有些条目可能从backing map中被插入或者删除。

 

4.容量规划
 
根据实际的实现,backing map存储缓存数据用一下几种方式
  • on-heap memory
  • off-heap memory
  • disk(memory-mapped files 或者 in process DB)
  • solid state device(日志文件)
  • 以上任意的结合
自然的在内存中保存数据,极大的减少了访问和更新的演示,这是最常用的。
 
通常,应用程序必须确保所有的数据被放进了date grid,没有超出预定的内存。这个能够通过应用层的逻辑或者自动的使用size-或者expiry-based逐出来直接做到。很自然的,在coherence cache持有的所有数据等于相应的backing maps中的数据量的综合(每个cluster节点运行在启用了storage enabled模式的相应的partitioned cache service)。
 
思考下面的缓存配置节选:

<backing-map-scheme>
  <local-scheme/>
</backing-map-scheme>

上面的backing map是一个com.tangosol.net.cache.LocalCache的实例,没有任何预定的大小限制,且必须显式的控制。如果不这么做,可能导致JVM内存不足。

<backing-map-scheme>
  <local-scheme>
    <eviction-policy>LRU</eviction-policy>
    <high-units>100m</high-units>
    <unit-calculator>BINARY</unit-calculator>
  </local-scheme>
</backing-map-scheme>

 

上面的backing map也是com.tangosol.net.cache.LocalCache,有一个100MB的容量限制。如果backing map所持有的数据超出了这个watermark,一些条目将会从backing map被移除,使得容量降低到低的watermark值(<low-units>配置元素,默认是<high-units>的75%)。移除条目的选择是基于LRU逐出规则。其它的参数有LFU和Hybird。<high-units>限制是2GB。要超过这个限制,使用<unit-factor>元素。例如,用<unit-factor>为1048576和<high-units>值为8192,结果是一个high watermark的值为8GB(8192*1048576)。

<backing-map-scheme>
  <local-scheme>
    <expiry-delay>1h</expiry-delay>
  </local-scheme>
</backing-map-scheme>

上面的bakcing map自动逐出任何一条木,只要它有超过1小时没有更新。注意,这种逐出是一种"lazy"方式,一谈有更新发生,会在任何时间触发。唯一保证Coherence提供了超过1小时的条目不会回调。

 
下面的backing map是一个com.tangosol.net.cache.SerializationCache的实例,在extended(nio) memory存储值,有一个100MB的限制。

<backing-map-scheme>
  <external-scheme>
    <nio-memory-manager>
      <initial-size>1MB</initial-size>
      <maximum-size>100MB</maximum-size>
    </nio-memory-manager>
    <high-units>100</high-units>
    <unit-calculator>BINARY</unit-calculator>
    <unit-factor>1048576</unit-factor>
  </external-scheme>
</backing-map-scheme>

配置这个缓存的backup storage为off-heap(or file-mapped):


<backup-storage>
  <type>off-heap</type>
  <initial-size>1MB</initial-size>
  <maximum-size>100MB</maximum-size>
</backup-storage>

5.使用Partitioned Backing Maps

传统的backing map实现为所有相应节点所拥有的partitions包含了条目。(在partition传输过重中,它也能持有"in flight"条目,从客户端的角度来说是暂时的不属于任何人)。
下图展示了一个传统backing map实现的概念视图。

Coherence Step by Step 第三篇 缓存(三)实现Storage和Backing Maps(翻译)

partitioned的backing map是一个基本的多个真是映射的实现,每个都只包含了属于同一个partition的条目。

下图是partitioned backing map实现的概念视图

Coherence Step by Step 第三篇 缓存(三)实现Storage和Backing Maps(翻译)

配置partitioned backing map,增加一个<partitioned>元素,值为true,例如:

<backing-map-scheme>
  <partitioned>true</partitioned>
  <external-scheme>
    <nio-memory-manager>
      <initial-size>1MB</initial-size>
      <maximum-size>50MB</maximum-size>
    </nio-memory-manager>
    <high-units>8192</high-units>
    <unit-calculator>BINARY</unit-calculator>
    <unit-factor>1048576</unit-factor>
  </external-scheme>
</backing-map-scheme>
backing map是com.tangosol.net.partition.PartitionSplittingBackingMap的实例,随着单独的分区持有的映射被com.tangosol.net.cache.SerializationCache实例化,每个值存储在extended(nio) memory。单独的nio 缓存有个50MB的限制,而backing map有一个蒸发容量为8GB(8192*1048576)的限制。
再一次重复,你必须为这个缓存配置backup storage为off-heap或者file-mapped的
 
6.使用Elastic Data Feature 来存储数据
 
Elastic Date feature用来无缝的在内存和基本磁盘的谁被间存储数据。这个特性是特别值得欣赏的,利用了快速的基于磁盘的设备,如SSD且从SSD读取数据或存储数据使得接近内存速度。Elastic Date feature 使用了成为journaling的技术来优化在内存和磁盘间的存储。
 
Elastic date包含两个不同的组件:RAM journal 用来在in-memory中存储数据,flash journal用来在基于磁盘的设备上存储数据。这些可以用不同的组合方式组合,通常用在backing maps和backup storage,但是也能和composite cache一起使用(例如,near cache)。RAM journal总是用flash journal使得数据无缝的流向磁盘。
 
Cache使用RAM或者是flash journal是作为缓存配置文件中缓存方案定义的一部分作为配置。Journaling behavior被配置,更具需要,通过使用一个operational override file来覆盖即用的配置。
 
6.1 Journaling 概述
Journaling引用了一种技术,记录一个队列的修改的状态变化,称为journal。当变化发生时,journal就会为每个指定的键记录每个值,一个树形结构被存储在内存中,用来跟踪哪个journal条目包含了特定键的当前值。为了找到一个条目的值,查找树中的键,它包含了指向包含最新值的journal条目的指针。
 
如由于为一个键写了新的值使得journal里的变化成为淘汰的,旧的值在journal堆积。每隔一段时间,旧的值会被逐出,让出控件给新的值。
 
Elastic Data feature包含了RAM journal 实现和flash journal 实现,两者无缝的工作。如果,例如RAM journal 用尽内存,flash journal自动接收从ram journal流出的数据,允许缓存扩大,远远超出内存的大小。
 
NOTE:当journaling 是开启的,如果你正在执行data grid operation(如查询和聚合),要求额外的容量规划。
 
resource manager 控制journaling。这resource manager 创建和使用binary store在journal上执行操作。binary store是JournalBinaryStore 类的实现。
 
所有的读和写操作通过binary store由resource manager处理。有一个为RAM journal的resource manager(RamJournalRM)和一个为flash journalFlashJournalRM。最后,journaling使用SimpleSerializationMap类作为backing map的实现。如果有需要可以使用自定义的SimpleSerializationMap的实现。
 
 
6.2 定义Journal方案
<ramjoural-scheme>和<flashjournal-scheme>元素用来配置缓存配置文件中的RAM和FLash journal。
 
6.2.1 配置RAM Jouranl Backing Map
 
配置RAM journal backing map,在缓存定义中的<backing-map-schmem>元素中增加一个<ramjournal-scheme>元素。下面的列子创建了一个distributed cache中使用RAM journal作为backing map。当RAM journal超出了配置的内存大小时,会自动委托给flash journal。
<distributed-scheme>
   <scheme-name>distributed-journal</scheme-name>
   <service-name>DistributedCacheRAMJournal</service-name>
   <backing-map-scheme>
      <ramjournal-scheme/>
   </backing-map-scheme>
   <autostart>true</autostart>
</distributed-scheme>

 

6.2.2 配置Flash Journal Backing Map

配置flash journalbacking map,在缓存定义中的<backing-map-scheme>元素中增加一个<flashjournal-scheme>的元素。下面的例子创建了一个distributed scheme,使用了flash journal 作为bakcing map。
 
6.2.3 引用Journal Scheme
 
RAM和flash journal scheme都支持使用方案的引用来重用方案定义。下面的例子创建了一个distributed cache ,通过引用名为default-ram的RAM scheme定义来配置RAM journal backing map。
<caching-schemes>
   <distributed-scheme>
      <scheme-name>distributed-journal</scheme-name>
         <service-name>DistributedCacheJournal</service-name>
         <backing-map-scheme>
            <ramjournal-scheme>
               <scheme-ref>default-ram</scheme-ref>
            </ramjournal-scheme>
         </backing-map-scheme>
         <autostart>true</autostart>
   </distributed-scheme>

   <ramjournal-scheme>
      <scheme-name>default-ram</scheme-name>
   </ramjournal-scheme>
</caching-schemes>

 

6.2.4 使用Journal Scheme作为Backup Storage

Journal scheme也可以像backing map一样用来作为backup storage。默认的,distributed scheme配置类使用RAM journal作为backing map,也为backup storage使用RAM journal。同样的,使用flash journal作为backing map的distributed scheme也使用flash journal作为backup storage。这个默认的行为能够通过使用<backup-storage>明确指定存储类型来修改。下面的配置使用一个RAM journal 作为backing map和志明配置一个flash journal作为backup storage:

<caching-schemes>
   <distributed-scheme>
      <scheme-name>default-distributed-journal</scheme-name>
         <service-name>DistributedCacheJournal</service-name>
         <backup-storage>
            <type>scheme</type>
            <scheme-name>example-flash</scheme-name>
         </backup-storage>
         <backing-map-scheme>
            <ramjournal-scheme/>
         </backing-map-scheme>
      <autostart>true</autostart>
   </distributed-scheme>

   <flashjournal-scheme>
      <scheme-name>example-flash</scheme-name>
   </flashjournal-scheme>
</caching-schemes>

 

6.2.5 为Journal Scheme启用自定义的映射实现
 
Journal scheme可以根据需求来配置使用自定义的映射。自定义的映射实现必须继承SimpleSerializationMap类,且声明相同集合的公共构造函数。使得能用,自定义的实现,增加一个<calss-scheme>元素,值为完全引用一个自定义类的名字。任何要求的参数都可以使用<init-params>元素来一个一个自定义类。下面的例子使用了一个名为MySimpleSerializationMap的自定义映射的实现。

 

6.3 改变Journaling Behavior
 
resource manager控制journaling behavior。有一个为RAM journals(RamJournalRM)的resource manager和一个味Flash journals(FlashJournalRM)的resource manager。resource manager在tangosol-coherence-override.xml operational override file中对cluster进行配置。resource manager如果没有配置覆盖,那么使用默认的即用设置。
 
 
6.3.1 配置RAM Journal Resource Manager
 
用<ramjournal-manager>元素配置Ram Journal Behavior。下面的列表提供了由resource manager设置的默认值的详细汇总。
 
  • 二进制值默认限制为64KB(最大4MB)
  • 一个单独的缓冲区(一个journal file)限制在2MB(最大2GB)
  • journal 由最多512个文件组成
  • journal总共能用的内存是默认为1GB(最大64GB)
NOTE: 如果设置了二进制值,或者内存设置或者两个都设置了,falsh journal会被自动使用。
 
配置RAM joural resource manager,在<journaling-config>中增加一个<ramjournal-manager>元素并且定义要被覆盖的子元素。下面的例子演示了覆盖了可用的子元素。
<?xml version='1.0'?>

<coherence xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns="http://xmlns.oracle.com/coherence/coherence-operational-config"
   xsi:schemaLocation="http://xmlns.oracle.com/coherence/
   coherence-operational-config coherence-operational-config.xsd">
   <cluster-config>
      <journaling-config>
         <ramjournal-manager>
            <maximum-value-size>64K</maximum-value-size>
            <maximum-size>2G</maximum-size>
         </ramjournal-manager>
      </journaling-config>
   </cluster-config>
</coherence>

 

6.3.2 配置Flash Journal Resource Manager

<flashjournal-manager>元素用来配置flash journal behavior。下面的列表提供了一个由resouce manager设置的默认值的详细汇总。

  • 二进制值默认限制为64MB
  • 一个单独的缓冲区(一个journal file)限制在2GB(最大4GB)
  • journal 由最多512个文件组成
  • journal 默认限制在1TB,理论上是2TB
配置flash journal resouce manager,在<journaling-config>元素中增加<flashjournal-manager>元素,定义用来覆盖的子元素。下面的例子演示了覆盖各个有效的子元素:
<?xml version='1.0'?>

<coherence xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns="http://xmlns.oracle.com/coherence/coherence-operational-config"
   xsi:schemaLocation="http://xmlns.oracle.com/coherence/
   coherence-operational-config coherence-operational-config.xsd">
   <cluster-config>
      <journaling-config>
         <flashjournal-manager>
            <maximum-value-size>64K</maximum-value-size>
            <maximum-file-size>8M</maximum-file-size>
            <block-size>512K</block-size>
            <maximum-pool-size>32M</maximum-pool-size>
            <directory>/coherence_storage</directory>
            <async-limit>32M</async-limit>
         </flashjournal-manager>
      </journaling-config>
   </cluster-config>
</coherence>
NOTE:用来存储journal文件的目录必须存在。如果不存在,会有警告信息,并且使用JVM指定的默认的临时文件目录。

7.使用差异备份

差异备份是一种当主要的entry发生改变时,用来将变化的部分保存进backup binary entry 而不是将整个entry给替换。差异备份对于需要更新的东西非常庞大,但是只有很小的一部分发生变化的场景是非常理想的。在这种情况下,改变的代价只是enrry的一小部分,小于重写整个entry的代价,结果是性能更好。如果改变超过50% ,差异备份通常可以证明几乎没有什么性能上的增加。
差异备份使用了压缩器,对比两个in-memory 缓冲区中包含的旧值和新值,产生了一个结果(称为差异),能够在旧值的基础上创建新值。Coherence 为POF和non-POF格式提供了标准的差异压缩器。也能根据需要来创建自定义的压缩器。
 
7.1 开启差异备份
 
差异备份只对distributed cache有效,默认是关闭的。差异备份能够对单独的每个distributed cache开启,也能对所有的distributed cache服务类型的实例开启。
 
开启distributed cache的差异备份,在<distributed-scheme>元素中增加一个<compressor>元素,设置为standard。例如:
<distributed-scheme>
   ...        
   <compressor>standard</compressor>
   ...
</distributed-scheme>
为所有的distributed cache 服务类型的实例开启差异备份。在operational override file中覆盖部分缓存服务的compressor 初始参数。例如:
<?xml version='1.0'?>

<coherence xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns="http://xmlns.oracle.com/coherence/coherence-operational-config"
   xsi:schemaLocation="http://xmlns.oracle.com/coherence/
   coherence-operational-config coherence-operational-config.xsd">
   <cluster-config>
      <services>
         <service id="3">
            <init-params>
               <init-param id="22">
                  <param-name>compressor</param-name>
                  <param-value
                     system-property="tangosol.coherence.distributed.compressor">
                     standard</param-value>
               </init-param>
            </init-params>
         </service>
      </services>
   </cluster-config>
</coherence>

 

tangosol.coherence.distributed.compressor 系统属性也被用来为所有的distributed cache 服务类型开启差异备份而不用operational override file。例如:
 
-Dtangosol.coherence.distributed.compressor=standard
 
7.2 使用自定义的差异备份Compressor
 
为执行差异备份使用自定义的compressor,抱在在<instance>元素内,提供一个完整的实现DeltaCompressor接口的的引用类名。下面的例子使用了在MyDeltaCompressor类中实现的自定义compressor。
<distributed-scheme>
   ...        
   <compressor>
      <instance>
         <class-name>package.MyDeltaCompressor</class-name>
      </instance>
   </compressor>
   ...
</distributed-scheme>

作为可选的方案,<instance>元素支持使用<class-factory-name>元素来使用工厂类来负责创建DeltaCompressor实例,<method-name>元素在工厂类上指定了静态工厂方法来执行对象实例化。下面的例子通过使用MyCompressorFactory类中的getCompressor方法来获取一个自定义的compressor实例。

<distributed-scheme>
   ...        
   <compressor>
      <instance>
         <class-factory-name>package.MyCompressorFactory</class-factory-name>
         <method-name>getCompressor</method-name>
      </instance>
   </compressor>
   ...
</distributed-scheme>

需要任何的初始参数可以通过<init-params>元素类指定。下面的例子设置iMaxTime参数为2000。

<distributed-scheme>
   ...        
   <compressor>
      <instance>
         <class-name>package.MyDeltaCompressor</class-name>
         <init-params>
            <init-param>
               <param-name>iMaxTime</param-name>
               <param-value>2000</param-value>
            </init-param>
         </init-params>
      </instance>
   </compressor>
   ...
</distributed-scheme>

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

相关文章:

  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2021-11-27
  • 2021-10-14
  • 2021-06-22
  • 2021-05-06
猜你喜欢
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-01-22
相关资源
相似解决方案