@liyuj
2017-09-25T22:36:07.000000Z
字数 21707
阅读 7337
Apache-Ignite-2.2.0-中文开发手册
Ignite平台是基于固化内存架构的,当开启Ignite原生持久化功能时,它可以存储和处理存储在内存和磁盘上的数据和索引,固化内存架构有助于通过利用集群的所有可用资源,使数据固化到磁盘的同时,获得内存级的性能。
Ignite*固化内存的操作方式类似于操作系统的虚拟内存*,比如Linux,但是这两种架构的显著不同在于,当开启固化内存功能时,它会将磁盘视为数据的超集,即使重启或者故障,数据仍然会保留,而传统的虚拟内存只是将磁盘作为一个交换空间,如果进程终止数据就会丢失。
因为这种架构是以内存为中心的,所以RAM会被视为首选的存储层,所有的处理都是在内存中进行的。下面会列出这种内存架构的特性和优势:
Ignite的原生持久化具有如下优势:
Ignite固化内存是一个机遇也面对内存架构,它会将内存拆分成固定大小的页面。这些页面会被存储于内存的堆外受管内存区(Java堆外)中,然后在磁盘上以特定的层次结构进行组织。
数据格式
Ignite在内存和磁盘上维护了同样的二进制格式,这样就不需要花费在内存和磁盘之间移动数据时进行序列化的开销。
下面描述的是Ignite固化内存架构的结构图:
固化内存由一个或者多个堆外内存区组成,一个内存区是通过内存策略配置的逻辑可扩展区域,这个区域大小可变,退出策略以及其他的参数在下面的内存策略中会详述。
固化内存默认只会分配一个内存区,它会占用本地集群节点可用内存的20%。
基于性能的考虑,需要尽可能地将操作型数据保持在内存中,这时需要配置多个内存区。
比如,假设有Person、Purchases和Records实体,它们分别存储于PersonsCache、PurchasesCache和RecordsCache缓存中。Person和Purchases的数据是操作型的,即这些数据会被频繁访问,而Records是访问量较少的历史数据。
假定我们只有200GB的可用内存空间,那么在这个场景中,会按照如下方式分配物理内存:
每个内存区都开始于初始值,然后有一个可增长的最大值。这个区域扩展至其最大值的过程中,都会被分配连续的内存段。内存区的最大值默认为系统可用物理内存的20%。
默认最大值
如果内存区的最大值没有显式地配置(通过org.apache.ignite.configuration.MemoryPolicyConfiguration.setMaxSize()
),那么它会使用机器可用RAM的20%。
一个内存块是从操作系统获得的连续字节数组或者物理内存,这个块会被分为固定大小的页面,该块中可以驻留若干种不同类型的页面,如下图所示:
数据页面存储的是从应用端插入Ignite缓存中的缓存条目(数据页面在上图中标注为绿色)。
通常,一个数据页面持有多个键-值条目,以更高效地利用内存避免内存碎片化。当新的键-值条目加入缓存时,页面内存机制会查找适合该条目的页面然后加入里面。但是,当条目的总大小达到通过MemoryConfiguration.setPageSize(..)
参数配置的页面大小时,该条目会占据多于一个数据页面。
如果有很多的缓存条目都不适合单个页面,那么就需要增加配置参数中的页面大小。
如果在更新期间条目的大小超过了它所属的数据页面的可用空间,那么Ignite会搜索一个有足够空间容纳更新后的条目的新数据页面,然后将数据移动到那里。
应用定义和使用的SQL索引是以B+树数据结构的形式进行维护的。对于一个SQL模式中声明的每个唯一索引,Ignite会实例化并且管理一个专用的B+树实例。
哈希索引
缓存的键也会存储于B+树,它们通过哈希值进行排序。
如上图所示,整个B+树的目的就是链接和排序在固化内存中分配和存储的索引页面。从内部来说,索引页面包括了定位索引值、索引指向的缓存条目在数据页面中的偏移量、还有到其他索引页面的引用(用来遍历树)等所有必要的信息,索引页面在上图中标注为紫色。
B+树的元页面需要获得特定B+树的根和它的层次,以高效地执行范围查询。比如,当执行myCache.get(keyA)
操作时,在一个节点上它会触发下面的操作流程:
myCache
属于那个内存区;myCache
的键的B+树的元页面;keyA
的哈希值,然后在B+树中检索该键所属的索引页面;myCache
中不存在,然后Ignite会返回null
作为myCache.get(keyA)
操作的返回值;keyA
所在的数据页面的所有必要信息;前述章节的执行流程描述的是当应用希望获取缓存时在页面内存中如何检索缓存的条目。下面的内容是当调用像myCache.put(keyA,valueA)
这样的操作时,Ignite如何存储一个新的条目。
在这个场景中,固化内存依赖的是空闲列表数据结构。空闲列表是一个双向链表,它存储了到大致相当于空闲空间的内存页面的引用。比如,有一个空闲列表,它存储了所有的数据页面,它占用了最多75%的空闲空间,还有一个列表来跟踪索引页面,它占用了剩余的25%的容量,数据和索引页面是由独立的空闲列表来跟踪的。
下面是myCache.put(keyA,valueA)
操作的执行流程:
myCache
所属的内存区;myCache
的键的B+树的元页面;keyA
的哈希值,然后在B+树中检索该键所属的索引页面;Ignite节点默认会至多消费本地可用内存的20%,大多数情况下这也是唯一需要调整的参数,要修改默认内存区大小,代码如下所示:
XML:
<bean class="org.apache.ignite.configuration.IgniteConfiguration">
<property name="memoryConfiguration">
<bean class="org.apache.ignite.configuration.MemoryConfiguration">
<!-- Set the size of default memory region to 4GB. -->
<property name="defaultMemoryPolicySize" value="#{4L * 1024 * 1024 * 1024}"/>
</bean>
</property>
<!-- The rest of the parameters -->
</bean>
Java:
IgniteConfiguration cfg = new IgniteConfiguration();
// Changing total RAM size to be used by Ignite Node.
MemoryConfiguration memCfg = new MemoryConfiguration();
// Setting the size of the default memory region to 4GB to achieve this.
memCfg.setDefaultMemoryPolicySize(4L * 1024 * 1024 * 1024);
cfg.setMemoryConfiguration(memCfg);
// Starting the node.
Ignition.start(cfg);
要修改固化内存的主要配置参数,比如页面大小,通过IgniteConfiguration.setMemoryConfiguration(...)
方法传递一个org.apache.ignite.configuration.MemoryConfiguration
即可,下面是可用的参数:
参数 | 描述 | 默认值 |
---|---|---|
setPageSize(...) |
设置默认页面大小 | 2 KB |
setDefaultMemoryPolicySize(...) |
设置自动创建的默认内存区的大小,如果该属性未设置,那么默认的区域会消耗本地主机可用内存的20%。 | 内存的20% |
setDefaultMemoryPolicyName(...) |
设置默认内存策略的名字,每个缓存都会绑定到一个通过本策略实例化的内存区域。 | default |
setMemoryPolicies(...) |
设置集群中可用的所有内存策略的列表。 | 一个空数据,这里不包括创建默认内存区域的配置。 |
setSystemCacheInitialSize(...) |
设置为系统缓存预留的内存区域的初始大小。 | 40 MB |
setSystemCacheMaxSize(...) |
设置为系统缓存预留的内存区域的最大值。因为内部数据结构的限制,总大小不应小于10MB。 | 100 MB |
setConcurrencyLevel(...) |
设置在Ignite的内部页面映射表中并行段的数量。 | 可用CPU总数的4倍。 |
在Ignite的javadoc中可以看到MemoryConfiguration
的完整参数列表。
下面是使用MemoryConfiguration
如何修改页面大小和并发级别的示例代码:
XML:
<bean class="org.apache.ignite.configuration.IgniteConfiguration">
<property name="memoryConfiguration">
<bean class="org.apache.ignite.configuration.MemoryConfiguration">
<!-- Set concurrency level -->
<property name="concurrencyLevel" value="4"/>
<!-- Set the page size to 4 KB -->
<property name="pageSize" value="4096"/>
</bean>
</property>
<!--- Additional settings ---->
</bean>
Java:
// Ignite configuration.
IgniteConfiguration cfg = new IgniteConfiguration();
// Page memory configuration.
MemoryConfiguration memCfg = new MemoryConfiguration();
// Altering the concurrency level.
memCfg.setConcurrencyLevel(4);
// Changing the page size to 4 KB.
memCfg.setPageSize(4096);
// Applying the new page memory configuration.
cfg.setMemoryConfiguration(memCfg);
固化内存默认会初始化一个单一的可扩展内存区,它会占用本地主机的20%可用内存。也可以根据内存策略API的各种参数以及自定义行为来定义多个内存区。
一个内存策略是一套配置参数,都是通过org.apache.ignite.configuration.MemoryPolicyConfiguration
暴露的,比如初始和最大内存区大小,退出策略等等。
比如,要配置一个500MB的内存区并且开启数据页面退出,那么就需要定义一个如下所示的内存策略:
XML:
<bean class="org.apache.ignite.configuration.IgniteConfiguration">
<!-- Durable Memory configuration -->
<property name="memoryConfiguration">
<bean class="org.apache.ignite.configuration.MemoryConfiguration">
<!-- Defining a custom memory policy. -->
<property name="memoryPolicies">
<list>
<!-- 500 MB total size and RANDOM_2_LRU eviction algorithm. -->
<bean class="org.apache.ignite.configuration.MemoryPolicyConfiguration">
<property name="name" value="500MB_Region"/>
<!-- 100 MB initial size. -->
<property name="initialSize" value="#{100 * 1024 * 1024}"/>
<!-- 500 MB maximum size. -->
<property name="maxSize" value="#{500 * 1024 * 1024}"/>
<!-- Enabling data pages eviction. -->
<property name="pageEvictionMode" value="RANDOM_2_LRU"/>
</bean>
</list>
</property>
</bean>
</property>
<!-- The rest of the configuration. -->
<!-- ....... -->
</bean>
Java:
// Ignite configuration.
IgniteConfiguration cfg = new IgniteConfiguration();
// Durable Memory configuration.
MemoryConfiguration memCfg = new MemoryConfiguration();
// Creating a custom memory policy for a new memory region.
MemoryPolicyConfiguration plCfg = new MemoryPolicyConfiguration();
// Policy/region name.
plCfg.setName("500MB_Region_Eviction");
// Setting initial size.
plCfg.setInitialSize(100L * 1024 * 1024);
// Setting maximum size.
plCfg.setMaxSize(500L * 1024 * 1024);
// Setting data pages eviction algorithm.
plCfg.setPageEvictionMode(DataPageEvictionMode.RANDOM_2_LRU);
// Applying the memory policy.
memCfg.setMemoryPolicies(plCfg);
// Applying the new page memory configuration.
cfg.setMemoryConfiguration(memCfg);
Ignite缓存可以被映射到这个区域(参照下面的配置示例),需要做的就是将这个策略的名字作为参数传递给org.apache.ignite.configuration.CacheConfiguration.setMemoryPolicyName(...)
方法:
XML:
<bean class="org.apache.ignite.configuration.IgniteConfiguration">
<!-- Durable Memory and other configuration parameters. -->
<!-- ....... -->
<property name="cacheConfiguration">
<list>
<!-- Cache that is mapped to non-default memory region. -->
<bean class="org.apache.ignite.configuration.CacheConfiguration">
<!--
Setting a memory policy name to bind to a specific region.
-->
<property name="memoryPolicyName" value="500MB_Region"/>
<!-- Cache unique name. -->
<property name="name" value="SampleCache"/>
<!-- Additional cache configuration parameters -->
</bean>
</list>
</property>
<!-- The rest of the configuration. -->
<!-- ....... -->
</bean>
Java:
// Ignite configuration.
IgniteConfiguration cfg = new IgniteConfiguration();
// Durable Memory configuration and the rest of the configuration.
// ....
// Creating a cache configuration.
CacheConfiguration cacheCfg = new CacheConfiguration();
// Setting a memory policy name to bind to a specific memory region.
cacheCfg.setMemoryPolicyName("500MB_Region_Eviction");
// Setting the cache name.
cacheCfg.setName("SampleCache");
// Applying the cache configuration.
cfg.setCacheConfiguration(cacheCfg);
如果用这个配置启动Ignite集群,固化内存会分配一个初始大小为256MB的内存区,然后它可以增长到500MB。这个新的内存区会与默认的内存区共存,然后SampleCache
的所有数据和索引都会驻留在该区域,除非通过前述的方式显式地指定其它的内存区,其他的缓存都会绑定到默认的内存区。
如果所有的内存使用量超过了最大值,那么会抛出内存溢出异常,要避免这个问题,可以采用下面的一个或者多个组合来解决:
修改默认内存策略
默认的内存区是由org.apache.ignite.configuration.MemoryConfiguration.createDefaultPolicyConfig()
方法准备的默认内存策略参数实例化的,如果希望改变部分参数,步骤如下:
1.通过自定义名字和参数创建一个新的内存策略;
2.将策略的名字传递给org.apache.ignite.configuration.MemoryConfiguration. setDefaultMemoryPolicyName(...)
方法。
可以参照示例代码中的内存策略示例和配置文件,这里会详述如何配置和使用多个内存区。
配置参数
org.apache.ignite.configuration.MemoryPolicyConfiguration
支持的配置参数如下:
参数名 | 描述 | 默认值 |
---|---|---|
setName(...) |
内存策略的名字 | 必须参数,无默认值 |
setInitialSize(...) |
设置该内存策略定义的内存区的初始大小,当内存使用量达到该值时,会分配一个新的内存块,直到达到最大值。 | 256 MB |
setMaxSize(...) |
设置该内存策略定义的内存区的最大值,由于内部数据结构的限制,总大小不能小于10MB。如果内存使用量超过该值,会抛出内存溢出异常,要解决这个问题,可以配置退出算法,或者将该值调大。 | 内存的20% |
setSwapFilePath(...) |
设置该内存策略定义的内存区的内存映射文件路径,配置该参数后,可以为该区域提供基于底层文件系统的交换能力。 | 默认禁用 |
setPageEvictionMode(...) |
设置数据页面使用的退出算法。 | 默认禁用 |
setEvictionThreshold(...) |
内存页面退出的初始阈值,比如,如果阈值配置为0.9,这意味着当页面内存占用了90%的内存区之后,退出就会生效。 | 0.9 |
setEmptyPagesPoolSize(...) |
设置该内存策略的重用列表中的空白页面的最小数量。当键值对的大小超过页面大小的一半时,这个参数会确保Ignite能成功地退出旧的条目。如果缓存中包含很大的条目时,可以调大该参数(池中页面的总大小足够容纳最大的条目)。 | 100 |
setMetricsEnabled(...) |
为该内存区开启内存指标收集。 | false |
固化内存是堆外的内存,它是在Java堆之外分配的内存区,然后将数据条目存储在其中。但是,通过将org.apache.ignite.configuration.CacheConfiguration.setOnheapCacheEnabled(...)
配置为true
为缓存条目开启堆内缓存。
当以二进制形式处理缓存条目或者调用缓存的反序列化时在服务端节点有大量的读操作,堆内缓存对这样的场景非常有用。比如,当一个分布式计算或者部署的服务为下一步处理从缓存中获取一些数据时,就会发生这样的情况。
堆内缓存大小
要管理堆内缓存的大小,避免其不断增长,一定要配置一个可用的基于缓存条目的退出策略
。
Ignite支持两种数据退出策略:
如果开启了Ignite持久化本策略不生效
注意如果开启了Ignite持久化,那么基于页面的退出策略是无效的,因为最旧的页面会自动地从内存中清除。
基于页面的退出是通过页面缓存策略进行配置的,页面内存由一个或者多个通过MemoryPolicyConfigurations
配置的内存区组成。一个内存区的大小默认会一直增长直到最大值,为避免可能的内存区溢出,需要设置一个数据页面的退出模式:Random-LRU
或者Random-2-LRU
,通过MemoryPolicyConfiguration.setPageEvictionMode(...)
配置参数进行设定,退出模式会跟踪数据页面的使用然后根据模式的实现退出部分数据。
Random-LRU
要启用Random-LRU退出算法,可以将DataPageEvictionMode.RANDOM_LRU
传递给相应的MemoryPolicyConfiguration
,如下所示:
XML:
<bean class="org.apache.ignite.configuration.MemoryConfiguration">
<!-- Defining additional memory poolicies. -->
<property name="memoryPolicies">
<list>
<!--
Defining a policy for 20 GB memory region with RANDOM_LRU eviction.
-->
<bean class="org.apache.ignite.configuration.MemoryPolicyConfiguration">
<property name="name" value="20GB_Region_Eviction"/>
<!-- Initial size is 5 GB. -->
<property name="initialSize" value="#{5 * 1024 * 1024 * 1024}"/>
<!-- Maximum size is 20 GB. -->
<property name="maxSize" value="#{20 * 1024 * 1024 * 1024}"/>
<!-- Enabling RANDOM_LRU eviction. -->
<property name="pageEvictionMode" value="RANDOM_LRU"/>
</bean>
</list>
...
</property>
...
</bean>
Java:
// Defining additional memory poolicies.
MemoryConfiguration memCfg = new MemoryConfiguration();
// Defining a policy for 20 GB memory region with RANDOM_LRU eviction.
MemoryPolicyConfiguration memPlc = new MemoryPolicyConfiguration();
memPlc.setName("20GB_Region_Eviction");
// Initial size is 5 GB.
memPlc.setInitialSize(5L * 1024 * 1024 * 1024);
// Maximum size is 5 GB.
memPlc.setMaxSize(20L * 1024 * 1024 * 1024);
// Enabling RANDOM_LRU eviction.
memPlc.setPageEvictionMode(DataPageEvictionMode.RANDOM_LRU);
// Setting the new memory policy.
memCfg.setMemoryPolicies(memPlc);
Random-LRU算法工作方式如下:
最后使用
时间戳;Random-2-LRU
Random-2-LRU退出算法是Random-LRU算法的抗扫描版,要启用这个算法,将DataPageEvictionMode.RANDOM_2_LRU
传递给相应的MemoryPolicyConfiguration
即可,如下所示:
XML:
<bean class="org.apache.ignite.configuration.MemoryConfiguration">
<!-- Defining additional memory poolicies. -->
<property name="memoryPolicies">
<list>
<!--
Defining a policy for 20 GB memory region with RANDOM_2_LRU eviction.
-->
<bean class="org.apache.ignite.configuration.MemoryPolicyConfiguration">
<property name="name" value="20GB_Region_Eviction"/>
<!-- Initial size is 5 GB. -->
<property name="initialSize" value="#{5 * 1024 * 1024 * 1024}"/>
<!-- Maximum size is 20 GB. -->
<property name="maxSize" value="#{20 * 1024 * 1024 * 1024}"/>
<!-- Enabling RANDOM_2_LRU eviction. -->
<property name="pageEvictionMode" value="RANDOM_2_LRU"/>
</bean>
</list>
...
</property>
...
</bean>
Java:
// Defining additional memory poolicies.
MemoryConfiguration memCfg = new MemoryConfiguration();
// Defining a policy for 20 GB memory region with RANDOM_LRU eviction.
MemoryPolicyConfiguration memPlc = new MemoryPolicyConfiguration();
memPlc.setName("20GB_Region_Eviction");
// Initial size is 5 GB.
memPlc.setInitialSize(5L * 1024 * 1024 * 1024);
// Maximum size is 5 GB.
memPlc.setMaxSize(20L * 1024 * 1024 * 1024);
// Enabling RANDOM_2_LRU eviction.
memPlc.setPageEvictionMode(DataPageEvictionMode.RANDOM_2_LRU);
// Setting the new memory policy.
memCfg.setMemoryPolicies(memPlc);
在Random-2-LRU算法中,每个数据页面会存储两个最近访问时间戳,退出时,算法会随机地从跟踪数组中选择5个索引值,然后两个最近时间戳中的最小值会被用来和另外四个候选页面中的最小值进行比较。
Random-2-LRU比Random-LRU要好,因为它解决了昙花一现
的问题,即一个页面很少被访问,但是偶然地被访问了一次,然后就会被退出策略保护很长时间。
Random-LRU与Random-2-LRU的对比
Random-LRU退出模式中,一个数据页面只会保存一份最近访问时间戳,而Random-2-LRU模式会为每个数据页面保存两份最近访问时间戳。
退出的触发
一个数据页面退出算法的触发默认是当内存区的总消耗量达到了90%,如果要调整的话,可以使用MemoryPolicyConfiguration.setEvictionThreshold(...)
参数。
如果通过CacheConfiguration.setOnheapCacheEnabled(...)
开启了堆内缓存,那么固化内存是可以将热数据存储于Java堆中的。开启了堆内缓存之后,就可以使用一个缓存条目退出策略来管理不断增长的堆内缓存了。
退出策略控制着一个缓存对应的堆内内存可以存储的条目的最大数量,当达到堆内缓存数量的最大值之后,条目就会从Java堆中退出。
堆内退出策略只是将缓存条目从Java堆中删除,存储在堆外内存区中的条目不受影响。
部分退出策略支持批量退出。如果是受到缓存数量限制的退出,开启了批量退出之后,那么当缓存的数量比缓存最大值多出batchSize
个条目时,退出就开始了,这时batchSize
个条目就会被退出。如果开启了缓存大小限制的退出,那么当缓存条目的大小(字节数)大于最大值时,退出就会被触发。
只有未配置最大内存限制时,才会支持批量退出。
Ignite中退出策略是可插拔的,可以通过EvictionPolicy
接口进行控制,退出策略的实现定义了从堆内缓存选择待退出条目的算法,然后当缓存发生改变时就会收到通知。
最近最少使用(LRU)
LRU退出策略基于最近最少使用算法,他会确保最近最少使用的数据(即最久没有被访问的数据)会被首先退出。
LRU退出策略适用于堆内缓存的大多数使用场景,不确定时可以优先使用。
这个策略通过LruEvictionPolicy
实现,通过CacheConfiguration
进行配置,支持批量退出以及受到内存大小限制的退出。
XML:
<bean class="org.apache.ignite.cache.CacheConfiguration">
<property name="name" value="myCache"/>
<!-- Enabling on-heap caching for this distributed cache. -->
<property name="onheapCacheEnabled" value="true"/>
<property name="evictionPolicy">
<!-- LRU eviction policy. -->
<bean class="org.apache.ignite.cache.eviction.lru.LruEvictionPolicy">
<!-- Set the maximum cache size to 1 million (default is 100,000). -->
<property name="maxSize" value="1000000"/>
</bean>
</property>
...
</bean>
Java:
CacheConfiguration cacheCfg = new CacheConfiguration();
cacheCfg.setName("cacheName");
// Enabling on-heap caching for this distributed cache.
cacheCfg.setOnheapCacheEnabled(true);
// Set the maximum cache size to 1 million (default is 100,000).
cacheCfg.setEvictionPolicy(new LruEvictionPolicy(1000000));
IgniteConfiguration cfg = new IgniteConfiguration();
cfg.setCacheConfiguration(cacheCfg);
// Start Ignite node.
Ignition.start(cfg);
先进先出(FIFO)
FIFO退出策略基于先进先出算法,他确保缓存中保存时间最久的数据会被首先退出,它与LruEvictionPolicy
不同,因为它忽略了数据的访问顺序。
这个策略通过FifoEvictionPolicy
实现,通过CacheConfiguration
进行配置,支持批量退出以及受到内存大小限制的退出。
XML:
<bean class="org.apache.ignite.cache.CacheConfiguration">
<property name="name" value="myCache"/>
<!-- Enabling on-heap caching for this distributed cache. -->
<property name="onheapCacheEnabled" value="true"/>
<property name="evictionPolicy">
<!-- FIFO eviction policy. -->
<bean class="org.apache.ignite.cache.eviction.fifo.FifoEvictionPolicy">
<!-- Set the maximum cache size to 1 million (default is 100,000). -->
<property name="maxSize" value="1000000"/>
</bean>
</property>
...
</bean>
Java:
CacheConfiguration cacheCfg = new CacheConfiguration();
cacheCfg.setName("cacheName");
// Enabling on-heap caching for this distributed cache.
cacheCfg.setOnheapCacheEnabled(true);
// Set the maximum cache size to 1 million (default is 100,000).
cacheCfg.setEvictionPolicy(new FifoEvictionPolicy(1000000));
IgniteConfiguration cfg = new IgniteConfiguration();
cfg.setCacheConfiguration(cacheCfg);
// Start Ignite node.
Ignition.start(cfg);
有序
有序退出策略和FIFO退出策略很像,不同点在于通过默认或者用户定义的比较器定义了数据的顺序,然后确保最小的数据(即排序数值最小的数据)会被退出。
默认的比较器用缓存条目的键作为比较器,它要求键必须实现Comparable
接口。也可以提供自定义的比较器实现,可以通过键,值或者两者都用来进行条目的比较。
这个策略通过SortedEvictionPolicy
实现,通过CacheConfiguration
进行配置,支持批量退出以及受到内存大小限制的退出。
XML:
<bean class="org.apache.ignite.cache.CacheConfiguration">
<property name="name" value="myCache"/>
<!-- Enabling on-heap caching for this distributed cache. -->
<property name="onheapCacheEnabled" value="true"/>
<property name="evictionPolicy">
<!-- Sorted eviction policy. -->
<bean class="org.apache.ignite.cache.eviction.sorted.SortedEvictionPolicy">
<!--
Set the maximum cache size to 1 million (default is 100,000)
and use default comparator.
-->
<property name="maxSize" value="1000000"/>
</bean>
</property>
...
</bean>
Java:
CacheConfiguration cacheCfg = new CacheConfiguration();
cacheCfg.setName("cacheName");
// Enabling on-heap caching for this distributed cache.
cacheCfg.setOnheapCacheEnabled(true);
// Set the maximum cache size to 1 million (default is 100,000).
cacheCfg.setEvictionPolicy(new SortedEvictionPolicy(1000000));
IgniteConfiguration cfg = new IgniteConfiguration();
cfg.setCacheConfiguration(cacheCfg);
// Start Ignite node.
Ignition.start(cfg);
随机
随机退出策略会随机地选择条目退出,这个退出策略主要用于调试或者基准测试的目的。
这个策略通过RandomEvictionPolicy
实现,通过CacheConfiguration
进行配置。
XML:
<bean class="org.apache.ignite.cache.CacheConfiguration">
<property name="name" value="myCache"/>
<!-- Enabling on-heap caching for this distributed cache. -->
<property name="onheapCacheEnabled" value="true"/>
<property name="evictionPolicy">
<!-- Random eviction policy. -->
<bean class="org.apache.ignite.cache.eviction.random.RandomEvictionPolicy"> <!-- Set the maximum cache size to 1 million (default is 100,000). -->
<property name="maxSize" value="1000000"/>
</bean>
</property>
...
</bean>
Java:
CacheConfiguration cacheCfg = new CacheConfiguration();
cacheCfg.setName("cacheName");
// Enabling on-heap caching for this distributed cache.
cacheCfg.setOnheapCacheEnabled(true);
// Set the maximum cache size to 1 million (default is 100,000).
cacheCfg.setEvictionPolicy(new RandomEvictionPolicy(1000000));
IgniteConfiguration cfg = new IgniteConfiguration();
cfg.setCacheConfiguration(cacheCfg);
// Start Ignite node.
Ignition.start(cfg);
过期策略指定了在缓存条目过期之前必须经过的时间量,时间可以从创建,最后访问或者修改时间开始计算。
过期策略可以通过任何预定义的ExpiryPolicy
实现进行设置。
类名 | 创建时间 | 最后访问时间 | 最后更新时间 |
---|---|---|---|
CreatedExpiryPolicy |
可用 | ||
AccessedExpiryPolicy |
可用 | 可用 | |
ModifiedExpiryPolicy |
可用 | 可用 | |
TouchedExpiryPolicy |
可用 | 可用 | 可用 |
EternalExpiryPolicy |
也可以自定义ExpiryPolicy
实现。
过期策略可以在CacheConfiguration
中进行设置,这个策略可以用于缓存内的所有条目。
cfg.setExpiryPolicyFactory(CreatedExpiryPolicy.factoryOf(Duration.ZERO));
也可以在对缓存进行单独操作时对过期策略进行设置或者修改。
IgniteCache<Object, Object> cache = cache.withExpiryPolicy(
new CreatedExpiryPolicy(new Duration(TimeUnit.SECONDS, 5)));
此策略将用于在返回的缓存实例上调用的每个操作。
过期的条目从缓存中删除,既可以马上删除,也可以通过不同的缓存操作涉及它们再删除。只要有一个缓存配置启用了Eager TTL,Ignite就会创建一个线程在后台清理过期的数据。
Eager TTL可以通过CacheConfiguration.eagerTtl
属性启用或者禁用(默认值是true
)。
XML:
<bean class="org.apache.ignite.configuration.CacheConfiguration">
<property name="eagerTtl" value="true"/>
</bean>
自动碎片整理
在Ignite中内存碎片整理是自动进行的,不需要人工干预。
固化内存会将数据全部保存在叫做数据页面的特定页面类型中,这样随着时间的推移,每个独立的页面都可能由于键-值条目的插入、更新和删除而更新多次,这就会导致整个内存的碎片化。
为了最小化内存碎片,当页面发生严重碎片化时,Ignite会进行页面的压缩。
压缩后的数据页面大体如下所示:
页面有一个头部,保存了所有的必要信息,所有的键-值条目都是从右往左添加的,在上图的页面中有三个条目(分别为1,2,3),这些条目大小可能不同。
保存页面中键-值条目位置的偏移量(或者引用)是从左往右保存的,并且大小是固定的,偏移量作为指针用于定位页面中的键-值条目。
中间的区域都是空闲空间,当新的数据进入集群时就会被填充进去。
下一步,假设随着时间推移条目2被删除,这就导致了页面中空闲空间的不连续。
碎片化的页面大概就是这样的。
但是,当空闲空间需要或者碎片化达到了一个阈值,压缩进程就会进行碎片整理,然后使其达到上面第一张图片的状态-即空闲空间连续。这个进程是自动的,不需要人工干预。
Ignite的固化内存可以通过MemoryMetrics
接口和JMX bean暴露的若干接口进行监控,这有助于跟踪所有的内存使用,度量性能,以及在出现性能瓶颈时进行优化。
对于一个节点来说,要获取和固化内存有关的指标,MemoryMetrics
是主要的入口点,因为一个节点可配置多个内存区,因此通过API调用可以为每个内存区单独收集和获取指标。
当前MemoryMetrics
提供了如下的方法:
方法名 |
描述 |
---|---|
getName() |
返回指标所属内存区的名字。 |
getTotalAllocatedPages() |
获取该内存区已分配页面的总数量。 |
getAllocationRate() |
获取该内存区的页面分配比率。 |
getEvictionRate() |
获取该内存区的页面退出比率。 |
getLargeEntriesPagesPercentage() |
获取被超过页面大小的大条目完全占用的页面的百分比,大条目也可以拆分为多个片段,每个片段适配一个单个页面。 |
getPagesFillFactor() |
获取仍然空闲可用的空间的百分比。 |
getDirtyPages() |
获取脏页面的数量(页面的内容与磁盘上同一页的内容不同),这个指标只有当持久化存储启用的时候才可用。 |
getPagesReplaceRate() |
获取内存中的页面被磁盘上的其他页面替换的速率(页/秒)。这个指标有效地表示了内存中页面退出并且被磁盘上的页面替换的速率,这个指标只有当持久化存储启用的时候才可用。 |
getPhysicalMemoryPages() |
获取当前加载进内存的页面数量,如果持久化存储未启用,这个指标会等同于getTotalAllocatedPages() 。 |
调用Ignite.memoryMetrics()
方法可以获得最新的指标快照然后进行迭代,如下所示:
// Get the metrics of all the memory regions defined on the node.
Collection<MemoryMetrics> regionsMetrics = ignite.memoryMetrics();
// Print some of the metrics' probes for all the regions.
for (MemoryMetrics metrics : regionsMetrics) {
System.out.println(">>> Memory Region Name: " + metrics.getName());
System.out.println(">>> Allocation Rate: " + metrics.getAllocationRate());
System.out.println(">>> Fill Factor: " + metrics.getPagesFillFactor());
}
另外,还有一些指标是只和持久化存储有关的,这些都是通过PersistenceMetrics
接口提供的,部分如下所示:
getWalWritingRate() |
getWalArchiveSegments() |
getWalFsyncTimeAverage() |
getLastCheckpointingDuration() |
getLastCheckpointTotalPagesNumber() |
调用Ignite.persistentStoreMetrics()
方法可以获得和使用最新的持久化指标快照,如下例所示:
// Getting metrics.
PersistenceMetrics pm = ignite.persistentStoreMetrics();
System.out.println("Fsync duration: " + pm.getLastCheckpointFsyncDuration());
System.out.println("Data pages: " + pm.getLastCheckpointDataPagesNumber());
System.out.println("Checkpoint duration:" + pm.getLastCheckpointingDuration());
启用指标收集
内存指标收集不是没有代价的操作,可能会影响应用的性能,因此,内存指标收集默认是关闭的。
要打开它,可以使用如下的两个方式:
1.对于每个希望收集内存指标的内存区,设置MemoryPolicyConfiguration.setMetricsEnabled(boolean)
为true
;
2.对于希望获得和持久化有关的指标,设置PersistentStoreConfiguration.setMetricsEnabled(boolean)
为true
;
3.通过下面描述的特定JMX bean暴露的MemoryMetricsMXBe
PersistenceMetricsMXBeanan.enableMetrics()
方法启用;
4.通过下面描述的特定JMX bean暴露的PersistenceMetricsMXBean.enableMetrics()
方法来激活和持久化有关的指标的收集。
另外,固化内存的状态可以使用MemoryMetricsMXBean
和PersistenceMetricsMXBean
接口进行保留,可以使用任何兼容JMX的工具或者API接入bean。
该JMX bean暴露了和MemoryMetrics
和PersistenceMetrics
接口一样的指标集合,同时还有一些其他的。