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

本章使用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 概念上的展示

 
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实现的概念视图。

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

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

配置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>

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

posted on 2012-07-27 13:06  萌二&威比  阅读(2012)  评论(0编辑  收藏  举报

导航