@liyuj
2017-12-05T23:17:46.000000Z
字数 21586
阅读 6432
Apache-Ignite-2.3.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.setDataStorageConfiguration(...)
方法传递一个org.apache.ignite.configuration.DataStorageConfiguration
即可,下面是可用的参数:
参数 | 描述 | 默认值 |
---|---|---|
setPageSize(...) |
设置默认页面大小。通常只有当应用产生大量的对象无法放入单一页面时,才需要修改这个参数。 | 4 KB |
setDefaultDataRegionConfiguration(...) |
设置自动创建的默认内存区的大小,如果该属性未设置,那么默认的区域会消耗本地主机可用内存的20%。 | 内存的20% ,禁用持久化 |
setDataRegionConfigurations(...) |
配置一个节点上配置的所有数据区的列表。 | 空数组,用于创建默认区域的配置是不会保存在这里的。 |
setSystemRegionInitialSize(...) |
设置为系统需求预留的内存区域的初始大小。 | 40 MB |
setSystemRegionMaxSize(...) |
设置为系统需求预留的内存区域的最大值。因为内部数据结构的限制,总大小不应小于10MB。 | 100 MB |
setConcurrencyLevel(...) |
设置在Ignite的内部页面映射表中并行段的数量。 | 可用CPU总数的4倍。 |
在Ignite的javadoc中可以看到DataStorageConfiguration
的完整参数列表。
下面是使用DataStorageConfiguration
如何修改页面大小和并发级别的示例代码:
XML:
<bean class="org.apache.ignite.configuration.IgniteConfiguration">
<property name="dataStorageConfiguration">
<bean class="org.apache.ignite.configuration.DataStorageConfiguration">
<!-- Set concurrency level -->
<property name="concurrencyLevel" value="4"/>
<!-- Set the page size to 8 KB -->
<property name="pageSize" value="8192"/>
</bean>
</property>
<!--- Additional settings ---->
</bean>
Java:
// Ignite configuration.
IgniteConfiguration cfg = new IgniteConfiguration();
// Durable memory configuration.
DataStorageConfiguration storageCfg = new DataStorageConfiguration();
// Altering the concurrency level.
storageCfg.setConcurrencyLevel(4);
// Changing the page size to 8 KB.
storageCfg.setPageSize(8192);
// Applying the new configuration.
cfg.setDataStorageConfiguration(storageCfg);
固化内存默认会初始化一个单一的可扩展内存区,它会占用本地主机的20%可用内存并且禁用持久化。也可以使用org.apache.ignite.configuration.DataRegionConfiguration
类,定义多个数据区,它们可以有不同的参数,比如区大小、持久化和退出策略。
比如,要配置一个500MB的内存区并且开启持久化,那么就需要定义一个如下所示的配置:
XML:
<bean class="org.apache.ignite.configuration.IgniteConfiguration">
<!-- Durable memory configuration. -->
<property name="dataStorageConfiguration">
<bean class="org.apache.ignite.configuration.DataStorageConfiguration">
<property name="dataRegionConfigurations">
<list>
<!--
Defining a data region that will consume up to 500 MB of RAM and
will have eviction and persistence enabled.
-->
<bean class="org.apache.ignite.configuration.DataRegionConfiguration">
<!-- Custom region name. -->
<property name="name" value="500MB_Region"/>
<!-- 100 MB initial size. -->
<property name="initialSize" value="#{100L * 1024 * 1024}"/>
<!-- 500 MB maximum size. -->
<property name="maxSize" value="#{500L * 1024 * 1024}"/>
<!-- Enabling persistence for the region. -->
<property name="persistenceEnabled" value="true"/>
</bean>
</list>
</property>
</bean>
</property>
<!-- The rest of the configuration. -->
</bean>
Java:
// Ignite configuration.
IgniteConfiguration cfg = new IgniteConfiguration();
// Durable Memory configuration.
DataStorageConfiguration storageCfg = new DataStorageConfiguration();
// Creating a new data region.
DataRegionConfiguration regionCfg = new DataRegionConfiguration();
// Region name.
regionCfg.setName("500MB_Region");
// Setting initial RAM size.
regionCfg.setInitialSize(100L * 1024 * 1024);
// Setting maximum RAM size.
regionCfg.setMaxSize(500L * 1024 * 1024);
// Enable persistence for the region.
regionCfg.setPersistenceEnabled(true);
// Setting the data region configuration.
storageCfg.setDataRegionConfigurations(regionCfg);
// Applying the new configuration.
cfg.setDataStorageConfiguration(storageCfg);
下一步,要使用这个配置好的区域,使得Ignite缓存将数据存储于其中,需要将区域的名字(500MB_Region
)传递给org.apache.ignite.configuration.CacheConfiguration.setDataRegionName(...)
方法:
XML:
<bean class="org.apache.ignite.configuration.IgniteConfiguration">
<!-- Durable Memory and other configuration parameters. -->
<!-- ....... -->
<property name="cacheConfiguration">
<list>
<!-- Cache that is mapped to a specific data region. -->
<bean class="org.apache.ignite.configuration.CacheConfiguration">
<!--
Assigning the cache to the `500MB_Region` defined earlier.
-->
<property name="dataRegionName" value="500MB_Region"/>
<!-- Cache 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();
// Binding the cache to the earlier defined region.
cacheCfg.setDataRegionName("500MB_Region");
// Setting the cache name.
cacheCfg.setName("SampleCache");
// Applying the cache configuration.
cfg.setCacheConfiguration(cacheCfg);
用这个配置启动Ignite集群后,固化内存会分配一个初始大小为100MB的内存区,然后它可以增长到500MB。数据的超集会一直存储于磁盘上,确保即使内存空间不足也不会出现数据丢失的情况。如果开启了持久化,Ignite会自动地使最近最少使用的数据退出。这个区域只会存储SampleCache
的所有数据,除非通过前述的方式显式地指定其它的内存区,其他的缓存都会绑定到默认的内存区。
如果禁用了持久化并且所有的内存使用量超过了500MB,那么会抛出内存溢出异常,要避免这个问题,可以采用如下的办法来解决:
固化内存是堆外的内存,它是在Java堆之外分配的内存区,然后将数据条目存储在其中。但是,通过将org.apache.ignite.configuration.CacheConfiguration.setOnheapCacheEnabled(...)
配置为true
为缓存条目开启堆内缓存。
当以二进制形式处理缓存条目或者调用缓存的反序列化时在服务端节点有大量的读操作,堆内缓存对这样的场景非常有用。比如,当一个分布式计算或者部署的服务为下一步处理从缓存中获取一些数据时,就会发生这样的情况。
堆内缓存大小
要管理堆内缓存的大小,避免其不断增长,一定要配置一个可用的基于缓存条目的退出策略
。
Ignite支持两种数据退出策略:
如果开启了Ignite持久化本策略不生效
注意如果开启了Ignite持久化,那么基于页面的退出策略是无效的,因为最旧的页面会自动地从内存中清除。
对于存储于堆外内存中的数据,Ignite支持基于页面的退出。当达到最大内存使用量时,堆外内存中的一个页面就会退出。
每个数据区都可以配置基于页面的退出,Ignite的固化内存是由通过DataRegionConfiguration
配置的一个或者多个数据区组成的。默认情况下一个区域会一直增长直到达到最大值,为避免可能的内存区溢出,需要设置一个数据页面的退出模式:Random-LRU
或者Random-2-LRU
,通过DataRegionConfiguration.setPageEvictionMode(...)
配置参数进行设定,退出模式会跟踪数据页面的使用然后根据模式的实现退出部分数据。
Random-LRU
要启用Random-LRU退出算法,可以将DataPageEvictionMode.RANDOM_LRU
传递给相应的DataRegionConfiguration
,如下所示:
XML:
<bean class="org.apache.ignite.configuration.IgniteConfiguration">
<!-- Durable memory configuration. -->
<property name="dataStorageConfiguration">
<bean class="org.apache.ignite.configuration.DataStorageConfiguration">
<property name="dataRegionConfigurations">
<list>
<!--
Defining a data region that will consume up to 20 GB of RAM.
-->
<bean class="org.apache.ignite.configuration.DataRegionConfiguration">
<!-- Custom region name. -->
<property name="name" value="20GB_Region"/>
<!-- 500 MB initial size (RAM). -->
<property name="initialSize" value="#{500L * 1024 * 1024}"/>
<!-- 20 GB maximum size (RAM). -->
<property name="maxSize" value="#{20L * 1024 * 1024 * 1024}"/>
<!-- Enabling RANDOM_LRU eviction for this region. -->
<property name="pageEvictionMode" value="RANDOM_LRU"/>
</bean>
</list>
</property>
</bean>
</property>
<!-- The rest of the configuration. -->
</bean>
Java:
// Ignite configuration.
IgniteConfiguration cfg = new IgniteConfiguration();
// Durable Memory configuration.
DataStorageConfiguration storageCfg = new DataStorageConfiguration();
// Creating a new data region.
DataRegionConfiguration regionCfg = new DataRegionConfiguration();
// Region name.
regionCfg.setName("20GB_Region");
// 500 MB initial size (RAM).
regionCfg.setInitialSize(500L * 1024 * 1024);
// 20 GB max size (RAM).
regionCfg.setMaxSize(20L * 1024 * 1024 * 1024);
// Enabling RANDOM_LRU eviction for this region.
regionCfg.setPageEvictionMode(DataPageEvictionMode.RANDOM_LRU);
// Setting the data region configuration.
storageCfg.setDataRegionConfigurations(regionCfg);
// Applying the new configuration.
cfg.setDataStorageConfiguration(storageCfg);
Random-LRU算法工作方式如下:
最后使用
时间戳;Random-2-LRU
Random-2-LRU退出算法是Random-LRU算法的抗扫描版,要启用这个算法,将DataPageEvictionMode.RANDOM_2_LRU
传递给相应的DataRegionConfiguration
即可,如下所示:
XML:
<bean class="org.apache.ignite.configuration.IgniteConfiguration">
<!-- Durable memory configuration. -->
<property name="dataStorageConfiguration">
<bean class="org.apache.ignite.configuration.DataStorageConfiguration">
<property name="dataRegionConfigurations">
<list>
<!--
Defining a data region that will consume up to 20 GB of RAM.
-->
<bean class="org.apache.ignite.configuration.DataRegionConfiguration">
<!-- Custom region name. -->
<property name="name" value="20GB_Region"/>
<!-- 500 MB initial size (RAM). -->
<property name="initialSize" value="#{500L * 1024 * 1024}"/>
<!-- 20 GB maximum size (RAM). -->
<property name="maxSize" value="#{20L * 1024 * 1024 * 1024}"/>
<!-- Enabling RANDOM_2_LRU eviction for this region. -->
<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.
DataStorageConfiguration storageCfg = new DataStorageConfiguration();
// Creating a new data region.
DataRegionConfiguration regionCfg = new DataRegionConfiguration();
// Region name.
regionCfg.setName("20GB_Region");
// 500 MB initial size (RAM).
regionCfg.setInitialSize(500L * 1024 * 1024);
// 20 GB max size (RAM).
regionCfg.setMaxSize(20L * 1024 * 1024 * 1024);
// Enabling RANDOM_2_LRU eviction for this region.
regionCfg.setPageEvictionMode(DataPageEvictionMode.RANDOM_2_LRU);
// Setting the data region configuration.
storageCfg.setDataRegionConfigurations(regionCfg);
// Applying the new configuration.
cfg.setDataStorageConfiguration(storageCfg);
在Random-2-LRU算法中,每个数据页面会存储两个最近访问时间戳,退出时,算法会随机地从跟踪数组中选择5个索引值,然后两个最近时间戳中的最小值会被用来和另外四个候选页面中的最小值进行比较。
Random-2-LRU比Random-LRU要好,因为它解决了昙花一现
的问题,即一个页面很少被访问,但是偶然地被访问了一次,然后就会被退出策略保护很长时间。
Random-LRU与Random-2-LRU的对比
Random-LRU退出模式中,一个数据页面只会保存一份最近访问时间戳,而Random-2-LRU模式会为每个数据页面保存两份最近访问时间戳。
退出的触发
一个数据页面退出算法的触发默认是当内存区的总消耗量达到了90%,如果要调整的话,可以使用DataRegionConfiguration.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的固化内存可以通过DataRegionMetrics
接口和JMX bean暴露的若干接口进行监控,这有助于跟踪所有的内存使用,度量性能,以及在出现性能瓶颈时进行优化。
对于一个节点来说,要获取和固化内存有关的指标,DataRegionMetrics
是主要的入口点,因为一个节点可配置多个内存区,因此通过API调用可以为每个内存区单独收集和获取指标。
当前MemoryMetrics
提供了如下的方法:
方法名 |
描述 |
---|---|
getName() |
返回指标所属内存区的名字。 |
getTotalAllocatedPages() |
获取该内存区已分配页面的总数量。 |
getAllocationRate() |
获取该内存区的页面分配比率。 |
getEvictionRate() |
获取该内存区的页面退出比率。 |
getLargeEntriesPagesPercentage() |
获取被超过页面大小的大条目完全占用的页面的百分比,大条目也可以拆分为多个片段,每个片段适配一个单个页面。 |
getPagesFillFactor() |
获取仍然空闲可用的空间的百分比。 |
getDirtyPages() |
获取脏页面的数量(页面的内容与磁盘上同一页的内容不同),这个指标只有当持久化存储启用的时候才可用。 |
getPagesReplaceRate() |
获取内存中的页面被磁盘上的其他页面替换的速率(页/秒)。这个指标有效地表示了内存中页面退出并且被磁盘上的页面替换的速率,这个指标只有当持久化存储启用的时候才可用。 |
getPhysicalMemoryPages() |
获取当前加载进内存的页面数量,如果持久化存储未启用,这个指标会等同于getTotalAllocatedPages() 。 |
调用Ignite.dataRegionMetrics()
方法可以获得最新的指标快照然后进行迭代,如下所示:
// Get the metrics of all the data regions configured on a node.
Collection<DataRegionMetrics> regionsMetrics = ignite.dataRegionMetrics();
// Print out some of the metrics.
for (DataRegionMetrics metrics : regionsMetrics) {
System.out.println(">>> Memory Region Name: " + metrics.getName());
System.out.println(">>> Allocation Rate: " + metrics.getAllocationRate());
System.out.println(">>> Fill Factor: " + metrics.getPagesFillFactor());
}
另外,还有一些指标是只和持久化存储有关的,这些都是通过DataStorageMetrics
接口提供的,部分如下所示:
方法名 | 描述 |
---|---|
getWalWritingRate() |
获取上次配置的时间间隔内每秒写入的WAL记录平均数量。 |
getWalArchiveSegments() |
获取WAL归档文件中的当前WAL段数。 |
getWalFsyncTimeAverage() |
获取上次配置的时间间隔内平均WAL fsync持续时间(毫秒)。 |
getLastCheckpointingDuration() |
获取最近的检查点进程持续时间(毫秒)。 |
getLastCheckpointTotalPagesNumber() |
获取最近的检查点进程内的页面写入总量。 |
调用Ignite.dataStorageMetrics()
方法可以获得和使用最新的持久化指标快照,如下例所示:
// Getting metrics.
DataStorageMetrics pm = ignite.dataStorageMetrics();
System.out.println("Fsync duration: " + pm.getLastCheckpointFsyncDuration());
System.out.println("Data pages: " + pm.getLastCheckpointDataPagesNumber());
System.out.println("Checkpoint duration:" + pm.getLastCheckpointDuration());
另外,使用DataRegionMetricsMXBean
和DataStorageMetricsMXBean
接口,还可以观察到Ignite固化内存的状态,可以使用任何兼容JMX的工具和API进行接入,它们暴露了同样的指标,同时还有一些其它的接口。
启用指标收集
内存指标收集不是没有代价的操作,可能会影响应用的性能,因此,内存指标收集默认是关闭的。
要打开它,可以使用如下的两个方式:
1.对于每个希望收集内存指标的内存区,设置MemoryPolicyConfiguration.setMetricsEnabled(boolean)
为true
;
2.对于希望获得和持久化有关的指标,设置PersistentStoreConfiguration.setMetricsEnabled(boolean)
为true
;
3.通过下面描述的特定JMX bean暴露的MemoryMetricsMXBe
PersistenceMetricsMXBeanan.enableMetrics()
方法启用;
4.通过下面描述的特定JMX bean暴露的PersistenceMetricsMXBean.enableMetrics()
方法来激活和持久化有关的指标的收集。