深入浅出Ignite

ignite是什么?

Apache Ignite是一个分布式数据库,支持以内存级的速度进行高性能计算。
Apache Ignite为一个独立的、易于集成的内存组件的集合,目的是改进应用程序的性能和可扩展性,部分组件包括:
- 高级的集群化
- 数据网格(Data grid)
- 流计算和CEP(Streaming grid)
- 计算网格(Compute grid)
- 服务网格(Service grid)
- Ignite文件系统
- 分布式数据结构
- 分布式消息
- 分布式事件
- 大数据加速器(Bigdata accelerator)
- Spark共享RDD

apache ignite核心技术特点如下:
- 开源
- 纯Java编写
- 基于Spring框架
- 支持.Net、C++和PHP语言

提供的主要功能如下所示:
- Elasticity 弹性:集群可以通过添加节点进行水平扩展;
- Persistence 持久性:数据网格可以将缓存中的数据持久化到关系型数据库中,甚至是NoSQL数据库中,例如MongoDB或Cassandra;
- Cache as a Service(CaaS) 缓存即服务:允许跨组织、多应用去访问管理内存缓存而不是慢速的基于磁盘读写的数据库;
- 2nd Level Cache 二级缓存:可以作为Hibernate和MyBatis持久化框架的二级缓存层使用;
- 高性能hadoop加速器:apache ignite可以替代hadoop task tracker、job tracker和HDFS,从而提高大数据分析的性能;
- 在Spark应用中共享内存:ignite RDD允许在不同的Spark作业和应用之间轻松的共享状态;
- 分布式计算:apache ignite提供了一组简单的API,允许用户在多个节点上获得高性能的分布计算和处理数据的能力。ignite的分布式服务对于开发和执行微服务架构也会提供很多帮助。
- 流:apache ignite允许可伸缩和容错内存中处理连续不断的数据流,而不是在数据存储在数据库后分析数据。
- 分区和复制: Ignite在内存存储中,可以是分区模式,也可以是复制模式,复制模式中,数据在集群中的每个节点都有一份副本,而分区模式,Ignite会在多个集群节点上对数据进行平均拆分,因此可以在内存及磁盘上存储TB级的数据。

Apache Ignite应用架构

让我们快速浏览以下传统的应用结构,如下图所示:

传统的应用程序体系结构选择同步读写操作的数据存储。对于要求数据一致性和持久性可以起到很好的作用,但是如果有大量事务在队列中等待,就很容易出现性能瓶颈。
- 大容量的事务处理

在应用环境中添加一层内存数据网格,它使服务器的RAM来存储应用程序所需的大部分数据。

数据网格位于应用服务和数据存储之间。内存数据网格在活动的内存中缓存由客户端频繁访问的数据,并且可以在必要时访问持久化存储,甚至可以对持久化存储进行异步发送或接收更新数据的操作。如下图所示:

通过使用内存网格,使数据更接近应用程序端。这样可以减少了响应时间,并且可以将事务时间从几秒降低到几分之一秒。
通过这种方式,应用程序可以支持大量涉及tb级操作数据的并发事务,从而为客户提供更快、更可靠的事务体验。与传统的RDBMS相比,它是一个更现代的可伸缩数据管理系统,随着需求的增加,它能够弹性伸缩。
- 弹性网络加速
使用像Apache Ignite这样的内存数据网格,可以对web应用程序提供容错性,并加速web应用程序的性能。在不改变任何代码的情况下,可以通过缓存共享web应用程序之间的会话状态。如图所示:

上述方法提供了系统的高可用性,并提升了用户体验。如果使用apache ignite的方案,可以使web会话集群和用户web会话的复制机制的性能非常高。

  • 事件处理和实时分析

数据可以告诉我们现在的业务背景是什么。随着IoT最为持续的数据源,使用热数据hot data比以往任何时候都要多。
传统的数据管理系统无法快速处理数据,从而在发生重大事件时及时通知业务,例如:在线信用卡欺诈检测或风险计算。apache ignite允许在可伸缩和容错的内存中处理连续不断的数据流,而不是数据到达数据库后再分析。

这不仅可以使你能够关联关系并从大量的数据中检测出有意义的模式,而且还可以更快、更高效的进行处理。
apache ignite数据网格可以管理大量传入的数据,并在服务器发生变更时向业务应用程序推送通知。ignite的持续查询功能,允许系统快速的访问大量的传入数据,并采取行动。

  • 分布式微服务

微服务体系结构有很多优点,并且具有一定程度的模块化,这对于单模块代码库来说是非常难以实现的。Apache Ignite的内存数据网格可以为同一分布式集群中的相应微服务提供独立的缓存节点,对比传统方法具有一些优势。

它允许您最大限度地利用数据结构/网格资源。在内存中集群上运行的服务比基于磁盘的应用程序服务器要快得多。Apache Ignite基于微服务的服务网格提供了一个平台来自动部署集群中的任何数量的分布式服务实例。

  • 大数据加速器

Hadoop以其经济地存储和分析大型数据集的能力而被广泛使用,并且早已超越了作为新兴技术的地位。然而,它的批处理调度开销以及基于磁盘的数据存储使它不适合用于分析生产环境中的实时数据。限制Hadoop和Map/Reduce性能扩展的一个主要因素是Hadoop依赖于生成大量输入/输出(I/O)文件的文件系统。另一种方法是将所需的分布式数据存储在内存中。在内存中放置Map/Reduce,以消除文件I/O延迟。

Apache Ignite提供了一组有用的组件,允许内存中的Hadoop作业执行和文件系统操作。Apache Ignite Hadoop accelerator可以自动部署所有必需的可执行程序和库,以便在jvm上执行Map/Reduce,这大大减少了启动时间,缩短到毫秒。这可以通过避免访问辅助存储的延迟来加快速度。此外,由于执行引擎与内存中的数据网格集成,因此可以有效地将驻留在数据网格中的键/值对读入执行引擎,以最小化访问时间。

  • 缓存即服务

数据驱动的应用程序加载时间太长,使用起来既枯燥又令人沮丧。五分之四的在线用户会在加载页面时点击离开。内存中的数据网格可以提供跨组织的公共缓存层,这可以允许多个应用程序访问管理的内存缓存。

集群化

在启动时,将为节点分配以下两个角色之一:服务端节点或客户端节点。服务端节点是集群的主体,它们存储数据、执行计算任务等。客户端节点作为常规节点加入拓扑,但不存储数据。客户端节点用于将数据流传输到集群中并执行用户查询。
Ignite集群基于无共享架构,所有的集群节点都是平等的,独立的,整个集群不存在单点故障。

要组成集群,每个节点必须能够连接到所有其他节点。为了确保这一点,必须配置适当的发现机制。
提示:
除了客户端节点,还可以使用瘦客户端来定义和操作集群中的数据


发现机制
节点间可以自动相互发现并组成集群,这样就可以在需要时进行横向扩展,而不必重启整个集群。开发者还可以利用Ignite的混合云支持,其可以在私有云和公有云(例如Amazon Web Services)之间建立连接,从而提供更多样化的选择。
Ignite针对不同的场景,提供了两种发现机制:
TCP/IP发现针对百级以内节点的集群规模进行了优化;
ZooKeeper发现可将Ignite集群扩展到上千个节点,仍能保持线性扩展性和性能。

TCP/IP发现

Ignite集群中,节点间可以通过DiscoverySpi相互发现。DiscoverySpi的默认实现是TcpDiscoverySpi,其使用的是TCP/IP协议,节点发现具体可以配置为基于组播或者基于静态IP模式。
组播IP探测器
TcpDiscoveryMulticastIpFinder使用组播来发现每个节点,这也是默认的IP探测器,下面是通过配置文件以及编程模式进行配置的示例:

<bean class="org.apache.ignite.configuration.IgniteConfiguration">

    <property name="discoverySpi">
        <bean class="org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi">
            <property name="ipFinder">
                <bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.multicast.TcpDiscoveryMulticastIpFinder">
                    <property name="multicastGroup" value="228.10.10.157"/>
                </bean>
            </property>
        </bean>
    </property>

</bean>

静态IP探测器
静态IP探测器实现了TcpDiscoveryVmIpFinder,可以指定一组IP地址和端口,IP探测器将检查这些IP地址和端口以进行节点发现。
只需提供至少一个远程节点的IP地址即可,但是通常建议提供2或3个规划范围内节点的地址。一旦建立了与提供的任何IP地址的连接,Ignite就会自动发现所有其他节点。
提示
除了在配置文件中指定以外,还可以通过IGNITE_TCP_DISCOVERY_ADDRESSES环境变量或者同名的系统属性来指定,地址间用逗号分割,还可以选择包含端口范围。
提示
TcpDiscoveryVmIpFinder默认用于非共享模式。如果打算启动一个服务端节点,则IP地址列表也会包含本地节点的地址,这时该节点将不会等到其他节点加入集群,而是成为第一个集群节点并开始正常运行。
可以通过编程或者配置文件的方式配置静态IP探测器:

<bean class="org.apache.ignite.configuration.IgniteConfiguration">
    <property name="discoverySpi">
        <bean class="org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi">
            <property name="ipFinder">
                <bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder">
                    <property name="addresses">
                        <list>
                            <!--
                              Explicitly specifying address of a local node to let it start and
                              operate normally even if there is no more nodes in the cluster.
                              You can also optionally specify an individual port or port range.
                              -->
                            <value>1.2.3.4</value>
                            <!--
                              IP Address and optional port range of a remote node.
                              You can also optionally specify an individual port.
                              -->
                            <value>1.2.3.5:47500..47509</value>
                        </list>
                    </property>
                </bean>
            </property>
        </bean>
    </property>
</bean>

警告
提供多个地址时,要确认这些地址都是有效的。无法访问的地址会增加节点加入集群所需的时间。假设设置了5个IP地址,但是其中2个没有监听输入连接,如果Ignite开始通过这2个无法访问的地址接入集群,它将影响节点的启动速度。
更多探测器请访问官网文档

网络配置

IPv4和IPv6
Ignite尝试支持IPv4和IPv6,但这有时会导致集群分离的问题。一个可能的解决方案(除非确实需要IPv6)是通过设置-Djava.net.preferIPv4Stack=trueJVM参数限制Ignite使用IPv4。
发现
发现机制的网络参数,该机制通过TcpDiscoverySpi类实现,通过TCP/IP协议交换发现消息。
可以通过如下方式调整该发现机制的参数:

<bean class="org.apache.ignite.configuration.IgniteConfiguration">

    <property name="discoverySpi">
        <bean class="org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi">
            <property name="localPort" value="8300"/>
        </bean>
    </property>

</bean>

警告
应该使用将用于节点间通信的IP地址初始化IgniteConfiguration.localHost或TcpDiscoverySpi.localAddress参数。节点默认会绑定并监听其运行的主机上所有的可用IP地址,如果某些地址无法从其他集群节点访问,则会延长节点故障的检测时间。
通信
在节点相互发现并组成集群之后,节点通过通信SPI交换消息。消息代表分布式集群操作,例如任务执行、数据修改操作、查询等。通信SPI的默认实现使用TCP/IP协议交换消息(TcpCommunicationSpi)。
每个节点都打开一个本地通信端口和其他节点连接并发送消息的地址。在启动时,节点会尝试绑定到指定的通信端口(默认为47100)。如果端口已被使用,则节点会递增端口号,直到找到可用端口为止。尝试次数由localPortRange属性定义(默认为100)。

<bean class="org.apache.ignite.configuration.IgniteConfiguration">

    <property name="communicationSpi">
        <bean class="org.apache.ignite.spi.communication.tcp.TcpCommunicationSpi">
            <property name="localPort" value="4321"/>
        </bean>
    </property>

</bean>

连接超时
可以在节点配置中设置故障检测超时,如下所示。默认值使发现SPI在大多数本地环境和容器化环境中都能可靠地工作。但是在稳定的低延迟网络中,可以将参数设置为约200毫秒,以便更快地检测故障并对故障做出响应。

<bean class="org.apache.ignite.configuration.IgniteConfiguration">

    <property name="failureDetectionTimeout" value="5000"/>

    <property name="clientFailureDetectionTimeout" value="10000"/>

</bean>

客户端节点连接

客户端节点重连
有几种情况客户端会从集群中断开:
- 由于网络原因,客户端无法和服务端重建连接;
- 与服务端的连接有时被断开,客户端也可以重建与服务端的连接,但是由于服务端无法获得客户端心跳,服务端仍然断开客户端节点;
- 慢客户端会被服务端节点踢出。
- 当一个客户端发现它与一个集群断开时,会为自己赋予一个新的节点ID然后试图与该服务端重新连接。注意这会产生一个副作用,就是当客户端重建连接时本地ClusterNode的id属性会发生变化,这意味着,如果业务逻辑依赖于这个id,就会受到影响。
- 在节点配置中可以禁用客户端重连:

<bean class="org.apache.ignite.configuration.IgniteConfiguration">
    <property name="clientMode" value="true"/>

    <property name="discoverySpi">
        <bean class="org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi">
            <!-- prevent this client from reconnecting on connection loss -->
            <property name="clientReconnectDisabled" value="true"/>
            <property name="ipFinder">

                <bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder">
                    <property name="addresses">
                        <list>
                            <value>127.0.0.1:47500..47509</value>
                        </list>
                    </property>
                </bean>
            </property>
        </bean>
    </property>
    <property name="communicationSpi">
        <bean class="org.apache.ignite.spi.communication.tcp.TcpCommunicationSpi">
            <property name="slowClientQueueLimit" value="1000"/>
        </bean>
    </property>
</bean>

当客户端处于一个断开状态并且试图重建与集群的连接过程中时,Ignite API会抛出一个IgniteClientDisconnectedException异常,这个异常提供了一个Future表示重连操作,可以使用这个Future来等待操作完成。

IgniteCache cache = ignite.getOrCreateCache(new CacheConfiguration<>("myCache"));

try {
    cache.put(1, "value");
} catch (IgniteClientDisconnectedException e) {
    if (e.getCause() instanceof IgniteClientDisconnectedException) {
        IgniteClientDisconnectedException cause = (IgniteClientDisconnectedException) e.getCause();

        cause.reconnectFuture().get(); // Wait until the client is reconnected.
        // proceed
    }
}

客户端断连/重连事件
客户端断连/重连集群时也会在客户端触发两个发现事件:
- EVT_CLIENT_NODE_DISCONNECTED
- EVT_CLIENT_NODE_RECONNECTED
可以监听这些事件然后执行自定义的逻辑
管理慢客户端
很多环境中,客户端节点是在主集群外启动的,机器和网络都比较差,而有时服务端可能会产生负载(比如持续查询通知)而客户端没有能力处理,导致服务端的输出消息队列不断增长,这可能最终导致服务端出现内存溢出或者导致整个集群阻塞。
要管理这样的状况,可以配置允许向客户端节点输出消息的最大值,如果输出队列的大小超过配置的值,该客户端节点会从集群断开。
下面是如何配置慢客户端队列限值的示例:

<bean class="org.apache.ignite.configuration.IgniteConfiguration">
    <property name="clientMode" value="true"/>

    <property name="communicationSpi">
        <bean class="org.apache.ignite.spi.communication.tcp.TcpCommunicationSpi">
            <property name="slowClientQueueLimit" value="1000"/>
        </bean>
    </property>
</bean>

基线拓扑

基准拓扑是一组持有数据数据的节点。引入基线拓扑概念是为了能够控制数据再平衡的时机。例如,如果有一个由3个节点组成的集群,并且数据分布在这些节点上,然后又添加了2个节点,则再平衡过程将在所有5个节点之间重新分配数据。再平衡过程发生在基线拓扑更改时,可以自动发生也可以手动触发。
基线拓扑仅包括服务端节点,不包括客户端节点,因为它们不存储数据。
基线拓扑的目的是:
- 当服务端节点短时间离开集群时,例如由于偶发的网络故障或计划内的服务器维护,可以避免不必要的数据移动;
- 可以控制数据再平衡的时机。
当基线拓扑自动调整功能启用后,基线拓扑会自动改变。这是纯内存集群的默认行为,但是对于开启持久化的集群,必须手动启用基线拓扑自动调整功能。该选项默认是禁用的,必须手动更改基线拓扑,可以使用控制脚本来更改基线拓扑。

安装

unzip apache-ignite-2.8.1-bin.zip;
mv apache-ignite-2.8.1-bin /home/tfd/app/ignite;
cp /home/tfd/app/ignite/examples/config/example-default.xml /home/tfd/app/ignite/config/default-config.xml;
sed -i 's/IGNITE_SERVER1_IP/192.168.118.170/' /home/tfd/app/ignite/config/default-config.xml;
sed -i 's/IGNITE_SERVER2_IP/192.168.118.171/' /home/tfd/app/ignite/config/default-config.xml;
sed -i 's/IGNITE_SERVER3_IP/192.168.118.172/' /home/tfd/app/ignite/config/default-config.xml;
sed -i '11i\JVM_OPTS="-server  -Xms1g  -Xmx1g -XX:+AlwaysPreTouch -XX:+UseG1GC -XX:+ScavengeBeforeFullGC -XX:+DisableExplicitGC"' /home/tfd/app/ignite/bin/ignite.sh;

启动

nohup /home/tfd/app/ignite/bin/ignite.sh /home/tfd/app/ignite/config/default-config.xml &
/home/tfd/app/ignite/bin/control.sh --activate
/home/tfd/app/ignite/bin/control.sh --baseline

数据建模

精心设计的数据模型可以提高应用的性能,高效地利用资源,并助力实现业务目标。在设计数据模型时,了解数据在Ignite集群中的分布方式以及访问数据的不同方式非常重要。

为了了解数据在Ignite中的存储和使用,有必要区分集群中数据的物理组织和逻辑表示,即用户将如何在应用中查看其数据。

在物理层,每个数据条目(缓存条目或表数据行)都以二进制对象的形式存储,然后整个数据集被划分为多个较小的集合,称为分区。分区均匀地分布在所有节点上。数据和分区之间以及分区和节点之间的映射方式都由关联函数控制。

在逻辑层,数据应该以易于使用的方式表示,并方便用户在其应用中使用。Ignite提供了两种不同的数据逻辑表示:键-值缓存和SQL表(模式)。尽管这两种表示形式可能看起来有所不同,但实际上它们是等效的,并且可以表示同一组数据。

提示
注意,在Ignite中,SQL表和键-值缓存的概念是相同(内部)数据结构的两个等效表示,可以使用键-值API或SQL语句或同时使用两者来访问数据。
键-值缓存与SQL表
缓存是键-值对的集合,可以通过键-值API对其进行访问。Ignite中的SQL表与传统RDBMS中表的概念相对应,但有一些附加约束。例如每个SQL表必须有一个主键。

具有主键的表可以表示为键-值缓存,其中主键列用作键,其余的表列代表对象的字段(值)。

这两种表示形式之间的区别在于访问数据的方式。键-值缓存可以通过支持的编程语言来处理对象。SQL表支持传统的SQL语法,并且有助于从现有数据库进行迁移。开发者可以根据业务场景,灵活使用一种或两种方法。

缓存API支持以下功能:
- 支持JCache(JSR 107)规范;
- ACID事务;
- 持续查询;
- 事件。
二进制对象格式
Ignite以称为二进制对象的特定格式存储数据条目,这种序列化格式具有以下优点:
- 可以从序列化的对象读取任意字段,而无需把对象完全反序列化,这完全消除了在服务端节点的类路径上部署键和值类的要求;
- 可以从相同类型的对象中添加或删除字段。考虑到服务端节点没有模型类的定义,此功能允许动态更改对象的结构,甚至允许多个客户端共存不同版本的类定义;
- 可以基于类型名称构造新对象,而完全不需要类定义,因此可以动态创建类型;
- 在Java、.NET和C++平台之间可以互操作。
- 仅当使用默认的二进制编组器(即在配置中未设置其他编组器)时,才可以使用二进制对象。
数据分区
数据分区是一种将大型数据集细分为较小的块,然后在所有服务端节点之间平均分配的方法。
分区由关联函数控制,关联函数确定键和分区之间的映射。每个分区由一组有限的数字(默认为0到1023)标识。分区集合分布在当前可用的服务端节点上。因此,每个键都会映射到某个节点,并存储在该节点上。当集群中节点的数量发生变化时,将通过称为再平衡的过程在新的节点集之间重新分配分区。

关联函数将关联键作为参数。关联键可以是缓存中存储的对象的任何字段(SQL表中的任何列)。如果未指定关联键,则默认使用键(对于SQL表,它是PRIMARY KEY列)。

分区通过将读写操作分布式化来提高性能。此外还可以设计数据模型,以使同一类数据条目存储在一起(即存储在一个分区中)。当请求该数据时,仅扫描少量分区,这种技术称为关联并置。

分区实际上可以在任何规模上实现线性可伸缩性。随着数据集的增长,可以向集群添加更多节点,Ignite会确保数据在所有节点间“平均”分布。

关联函数
关联函数控制数据条目和分区以及分区和节点之间的映射。默认的关联函数实现了约会哈希算法。它在分区到节点的映射中允许一些差异(即某些节点可能比其他节点持有的分区数量略多)。但是,关联函数可确保当拓扑更改时,分区仅迁移到新加入的节点或从离开的节点迁移,其余节点之间没有数据交换。

分区/复制模式
创建缓存或SQL表时,可以在缓存操作的分区模式和复制模式之间进行选择。两种模式设计用于不同的场景,并提供不同的性能和可用性优势。
PARTITIONED
在这种模式下,所有分区在所有服务端节点间平均分配。此模式是可扩展性最高的分布式缓存模式,可以在所有节点上的总内存(RAM和磁盘)中存储尽可能多的数据,实际上节点越多,可以存储的数据就越多。

与REPLICATED模式不同,该模式下更新成本很高,因为集群中的每个节点都需要更新。而在PARTITIONED模式下,更新成本很低,因为每个键只需要更新一个主节点(以及可选的一个或多个备份节点)。但是读取成本会高,因为只有某些节点才缓存有该数据。

提示
当数据集很大且更新频繁时,分区缓存是理想的选择。

在下图中,在JVM1中运行的节点是键A的主要节点,但它也存储了所有其他键(B,C,D)的备份副本。

REPLICATED
在REPLICATED模式下,所有数据(每个分区)都将复制到集群中的每个节点。由于每个节点上都有完整的数据,此缓存模式提供了最大的数据可用性。但是每次数据更新都必须传播到所有其他节点,这可能会影响性能和可扩展性。
提示
当数据集较小且不经常更新时,复制缓存非常理想。
在下图中,在JVM1中运行的节点是键A的主要节点,但它也存储了所有其他键(B,C,D)的备份副本。

因为相同的数据存储在所有集群节点上,所以复制缓存的大小受节点上可用内存(RAM和磁盘)的数量限制。对于缓存读多写少且数据集较小的场景,此模式是理想的。如果业务系统确实在80%的时间内都在进行缓存查找,那么应该考虑使用REPLICATED缓存模式。
备份分区
Ignite默认会保存每个分区的单个副本(整个数据集的单个副本)。这时如果一个或多个节点故障,存储在这些节点上的分区将无法访问,为避免这种情况,Ignite可以配置为每个分区维护备份副本。
警告
备份默认是禁用的。

备份副本的配置是缓存(表)级的,如果配置2个备份副本,则集群将为每个分区维护3个副本。其中一个分区称为主分区,其他两个分区称为备份分区,主分区对应的节点称为该分区中存储的键的主节点,否则称为备份节点。

当某些键的主分区对应的节点离开集群时,Ignite会触发分区映射交换(PME)过程,PME会将键的某个备份分区(如果已配置)标记为主分区。

备份分区提高了数据的可用性,在某些情况下还会提高读操作的速度,因为如果本地节点可用,Ignite会从备份分区中读取数据(这是可以禁用的默认行为,具体请参见缓存配置章节)。但是备份也会增加内存消耗或持久化存储的大小(如果启用)。

内存架构
Ignite内存架构通过可以同时在内存和磁盘上存储和处理数据及索引,得到了支持磁盘持久化的内存级性能。

- 多层存储的运行方式类似于操作系统(例如Linux)的虚拟内存。但是这两种类型架构之间的主要区别是,多层存储始终将磁盘视为数据的超集(如果启用了持久化),在故障或者重启后仍然可以保留数据,而传统的虚拟内存仅将磁盘作为交换扩展,一旦进程停止,数据就会被清除。
- 多层架构是一种基于固定大小页面的内存架构,这些页面存储在内存(Java堆外)的托管非堆区中,并按磁盘上的特定层次结构进行组织。

Ignite在内存和磁盘上都维护相同的二进制数据表示形式,这样在内存和磁盘之间移动数据时就不需要进行昂贵的序列化。

下图说明了多层存储架构:

内存段
每个数据区均以初始大小开始,并具有可以增长到的最大大小。该区域通过分配连续的内存段扩展到其最大大小。

内存段是从操作系统分配的物理内存的连续字节数组,该数组被拆分为固定大小的页面。该段中可以存在几种类型的页面,如下图所示。

数据页面
数据页面存储从应用端写入缓存的条目。
通常每个数据页面持有多个键值条目,以便尽可能高效地使用内存并避免内存碎片。将新条目添加到缓存后,Ignite会寻找一个适合整个键-值条目的最佳页面。
但是如果一个条目的总大小超过了DataStorageConfiguration.setPageSize(..)属性配置的页面大小,则该条目将占用多个数据页面。
提示
如果有许多缓存条目无法容纳在单个页面中,那么增加页面大小配置参数是有必要的。
如果在更新期间条目大小扩大并超过了其数据页面的剩余可用空间,则Ignite会搜索新的空间足够的数据页面,并将其移到那里。
配置数据区
Ignite使用数据区的概念来控制可用于缓存的内存数量,数据区是缓存数据存储在内存中的逻辑可扩展区域。可以控制数据区的初始值及其可以占用的最大值,除了大小之外,数据区还控制缓存的持久化配置。
Ignite有一个默认的数据区最多可占用该节点20%的内存,并且创建的所有缓存均位于该数据区中,但是也可以添加任意多个数据区,创建多个数据区的原因有:
- 可以通过不同数据区分别配置缓存对应的可用内存量;
- 持久化参数是按数据区配置的。如果要同时具有纯内存缓存和持久化缓存,则需要配置两个(或多个)具有不同持久化参数的数据区:一个用于纯内存缓存,一个用于持久化缓存;
- 部分内存参数,比如退出策略,是按照数据区进行配置的。
缓存预热策略
集群启动组网成功之后,Ignite本身并不需要对内存进行预热,应用就可以在其上执行计算和查询。但是对于需要低延迟的系统,还是希望在查询数据之前先将数据加载到内存中的。
当前,Ignite的预热策略是从索引开始,将数据加载到所有或者指定的数据区,直到用完可用空间为止。可以为所有的数据区进行配置(默认),也可以单独为某个数据区进行配置。
要预热所有数据区,需将配置参数LoadAllWarmUpStrategy传递给DataStorageConfiguration#setDefaultWarmUpConfiguration
退出策略
如果关闭了Ignite原生持久化,Ignite会在堆外内存中存储所有的缓存条目,当有新的数据注入,会进行页面的分配。如果达到了内存的限制,Ignite无法分配页面时,部分数据就必须从内存中删除以避免内存溢出,这个过程叫做退出,退出保证系统不会内存溢出,但是代价是内存数据丢失以及如果需要数据还需要重新加载。

退出策略用于下面的场景:
- 关闭原生持久化之后的堆外内存;
- 整合外部存储后的堆外内存;
- 堆内缓存;
- 近缓存(如果启用)。

如果开启了原生持久化,当Ignite无法分配新的页面时,会有一个叫做页面替换的简单过程来进行堆外内存的释放,不同点在于数据并没有丢失(因为其存储于持久化存储),因此不用担心数据丢失,而要关注效率。页面替换由Ignite自动处理,用户无法进行配置。

堆外内存退出
当内存使用超过预设限制时,Ignite使用预配置的算法之一来选择最适合退出的内存页面。然后将页面中的每个缓存条目从页面中删除,但是会保留被事务锁定的条目。因此,整个页面或大块页面都是空的,可以再次使用。

堆外内存的退出默认是关闭的,这意味着内存使用量会一直增长直到达到限值。如果要开启退出,需要在数据区配置中指定页面退出模式。注意堆外内存退出是数据区级的,如果没使用数据区,那么需要给默认的数据区显式地增加参数来配置退出。

默认情况下,当某个数据区的内存消耗量达到90%时,退出就开始了,如果希望更早或者更晚地发起退出,可以配置DataRegionConfiguration.setEvictionThreshold(...)参数。
Ignite支持两种页面选择算法:
- Random-LRU
- Random-2-LRU
Random-LRU
要启用Random-LRU退出算法,配置方式如下所示;

<bean class="org.apache.ignite.configuration.IgniteConfiguration">
    <!-- 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>
</bean>

<bean class="org.apache.ignite.configuration.IgniteConfiguration">
  <!-- Memory configuration. -->
  <property name="dataStorageConfiguration">
    <bean class="org.apache.ignite.configuration.DataStorageConfiguration">
      <property name="dataRegionConfigurations">
        <list>
          <!--
              Defining a data region that consumes 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>

Random-LRU算法工作方式如下:

  • 当一个数据区配置了内存策略时,就会分配一个堆外数组,它会跟踪每个数据页面的最后使用时间戳;
  • 当数据页面被访问时,跟踪数组的时间戳就会被更新;
  • 当到了退出页面时间时,算法会从跟踪数组中随机地选择5个索引,然后退出最近的时间戳对应的页面,如果部分索引指向非数据页面(索引或者系统页面),算法会选择其它的页面。
    Random-2-LRU
    Random-2-LRU退出算法是Random-LRU算法的抗扫描版,配置方式如下所示:
<bean class="org.apache.ignite.configuration.IgniteConfiguration">
  <!-- Memory configuration. -->
  <property name="dataStorageConfiguration">
    <bean class="org.apache.ignite.configuration.DataStorageConfiguration">
      <property name="dataRegionConfigurations">
        <list>
          <!--
              Defining a data region that consumes 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>

在Random-2-LRU算法中,每个数据页面会存储两个最近访问时间戳,退出时,算法会随机地从跟踪数组中选择5个索引值,然后两个最近时间戳中的最小值会被用来和另外4个候选页面中的最小值进行比较。

Random-2-LRU比Random-LRU要好,因为它解决了昙花一现的问题,即一个页面很少被访问,但是偶然地被访问了一次,然后就会被退出策略保护很长时间。

Ignite持久化

Ignite持久化,或者说原生持久化,是旨在提供持久化存储的一组功能。启用后,Ignite会将所有数据存储在磁盘上,并将尽可能多的数据加载到内存中进行处理。例如,如果有100个条目,而内存仅能存储20个,则所有100个都存储在磁盘上,而内存中仅缓存20个,以获得更好的性能。
如果关闭原生持久化并且不使用任何外部存储时,Ignite就是一个纯内存存储。
启用持久化后,每个服务端节点只会存储整个数据的一个子集,即只包含分配给该节点的分区(如果启用了备份,也包括备份分区)。
原生持久化基于以下特性:
- 在磁盘上存储数据分区;
- 预写日志;
- 检查点;
- 操作系统交换的使用。
启用持久化后,Ignite会将每个分区存储在磁盘上的单独文件中,分区文件的数据格式与保存在内存中的数据格式相同。如果启用了分区备份,则也会保存在磁盘上,除了数据分区,Ignite还存储索引和元数据。

启用持久化存储
原生持久化是配置在数据区上的。要启用持久化存储,需要在数据区配置中将persistenceEnabled属性设置为true,可以同时有纯内存数据区和持久化数据区。

以下是如何为默认数据区启用持久化存储的示例:

<bean class="org.apache.ignite.configuration.IgniteConfiguration">
    <property name="dataStorageConfiguration">
        <bean class="org.apache.ignite.configuration.DataStorageConfiguration">
            <property name="defaultDataRegionConfiguration">
                <bean class="org.apache.ignite.configuration.DataRegionConfiguration">
                    <property name="persistenceEnabled" value="true"/>
                </bean>
            </property>
        </bean>
    </property>
</bean>

配置持久化存储目录
启用持久化之后,节点就会在{IGNITE_WORK_DIR}/db目录中存储用户的数据、索引和WAL文件,该目录称为存储目录。通过配置DataStorageConfiguration的storagePath属性可以修改存储目录。

每个节点都会在存储目录下维护一个子目录树,来存储缓存数据、WAL文件和WAL存档文件。

子目录名 描述
{WORK_DIR}/db/{nodeId} 该目录中包括了缓存的数据和索引
{WORK_DIR}/db/wal/{nodeId} 该目录中包括了WAL文件
{WORK_DIR}/db/wal/archive/{nodeId} 该目录中包括了WAL存档文件

这里的nodeId要么是节点的唯一性ID(如果在节点配置中定义)要么是自动生成的节点ID,它用于确保节点目录的唯一性。如果多个节点共享同一工作目录,则它们将使用不同的子目录。

如果工作目录包含多个节点的持久化文件(存在多个具有不同nodeId的{nodeId}子目录),则该节点将选择第一个未使用的子目录。为了确保节点即使重启也始终使用固定的子目录,即指定数据分区,需要在节点配置中将IgniteConfiguration.setConsistentId设置为集群范围内的唯一值。

修改存储目录的代码如下所示:

<bean class="org.apache.ignite.configuration.IgniteConfiguration">
    <property name="dataStorageConfiguration">
        <bean class="org.apache.ignite.configuration.DataStorageConfiguration">
            <property name="defaultDataRegionConfiguration">
                <bean class="org.apache.ignite.configuration.DataRegionConfiguration">
                    <property name="persistenceEnabled" value="true"/>
                </bean>
            </property>
            <property name="storagePath" value="/opt/storage"/>
        </bean>
    </property>
</bean>

还可以将WAL和WAL存档路径指向存储目录之外的目录
预写日志
预写日志是节点上发生的所有数据修改操作(包括删除)的日志。在内存中更新页面时,更新不会直接写入分区文件,而是会附加到WAL的末尾。

预写日志的目的是为单个节点或整个集群的故障提供一个恢复机制。如果发生故障或重启,则可以依靠WAL的内容将集群恢复到最近成功提交的事务。

WAL由几个文件(称为活动段)和一个存档组成。活动段按顺序填充,然后循环覆盖。第一个段写满后,其内容将复制到WAL存档中。在复制第一段时,第二段会被视为激活的WAL文件,并接受来自应用端的所有更新,活动段默认有10个。
WAL模式
WAL模式有几种,每种模式对性能的影响方式不同,并提供不同的一致性保证:

WAL模式 描述 一致性保证
FSYNC 保证每个原子写或者事务性提交都会持久化到磁盘。 数据更新不会丢失,不管是任何的操作系统或者进程故障,甚至是电源故障。
LOG_ONLY 默认模式,对于每个原子写或者事务性提交,保证会刷新到操作系统的缓冲区缓存或者内存映射文件。默认会使用内存映射文件方式,并且可以通过将IGNITE_WAL_MMAP系统属性配置为false将其关闭。 如果仅仅是进程崩溃数据更新会保留。
BACKGROUND 如果打开了IGNITE_WAL_MMAP属性(默认),该模式的行为类似于LOG_ONLY模式,如果关闭了内存映射文件方式,变更会保持在节点的内部缓冲区,缓冲区刷新到磁盘的频率由walFlushFrequency参数定义。 如果打开了IGNITE_WAL_MMAP属性(默认),该模式提供了与LOG_ONLY模式一样的保证,否则如果进程故障或者其它的故障发生时,最近的数据更新可能丢失。
NONE WAL被禁用,只有在节点优雅地关闭时,变更才会正常持久化,使用Ignite#active(false)可以冻结集群然后停止节点。 可能出现数据丢失,如果节点在更新操作期间突然终止,则磁盘上存储的数据很可能出现不同步或损坏。

WAL存档
WAL存档用于保存故障后恢复节点所需的WAL段。存档中保存的段的数量应确保所有段的总大小不超过WAL存档的既定大小。
WAL存档的最大大小(在磁盘上占用的总空间)定义为检查点缓冲区大小的4倍,可以在配置中更改该值。
警告
将WAL存档大小配置为小于默认值可能影响性能,用于生产之前需要进行测试。

修改WAL段大小
在高负载情况下,默认的WAL段大小(64MB)可能效率不高,因为它会导致WAL过于频繁地在段之间切换,并且切换/轮转是一项昂贵的操作。更大的WAL段大小有助于提高高负载下的性能,但代价是增加WAL文件和WAL归档文件的总大小。
可以在数据存储配置中更改WAL段文件的大小,该值必须介于512KB和2GB之间。

<bean class="org.apache.ignite.configuration.IgniteConfiguration" id="ignite.cfg">

    <property name="dataStorageConfiguration">
        <bean class="org.apache.ignite.configuration.DataStorageConfiguration">

            <!-- set the size of wal segments to 128MB -->
            <property name="walSegmentSize" value="#{128 * 1024 * 1024}"/>

            <property name="defaultDataRegionConfiguration">
                <bean class="org.apache.ignite.configuration.DataRegionConfiguration">
                    <property name="persistenceEnabled" value="true"/>
                </bean>
            </property>

        </bean>
    </property>
</bean>

数据再平衡

当一个新节点加入集群时,部分分区会被分配至新的节点,以使整个集群的数据保持平均分布,这个过程称为数据再平衡。
如果现有节点永久离开集群,并且未配置备份,则会丢失此节点上存储的分区。配置备份后,丢失分区的备份副本之一将成为主分区,并开始再平衡过程。
警告
数据再平衡由基线拓扑的变化触发。在纯内存集群中,默认行为是在节点离开或加入集群时(基线拓扑自动更改)立即开始再平衡。在开启持久化的集群中,默认必须手动更改基线拓扑,或者在启用基线自动调整后可以自动更基线拓扑。
再平衡是缓存级的配置。
配置再平衡模式
Ignite支持同步和异步的再平衡,在同步模式中,再平衡结束前缓存的任何操作都会被阻塞。在异步模式中,再平衡过程以异步的模式执行,也可以为某个缓存禁用再平衡。
如果要修改再平衡模式,可以在缓存配置中配置如下的值:
- SYNC:同步再平衡模式,再平衡结束前缓存的任何操作都会被阻塞;
- ASYNC:异步再平衡模式,缓存直接可用,然后在后台会从其它节点加载所有必要的数据;
- NONE:该模式下不会发生再平衡,这意味着要么在访问数据时从持久化存储载入,要么数据被显式地填充。

<bean class="org.apache.ignite.configuration.IgniteConfiguration" id="ignite.cfg">
    <property name="cacheConfiguration">
        <list>
            <bean class="org.apache.ignite.configuration.CacheConfiguration">
                <property name="name" value="mycache"/>
                <!-- enable synchronous rebalance mode -->
                <property name="rebalanceMode" value="SYNC"/>
            </bean>
        </list>
    </property>
</bean>

配置再平衡线程池
默认一个节点只会有一个线程用于再平衡,这意味着在一个特定的时间点只有一个线程用于从一个节点到另一节点传输批量数据,或者处理来自远端的批量数据。
可以从系统线程池中拿到更多的线程数用于再平衡。每当节点需要将一批数据发送到远端节点或需要处理来自远端节点的一批数据时,都会从池中获取系统线程,批次处理完成后,该线程会被释放。

<bean class="org.apache.ignite.configuration.IgniteConfiguration" id="ignite.cfg">

    <property name="rebalanceThreadPoolSize" value="4"/>

    <property name="cacheConfiguration">
        <list>
            <bean class="org.apache.ignite.configuration.CacheConfiguration">
                <property name="name" value="mycache"/>
            </bean>
        </list>
    </property>
</bean>

警告
在内部,系统线程池广泛用于和缓存有关的所有操作(put,get等),SQL引擎和其它模块,因此将再平衡线程池设置为一个很大的值会显著提高再平衡的性能,但是会影响应用的吞吐量。
再平衡消息限流
当数据从一个节点传输到另一个节点时,整个数据集会被拆分为多个批次然后将每一个批次作为一个单独的消息进行发送,批次的大小和节点在消息之间的等待时间,都是可以配置的。

<bean class="org.apache.ignite.configuration.IgniteConfiguration" id="ignite.cfg">
    <property name="cacheConfiguration">
        <list>
            <bean class="org.apache.ignite.configuration.CacheConfiguration">
                <property name="name" value="mycache"/>
                <!-- Set batch size. -->
                <property name="rebalanceBatchSize" value="#{2 * 1024 * 1024}"/>
                <!-- Set throttle interval. -->
                <property name="rebalanceThrottle" value="100"/>
            </bean>
        </list>
    </property>
</bean>

Ignite分布式数据结构

队列和集合
Ignite除了提供了标准的键-值的类似于Map的存储以外,也提供了一个快速的分布式阻塞队列和分布式集合的实现。
IgniteQueue和IgniteSet分别是java.util.concurrent.BlockingQueue和java.util.Set接口的实现,也支持java.util.Collection接口的所有功能,这两个实现既可以以并置模式也可以以非并置模式创建。
并置和非并置模式
如果只打算创建包含大量数据的几个Queue或者Set,那么应该以非并置模式创建,这会确保每个集群节点存储每个队列或者集合大体均等的一部分。另一方面,如果打算持有很多的队列或者集合,而大小又相对较小(和整个缓存比),那么以并置模式创建它们是更合理的。这个模式下所有的队列和集合元素都会存储在同一个集群节点上,但是每个节点会被赋予均等的队列或者集合数量。

非并置模式只对分区缓存才有意义,也只有分区缓存才支持。
缓存队列和负载平衡
特定的元素会留在队列中直到被读取,以及没有两个节点会从队列中得到同一个元素。在Ignite中缓存队列会被用做一个备用的工作以及负载平衡的方式。

比如,可以简单地将一个计算,比如一个IgniteRunnable的实例加入队列,然后远程节点上有线程来调用IgniteQueue.take()方法,如果队列为空就会阻塞,如果take()方法返回一个作业,一个线程会处理它然后再次调用take()方法来获取下一个作业。通过这个方式,远程节点的线程只有在前一个作业完成之后才会开启下一个作业,因此创建一个理想的平衡系统,即每个节点只领取它能处理的作业数量,而不是更多。

安全

Ignite认证
通过将节点配置中的authenticationEnabled属性配置为true,可以开启Ignite的认证功能。但是开启认证需要至少一个数据区开启了持久化存储。

<bean class="org.apache.ignite.configuration.IgniteConfiguration">
    <property name="dataStorageConfiguration">
        <bean class="org.apache.ignite.configuration.DataStorageConfiguration">
            <property name="defaultDataRegionConfiguration">
                <bean class="org.apache.ignite.configuration.DataRegionConfiguration">
                    <property name="persistenceEnabled" value="true"/>
                </bean>
            </property>
        </bean>
    </property>

   <property name="authenticationEnabled" value="true"/>

</bean>

启动的第一个节点必须启用身份认证。启动时,Ignite会创建一个名为ignite和密码为ignite的账户,该账户可用于创建其他账户。
可以使用下面的命令管理用户:
- CREATE USER;
- ALTER USER;
- DROP USER。

命令
接入集群
如果执行脚本时没有连接参数,控制脚本会尝试连接运行在本机的节点(localhost:11211),如果希望接入运行在远程主机上的节点,需要指定连接参数:

--host HOST_OR_IP   节点的主机名或者IP地址    localhost
--port PORT 连接端口    11211
--user USER 用户名 
--password PASSWORD 密码

查看集群状态

control.sh --state

激活集群

control.sh --set-state ACTIVE
#或
control.sh --activate

查看集群节点

control.sh --baseline

输出中包含了当前的拓扑版本,基线中节点的唯一性ID列表,以及加入集群但是还没有添加到基线的节点列表。

Command [BASELINE] started
Arguments: --baseline
--------------------------------------------------------------------------------
Cluster state: active
Current topology version: 3

Current topology version: 3 (Coordinator: ConsistentId=dd3d3959-4fd6-4dc2-8199-bee213b34ff1, Order=1)

Baseline nodes:
    ConsistentId=7d79a1b5-cbbd-4ab5-9665-e8af0454f178, State=ONLINE, Order=2
    ConsistentId=dd3d3959-4fd6-4dc2-8199-bee213b34ff1, State=ONLINE, Order=1
--------------------------------------------------------------------------------
Number of baseline nodes: 2

Other nodes:
    ConsistentId=30e16660-49f8-4225-9122-c1b684723e97, Order=3
Number of other nodes: 1
Command [BASELINE] finished with code: 0
Control utility has completed execution at: 2019-12-24T16:53:08.392865
Execution time: 333 ms

添加节点,节点加入之后,会开启再平衡过程

control.sh --baseline add consistentId1,consistentId2,... [--yes]

删除节点。
只有离线的节点才能从基线拓扑中删除,需要先停止该节点然后才能执行remove命令。这个操作会开启再平衡过程,会在基线拓扑的剩余节点中重新分布数据。

control.sh --baseline remove consistentId1,consistentId2,... [--yes]

配置基线拓扑
可以通过提供节点的唯一性ID列表,或者通过指定基线拓扑版本来配置基线拓扑。

control.sh --baseline set consistentId1,consistentId2,... [--yes]

启用基线拓扑自动调整
基线拓扑自动调整是指在拓扑稳定一段时间后自动更新基线拓扑。
对于纯内存集群,自动调整是默认启用的,并且超时设置为0。这意味着基线拓扑在服务端节点加入或离开集群后立即更改。对于开启持久化的集群,自动调整默认是禁用的

control.sh --baseline auto_adjust enable timeout 30000

超时时间以毫秒计,在上一次JOIN/LEFT/FAIL事件之后经过给定的毫秒数时,会将基线设置为当前拓扑。每个新的JOIN/LEFT/FAIL事件都会重新启动超时倒计时。
使用以下命令可以禁用基线自动调整:

control.sh --baseline auto_adjust disable

事务管理
控制脚本可以拿到集群中正在执行的事务的信息,也可以取消某个事务。
下面的命令可以返回匹配过滤条件的事务列表(或者没有过滤条件返回所有的事务):

--xid XID   事务ID
--min-duration SECONDS  事务已执行的最小秒数
--min-size SIZE 事务大小最小值
--label LABEL   事务的标签,可以使用正则表达式
--servers   --clients
--nodes nodeId1,nodeId2…​   希望获得事务信息的节点唯一性ID列表
--limit NUMBER  将事务数限制为指定值
--order DURATION    SIZE

下面的命令可以取消事务:

control.sh --tx <transaction filter> --kill
#要取消已运行超过100秒的事务
control.sh --tx --min-duration 100 --kill

缓存状态监控
--cache list,其用于缓存的监控。该命令可以提供已部署缓存的列表及其关联/分布参数,还有在缓存组内的分布,另外还有一个命令用于查看已有的原子序列。

# Displays a list of all caches
control.sh|bat --cache list .

# Displays a list of caches whose names start with "account-".
control.sh|bat --cache list account-.*

# Displays info about cache group distribution for all caches.
control.sh|bat --cache list . --groups

# Displays info about cache group distribution for the caches whose names start with "account-".
control.sh|bat --cache list account-.* --groups

# Displays info about all atomic sequences.
control.sh|bat --cache list . --seq

# Displays info about the atomic sequnces whose names start with "counter-".
control.sh|bat --cache list counter-.* --seq

重置某个缓存丢失的分区

control.sh --cache reset_lost_partitions cacheName1,cacheName2...

一致性检查命令
可用于验证内部数据的一致性。
首先,这些命令可用于调试和故障排除场景,尤其是在开发高峰期。
其次,如果怀疑查询(例如SQL查询等)返回的结果集不完整或错误,则这些命令可以验证数据中是否存在不一致。
最后,一致性检查命令可以用作常规集群运行状况检测的一部分。
下面为更具体的使用场景:
验证分区校验和
idle_verify命令将主分区的哈希与备份分区的哈希进行比较,并报告差异。差异可能是更新操作期间节点故障或非正常关闭导致。如果检测到任何不一致之处,建议删除不正确的分区。

# Checks partitions of all caches that their partitions actually contain same data.
control.sh|bat --cache idle_verify
# Checks partitions of specific caches that their partitions actually contain same data.
control.sh|bat --cache idle_verify cache1,cache2,cache3

如果索引引用了不存在的条目(或部分条目未被索引),会输出错误,如下所示

PartitionKey [grpId=-528791027, grpName=persons-cache-vi, partId=0] ValidateIndexesPartitionResult [updateCntr=313, size=313, isPrimary=true, consistentId=bltTest0]
IndexValidationIssue [key=0, cacheName=persons-cache-vi, idxName=_key_PK], class org.apache.ignite.IgniteCheckedException: Key is present in CacheDataTree, but can't be found in SQL index.
IndexValidationIssue [key=0, cacheName=persons-cache-vi, idxName=PERSON_ORGID_ASC_IDX], class org.apache.ignite.IgniteCheckedException: Key is present in CacheDataTree, but can't be found in SQL index.
validate_indexes has finished with errors (listed above).

检查SQL索引内联值
运行中的Ignite集群在各个节点上可能有不同的SQL索引内联值,例如各个节点上IGNITE_MAX_INDEX_PAYLOAD_SIZE的属性值不同等。索引内联值之间的差异可能导致性能下降。
check_index_inline_sizes命令会验证所有节点上给定缓存的索引内联值。在节点加入时会始终检查二级索引的内联值,如有不同,则会在日志中输出警告信息。
使用以下命令可以检查各个节点上二级索引内联值是否相同:

control.sh|bat --cache check_index_inline_sizes

如果内联值不同,控制台输出如下所示:

Control utility [ver. 2.10.0]
2021 Copyright(C) Apache Software Foundation
User: test
Time: 2021-04-27T16:13:21.213
Command [CACHE] started
Arguments: --cache check_index_inline_sizes --yes

Found 4 secondary indexes.
3 index(es) have different effective inline size on nodes. It can lead to
performance degradation in SQL queries.
Index(es):
  Full index name: PUBLIC#TEST_TABLE#L_IDX nodes:
[ca1d23ae-89d4-4e8d-ae12-6c68f3900000] inline size: 1, nodes:
[8327bbd1-df08-4b97-8721-de95e363e745] inline size: 2
  Full index name: PUBLIC#TEST_TABLE#S1_IDX nodes:
[ca1d23ae-89d4-4e8d-ae12-6c68f3900000] inline size: 1, nodes:
[8327bbd1-df08-4b97-8721-de95e363e745] inline size: 2
  Full index name: PUBLIC#TEST_TABLE#I_IDX nodes:
[ca1d23ae-89d4-4e8d-ae12-6c68f3900000] inline size: 1, nodes:
[8327bbd1-df08-4b97-8721-de95e363e745] inline size: 2

系统视图命令
该命令会输出由参数列表指定的系统视图的内容,使用--node-id参数,可以拿到某个节点的指标,如果未指定该参数,Ignite会随机选择一个节点。

control.sh --system-view views

Visor终端

Visor命令行接口(CMD)是一个用于Ignite集群监控的命令行工具,它提供有关集群节点、缓存和计算任务的基本统计信息,还可以通过启动或停止节点来管理集群的大小。
Ignite通过IGNITE_HOME/bin/ignitevisorcmd.{sh|bat}脚本来启动Visor终端,要将Visor接入集群,需要使用open命令。
Visor支持下面的命令,要获得某个命令完整的信息,可以输入help "cmd"或者? "cmd"。

命令 描述
ack 所有远程节点的Ack参数
alert 提示用户定义的事件
cache 输出缓存的统计数据,清理缓存,从缓存输出所有条目的列表
close 将visor从网格断开
config 输出节点的配置
deploy 将文件或者文件夹复制到远程主机
disco 输出拓扑变更日志
events 从一个节点输出事件
gc 在远程节点运行GC
help 输出Visor控制台帮助
kill 杀掉或者重启节点
log 启动或者停止网格范围的事件日志
mclear 清除Visor控制台内存变量
mget 获取Visor控制台内存变量
mlist 输出Visor控制台内存变量
node 输出节点统计数据
open 将Visor接入网格
ping ping节点
quit 退出Visor控制台
start 在远程主机启动或者重启节点
status 输出Visor控制台状态
tasks 输出任务执行统计数据
top 输出当前的拓扑
vvm 打开节点的VisualVM

SQLLine

Ignite提供了一个SQLLine工具,它是一个接入关系数据库然后执行SQL命令的基于命令行的工具,本章节会描述如何用SQLLine接入Ignite集群,以及Ignite支持的各种SQLLine命令。

./sqlline.sh --verbose=true -u jdbc:ignite:thin://127.0.0.1

如开启认证

./sqlline.sh --verbose=true -u "jdbc:ignite:thin://127.0.0.1:10800;user=ignite;password=ignite"

SQLLine命令列表

命令 描述
!all 在当前的所有连接中执行指定的SQL
!batch 开始执行一批SQL语句
!brief 启动简易输出模式
!closeall 关闭所有目前已打开的连接
!columns 显示表中的列
!connect 接入数据库
!dbinfo 列出当前连接的元数据信息
!dropall 删除数据库中的所有表
!go 转换到另一个活动连接
!help 显示帮助信息
!history 显示命令历史
!indexes 显示表的索引
!list 显示所有的活动连接
!manual 显示SQLLine手册
!metadata 调用任意的元数据命令
!nickname 为连接命名(更新命令提示)
!outputformat 改变显示SQL结果的方法
!primarykeys 显示表的主键列
!properties 使用指定的属性文件接入数据库
!quit 退出SQLLine
!reconnect 重新连接当前的数据库
!record 开始记录SQL命令的所有输出
!run 执行一个命令脚本
!script 将已执行的命令保存到一个文件
!sql 在数据库上执行一个SQL
!tables 列出数据库中的所有表
!verbose 启动详细输出模式

SQLLine创建表

CREATE TABLE City (id LONG PRIMARY KEY, name VARCHAR) WITH "template=replicated";
CREATE TABLE Person (id LONG, name VARCHAR, city_id LONG, PRIMARY KEY (id, city_id))WITH "backups=1, affinityKey=city_id";
#查看表
!tables
+-----------+--------------+--------------+-------------+-------------+
| TABLE_CAT | TABLE_SCHEM  |  TABLE_NAME  | TABLE_TYPE  | REMARKS     |
+-----------+--------------+--------------+-------------+-------------+
|           | PUBLIC       | CITY         | TABLE       |             |
|           | PUBLIC       | PERSON       | TABLE       |             |
+-----------+--------------+--------------+-------------+-------------+

定义索引

CREATE INDEX idx_city_name ON City (name);
CREATE INDEX idx_person_name ON Person (name);
#查看索引
+-----------+--------------+--------------+-------------+-----------------+
| TABLE_CAT | TABLE_SCHEM  |  TABLE_NAME  | NON_UNIQUE  | INDEX_QUALIFIER |
+-----------+--------------+--------------+-------------+-----------------+
|           | PUBLIC       | CITY         | true        |                 |
|           | PUBLIC       | PERSON       | true        |                 |
+-----------+--------------+--------------+-------------+-----------------+

性能和故障排除

常规性能提示
Ignite作为一个分布式存储和计算平台,是需要做出优化的,在深入更高级的优化技术之前,需要了解如下的基本要点:
- Ignite是为分布式计算场景设计和优化的,因此建议在多节点集群而不是单节点上部署和测试;
- Ignite可以水平扩展也可以垂直扩展,因此建议将本地主机上的所有可用CPU和RAM资源分配给Ignite节点,建议每台主机一个节点;
- 如果将Ignite部署在虚拟机或云环境中,则将Ignite节点固定到单个主机是理想的(但并非严格要求),这提供了两个好处:
- 避免了Ignite节点会与其他应用竞争主机资源的问题,这可能会导致Ignite节点上的性能波动;
- 确保高可用性。如果主机发生故障,并且该主机部署有两个或多个Ignite服务端节点,则可能导致数据丢失。
- 如果资源允许,请将整个数据集存储在内存中。即使Ignite可以存储并使用磁盘上的数据,它的架构还是内存优先的。换句话说,在内存中缓存的数据越多,性能就越快;
- 仅将数据放入内存还不能期望性能可以提高一个数量级,还需要调整数据模型和现有应用(如果有)。在数据建模阶段,应使用关联并置概念来进行正确的数据分发。如果数据正确地实现了并置,则可以运行大规模带有关联的SQL查询,并获得显著的性能表现;
- 调整数据再平衡设置,以确保在集群拓扑更改时再平衡可以更快地完成。
交换参数调优
当内存的使用达到阈值时,操作系统就会开始进行从内存到磁盘的页面交换,交换会显著影响Ignite节点进程的性能,这个问题可以通过调整操作系统参数来避免。如果使用的是Linux,最佳选项是或者降低vm.swappiness的值到10,或者如果开启了原生持久化,也可以将其配置为0。

sysctl –w vm.swappiness=0

此参数值也可以调整GC暂停时间。例如如果GC日志显示low user time, high system time, long GC pause这样的记录,这可能是由于Java堆页面被换入和换出所致。要解决此问题,也需要使用上面的swappiness设置。

操作系统和应用共享内存
操作系统、Ignite和其他应用之间会共享整个主机的内存。通常来说,如果以纯内存模式部署Ignite集群(禁用原生持久化),则不应为Ignite节点分配超过90%的内存量。
另一方面,如果使用了原生持久化,则操作系统需要额外的内存用于其页面缓存,以便以最佳方式将数据同步到磁盘。如果未禁用页面缓存,则不应将超过70%的内存分配给Ignite。
除此之外,由于使用原生持久化可能会导致较高的页面缓存利用率,因此kswapd守护进程可能无法跟上页面回收(页面缓存在后台使用)。因此由于直接页面回收,可能导致高延迟,并导致长GC暂停。
要解决Linux上页面内存回收造成的影响,需要使用/proc/sys/vm/extra_free_kbytes在wmark_min和wmark_low之间添加额外的字节:

sysctl -w vm.extra_free_kbytes=1240000

Java堆和GC调优
虽然Ignite将数据保存在Java垃圾收集器看不到的堆外数据区中,但Java堆仍用于由应用生成的对象。例如每当执行SQL查询时,查询将访问堆外内存中存储的数据和索引,在应用读取结果集期间,此类查询的结果集会保留在Java堆中。因此根据吞吐量和操作类型,仍然可以大量使用Java堆,这也需要针对工作负载进行JVM和GC相关的调优。
常规GC配置
下面是一些应用的JVM配置集示例,这些应用会在服务端节点上大量使用Java堆,从而触发长时间或频繁的短期GC暂停。
对于JDK 1.8+环境,应使用G1垃圾收集器,如果10GB的堆可以满足服务端节点的需要,则以下配置是个好的起点:

-server
-Xms10g
-Xmx10g
-XX:+AlwaysPreTouch
-XX:+UseG1GC
-XX:+ScavengeBeforeFullGC
-XX:+DisableExplicitGC

如果G1不适用,则可以考虑使用CMS收集器,并以下面的设置为起点。注意10GB的堆空间仅为示例,也许较小的堆空间即可满足业务需要:

-server
-Xms10g
-Xmx10g
-XX:+AlwaysPreTouch
-XX:+UseParNewGC
-XX:+UseConcMarkSweepGC
-XX:+CMSClassUnloadingEnabled
-XX:+CMSPermGenSweepingEnabled
-XX:+ScavengeBeforeFullGC
-XX:+CMSScavengeBeforeRemark
-XX:+DisableExplicitGC

提示
如果使用了Ignite原生持久化,建议将MaxDirectMemorySizeJVM参数设置为walSegmentSize * 4,对于默认的WAL设置,该值等于256MB。
高级内存调优
在Linux和Unix环境中,由于I/O或内核特定参数配置导致的内存不足,应用可能面临长时间的GC暂停或性能下降。本章节会介绍有关如何修改内核参数配置以克服长时间GC暂停的一些准则。
如果GC日志显示,low user time, high system time, long GC pause则很可能是 内存限制触发了交换或扫描可用内存空间:
- 检查并调整交换设置;
- 启动时添加-XX:+AlwaysPreTouchJVM参数;
- 禁用NUMA区域回收优化:

sysctl -w vm.zone_reclaim_mode=0

关闭透明大页:

echo never > /sys/kernel/mm/redhat_transparent_hugepage/enabled
echo never > /sys/kernel/mm/redhat_transparent_hugepage/defrag

高级I/O调优
如果GC日志显示low user time, low system time, long GC pause,则GC线程可能在内核空间上花费了太多时间,被各种I/O活动所阻塞,这可能是由日志提交、gzip或日志轮转过程等引起的。
作为解决方案,可以尝试将页面刷新间隔从默认的30秒更改为5秒:

sysctl -w vm.dirty_writeback_centisecs=500
sysctl -w vm.dirty_expire_centisecs=500

持久化调优

调整页面大小
Ignite的页面大小(DataStorageConfiguration.pageSize)不要小于存储设备(SSD、HDD、闪存等)和操作系统缓存页面的大小的较小者,默认值是4KB。

<bean class="org.apache.ignite.configuration.IgniteConfiguration">
    <property name="dataStorageConfiguration">
        <bean class="org.apache.ignite.configuration.DataStorageConfiguration">

            <!-- Set the page size to 8 KB -->
            <property name="pageSize" value="#{8 * 1024}"/>
        </bean>
    </property>
</bean>

WAL单独存储
考虑为Ignite原生持久化的数据文件以及预写日志(WAL)使用单独的磁盘设备,Ignite会主动地写入数据文件以及WAL文件。
下面显示如何为数据存储、WAL和WAL存档配置单独的路径:

<bean class="org.apache.ignite.configuration.IgniteConfiguration">
    <property name="dataStorageConfiguration">
        <bean class="org.apache.ignite.configuration.DataStorageConfiguration">

            <!--
                Sets a path to the root directory where data and indexes are
                to be persisted. It's assumed the directory is on a separated SSD.
            -->
            <property name="storagePath" value="/opt/persistence"/>
            <property name="walPath" value="/opt/wal"/>
            <property name="walArchivePath" value="/opt/wal-archive"/>
        </bean>
    </property>
</bean>

增加WAL段大小
WAL段的默认大小(64MB)在高负载情况下可能是低效的,因为它导致WAL在段之间频繁切换,并且切换是有点昂贵的操作。将段大小设置为较大的值(最多2GB)有助于减少切换操作的次数,不过代价是这将增加预写日志的占用空间。
调整WAL模式
考虑其它WAL模式替代默认模式。每种模式在节点故障时提供不同程度的可靠性,并且可靠性与速度成反比,即,WAL模式越可靠,则速度越慢。因此,如果具体业务不需要高可靠性,那么可以切换到可靠性较低的模式。
页面写入限流
Ignite会定期地启动检查点进程,以在内存和磁盘间同步脏页面。脏页是指页面已经在内存中更新,但是还未写入对应的分区文件(更新只是添加到了WAL)。这个进程在后台进行,对应用的逻辑没有影响。
但是,如果由检查点进程调度的一个脏页面,在写入磁盘前被更新,它之前的状态会被复制进某个区域,叫做检查点缓冲区。如果这个缓冲区溢出,那么在检查点处理过程中,Ignite会停止所有的更新。因此,在检查点周期完成之前写入性能可能降为0,如下图所示:

当检查点处理正在进行中时,如果脏页面数达到阈值,同样的情况也会发生,这会使Ignite强制安排一个新的检查点执行,并停止所有的更新操作直到第一个检查点周期执行完成。
当磁盘较慢或者更新过于频繁时,这两种情况都会发生,要减少或者防止这样的性能下降,可以考虑启用页面写入限流算法。这个算法会在检查点缓冲区填充过快或者脏页面占比过高时,将更新操作的性能降低到磁盘的速度。
开启页面写入限流:

<bean class="org.apache.ignite.configuration.IgniteConfiguration">
    <property name="dataStorageConfiguration">
        <bean class="org.apache.ignite.configuration.DataStorageConfiguration">

            <property name="writeThrottlingEnabled" value="true"/>

        </bean>
    </property>
</bean>

调整检查点缓冲区大小
缓冲区的默认大小是根据数据区大小计算的。

数据区大小 默认检查点缓冲区大小
< 1GB MIN (256 MB, 数据区大小)
1GB ~ 8GB 数据区大小/4
> 8GB 2GB

默认的缓冲区大小并没有为写密集型应用进行优化,因为在大小接近标称值时,页面写入限流算法会降低写入的性能,因此在正在进行检查点处理时,可以考虑增加DataRegionConfiguration.checkpointPageBufferSize,并且开启写入限流来阻止性能的下降:

<bean class="org.apache.ignite.configuration.IgniteConfiguration">
    <property name="dataStorageConfiguration">
        <bean class="org.apache.ignite.configuration.DataStorageConfiguration">

            <property name="writeThrottlingEnabled" value="true"/>

            <property name="defaultDataRegionConfiguration">
                <bean class="org.apache.ignite.configuration.DataRegionConfiguration">
                    <!-- Enabling persistence. -->
                    <property name="persistenceEnabled" value="true"/>
                    <!-- Increasing the buffer size to 1 GB. -->
                    <property name="checkpointPageBufferSize" value="#{1024L * 1024 * 1024}"/>
                </bean>
            </property>

        </bean>
    </property>
</bean>

在上例中,默认内存区的检查点缓冲区大小配置为1GB。
启用直接IO
通常当应用访问磁盘上的数据时,操作系统拿到数据后会将其写入一个文件缓冲区缓存,写操作也是同样,操作系统首先将数据写入缓存,然后才会传输到磁盘,要消除这个过程,可以打开直接IO,这时数据会忽略文件缓冲区缓存,直接从磁盘进行读写。
Ignite中的直接I/O插件用于加速检查点进程,它的作用是将内存中的脏页面写入磁盘,建议将直接IO插件用于写密集型环境中。
提示
注意,无法专门为WAL文件开启直接I/O,但是开启直接I/O可以为WAL文件带来一点好处,就是WAL数据不会在操作系统的缓冲区缓存中存储过长时间,它会在下一次页面缓存扫描中被刷新(依赖于WAL模式),然后从页面缓存中删除。

要启用直接I/O插件,需要将二进制包的libs/optional/ignite-direct-io文件夹上移一层至libs/optional/ignite-direct-io文件夹,或者添加该插件的Maven依赖,
使用IGNITE_DIRECT_IO_ENABLED系统属性,可以在运行时启用/禁用该插件。

故障排除

调试工具:
./control.sh
重启后持久化文件丢失
在某些系统上,Ignite持久化文件的默认位置可能在temp文件夹下。这可能导致以下情况:每当重启节点进程时,操作系统都会删除持久化文件。为了避免这种情况:
确保Ignite启用WARN日志记录级别。如果将持久化文件写入临时目录,则会看到警告;
使用DataStorageConfigurationAPI,例如setStoragePath(…​)、setWalPath(…​)和setWalArchivePath(…​)更改持久化文件的位置。
字段类型变更后集群无法启动
在开发应用时,可能需要修改字段的类型。举例来说,假设有对象A的字段A.range为int类型,然后将A.range类型更改为long,执行此操作后,集群或应用将无法重启,因为Ignite不支持字段/列类型的更改。
这时,如果仍处于开发阶段,则需要进入文件系统并删除以下目录:位于Ignite工作目录的marshaller/、db/和wal/(如果调整了位置,db和wal可能位于其他地方)。
但是,如果在生产环境,则不要更改字段类型,而是在对象模型中添加一个不同名的新字段,并删除旧字段,此操作是完全支持的。同时,ALTER TABLE命令可用于在运行时添加新列或删除现有列
GC问题调试
堆转储
如果JVM抛出了OutOfMemoryException异常,则下次发生异常时会自动转储堆。这会有助于了解此异常的根本原因,并可以更深入地了解发生故障时的堆状态。

-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/path/to/heapdump
-XX:OnOutOfMemoryError=“kill -9 %p”
-XX:+ExitOnOutOfMemoryError

详细GC日志
为了捕获有关GC相关活动的详细信息,确认已在集群节点的JVM设置中配置了以下参数:

-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
-XX:+PrintGCDateStamps
-XX:+UseGCLogFileRotation
-XX:NumberOfGCLogFiles=10
-XX:GCLogFileSize=100M
-Xloggc:/path/to/gc/logs/log.txt

此外,对于G1收集器,需配置下面的属性。它提供了许多有意未包含在-XX:+PrintGCDetails参数中的其他细节信息:

-XX:+PrintAdaptiveSizePolicy

使用Flight Recorder进行性能分析
如果需要调试性能或内存问题,则可以使用Java Flight Recorder持续收集底层的运行时统计信息,从而可以进行事后分析。要启用Java Flight Recorder,请使用以下JVM参数:

-XX:+UnlockCommercialFeatures
-XX:+FlightRecorder
-XX:+UnlockDiagnosticVMOptions
-XX:+DebugNonSafepoints

要在固定的Ignite节点上开始记录状态,请使用以下命令:

jcmd <PID> JFR.start name=<recordcing_name> duration=60s filename=/var/recording/recording.jfr settings=profile

JVM暂停
有时可能会看到有关JVM暂停时间太长的警告消息,例如可能在批量加载期间发生这个问题。
调整IGNITE_JVM_PAUSE_DETECTOR_THRESHOLD超时设置可以增加处理时间以等待完成而不产生警告。可以通过环境变量设置该阈值,或将其作为JVM参数(-DIGNITE_JVM_PAUSE_DETECTOR_THRESHOLD=5000)或作为ignite.sh的参数(-J-DIGNITE_JVM_PAUSE_DETECTOR_THRESHOLD=5000)。
该值以毫秒为单位。

处理异常

处理Ignite异常
下表描述了Ignite API支持的异常以及可以用来处理这些异常的操作。可以查看javadoc中的throws子句,查看是否存在已检查异常。

异常 描述 要采取的动作 运行时异常
CacheInvalidStateException 当在分区发生丢失的缓存上执行操作时会抛出此异常。根据缓存配置的分区丢失策略,读/写操作都可能抛出此异常,具体请参见分区丢失策略章节的介绍。 重置丢失的分区,通过将触发分区丢失的节点恢复到集群可以恢复数据。
IgniteException 此异常表示网格中存在错误。 操作失败,从方法退出。
IgniteClientDisconnectedException 当客户端节点与集群断开连接时,Ignite API(缓存操作、计算API和数据结构操作)会抛出此异常。 Future中等待并重试。
IgniteAuthenticationException 当节点身份验证失败或安全身份验证失败时,会抛出此异常。 操作失败,从方法退出。
IgniteClientException 缓存操作会抛出此异常。 根据异常消息确定下一步的动作。
IgniteDeploymentException 当Ignite API(计算网格相关)未能在节点上部署作业或任务时,会抛出此异常。 操作失败,从方法退出。
IgniteInterruptedException 此异常用于将标准InterruptedException包装为IgniteException 清除中断标志后重试。
IgniteSpiException SPI引发的异常,如CollisionSpiLoadBalancingSpiTcpDiscoveryIpFinderFailoverSpiUriDeploymentSpi等。 操作失败,从方法退出。
IgniteSQLException SQL查询处理失败会抛出此异常,该异常会包含相关规范定义的错误代码。 操作失败,从方法退出。
IgniteAccessControlException 认证/授权失败时会抛出此异常。 操作失败,从方法退出。
IgniteCacheRestartingException 如果缓存正在重启,Ignite的缓存API会抛出此异常。 Future中等待并重试。
IgniteFutureTimeoutException Future的计算超时时,会抛出此异常。 要么增加超时限制要么方法退出。
IgniteFutureCancelledException Future的计算因为被取消而无法获得结果时,会抛出此异常。 可进行重试。
IgniteIllegalStateException 此异常表示Ignite实例对于请求的操作处于无效状态。 操作失败,从方法退出。
IgniteNeedReconnectException 此异常显示节点应尝试重新连接到集群。 可进行重试。
IgniteDataIntegrityViolationException 如果发现数据完整性冲突,会抛出此异常。 操作失败,从方法退出。
IgniteOutOfMemoryException 系统没有足够内存处理Ignite操作(缓存操作)时,会抛出此异常。 操作失败,从方法退出。
IgniteTxOptimisticCheckedException 当事务以乐观方式失败时,会抛出此异常。 可进行重试
IgniteTxRollbackCheckedException 当事务自动回滚时,会抛出此异常。 可进行重试。
IgniteTxTimeoutCheckedException 当事务超时时,会抛出此异常。 可进行重试。
ClusterTopologyException 当集群拓扑发生错误(比如节点故障)时会抛出此异常(针对计算和事件API)。 Future中等待并重试。

严重故障处理

Ignite是一个强大且容错的系统。但是在现实中总会出现一些无法预测的问题,这些问题会影响单个节点甚至整个集群的状态。可以在运行时检测到此类问题,并使用预配置的严重故障处理器进行相应的处理。
严重故障
以下故障被视为严重故障:
- 系统级严重错误(OutOfMemoryError);
- 意外的系统工作进程终止(未处理的异常);
- 系统工作进程被终止;
- 集群脑裂。
系统级严重错误会导致系统无法操作,比如:
- 文件I/O错误:通常IOException由文件读/写抛出,通常在开启持久化时会发生(比如磁盘空间不足或者设备故障),或者在内存模式中,Ignite会使用磁盘来存储部分元数据(比如达到了文件描述符限制或者文件访问被禁止);
- 内存溢出错误:Ignite内存管理系统无法分配更多的空间(IgniteOutOfMemoryException);
- 内存溢出错误:集群节点堆溢出(OutOfMemoryError);
故障处理
Ignite检测到严重的错误后,会通过预配置的故障处理器进行处理,配置方法如下:

<bean class="org.apache.ignite.configuration.IgniteConfiguration">
    <property name="failureHandler">
        <bean class="org.apache.ignite.failure.StopNodeFailureHandler"/>
    </property>
</bean>
描述
NoOpFailureHandler 忽略任何故障,用于测试和调试环境。
RestartProcessFailureHandler 只能用于ignite.(sh|bat)的特定实现,进程必须使用Ignition.restart(true)调用进行终止。
StopNodeFailureHandler 出现严重错误时,使用Ignition.stop(true)或者Ignition.stop(nodeName, true)调用停止节点。
StopNodeOrHaltFailureHandler 默认处理器,它会试图停止节点,如果无法停止,那么它会试图终止JVM进程。

关键工作进程健康检查
Ignite内部有一些工作进程,它们对集群的正常运行非常重要。如果它们中的一个终止了,Ignite节点可能变为失效状态。
下面的系统级工作进程为关键进程:
- 发现进程:发现事件处理;
- TCP通信进程:节点间的点对点通信;
- 交换进程:分区映射交换;
- 系统级平行线程池进程;
- 数据流处理器平行线程池进程;
- 超时进程:超时处理;
- 检查点线程:Ignite持久化的检查点;
- WAL进程:预写日志、段存档和压缩;
- 过期进程:基于TTL的过期;
- NIO进程:基础拓扑操作;
Ignite有一个内部机制用于验证关键进程是否正常,会定期检查每个进程是否在线,并更新其心跳时间戳。如果某个进程不在线并正在更新,则该进程会被视为阻塞,然后Ignite会在日志文件中输出信息。通过IgniteConfiguration.systemWorkerBlockedTimeout属性可以配置该不在线的时间段。
尽管Ignite认为无响应的系统工作进程是严重错误,但除了将消息输出到日志文件之外,它不会自动处理这种情况。如果要为所有类型的无响应系统工作进程启用固定的故障处理器,需清除处理器的ignoredFailureTypes属性,如下所示:

<bean class="org.apache.ignite.configuration.IgniteConfiguration">

    <property name="systemWorkerBlockedTimeout" value="#{60 * 60 * 1000}"/>

    <property name="failureHandler">
        <bean class="org.apache.ignite.failure.StopNodeFailureHandler">

          <!-- Enable this handler to react to unresponsive critical workers occasions. -->
          <property name="ignoredFailureTypes">
            <list>
            </list>
          </property>

      </bean>

    </property>
</bean>
THE END
分享
二维码
< <上一篇
下一篇>>
文章目录
关闭