[关闭]
@liyuj 2017-05-18T23:32:45.000000Z 字数 19463 阅读 10720

Apache-Ignite-2.0.0-中文开发手册

1.基本概念

1.1.Ignite是什么

Apache Ignite内存数据组织是高性能的、集成化的以及分布式的内存平台,他可以实时地在大数据集中执行事务和计算,和传统的基于磁盘或者闪存的技术相比,性能有数量级的提升。

1.1.1.特性一览

可以将Ignite视为一个独立的、易于集成的内存组件的集合,目的是改进应用程序的性能和可扩展性,部分组件包括:

除了Spark和Hadoop,Ignite也集成了其他的很多技术和产品,这样做的目的是简化Ignite和应用或者服务使用的其他技术的耦合,以便平滑地过渡到Ignite或者有助于将Ignite嵌入已有的系统。

1.2.入门

这部分帮助你开始一个新的Ignite程序,你会发现他瞬间就可以跑起来。

1.2.1.准备

Apache Ignite官方在如下环境中进行的测试:

1.2.2.安装

下面是安装Apache Ignite的简要步骤:

从源代码构建
如果你下载的是源代码包,可以用如下命令构建:

  1. # Unpack the source package
  2. $ unzip -q apache-ignite-{version}-src.zip
  3. $ cd apache-ignite-{version}-src
  4. # Build In-Memory Data Fabric release (without LGPL dependencies)
  5. $ mvn clean package -DskipTests
  6. # Build In-Memory Data Fabric release (with LGPL dependencies)
  7. $ mvn clean package -DskipTests -Prelease,lgpl
  8. # Build In-Memory Hadoop Accelerator release
  9. # (optionally specify version of hadoop to use)
  10. $ mvn clean package -DskipTests -Dignite.edition=hadoop [-Dhadoop.version=X.X.X]

1.2.3.从命令行启动

一个Ignite节点可以从命令行通过默认的配置或者传入外部配置文件的方式启动。可以启动很多很多的节点然后他们会自动地发现对方。
通过默认配置
要启动一个基于默认配置的网格节点,打开命令行然后切换到IGNITE_HOME(安装文件夹),然后输入如下命令:

  1. $ bin/ignite.sh

然后会看到输出大体是如下的样子:

  1. [02:49:12] Ignite node started OK (id=ab5d18a6)
  2. [02:49:12] Topology snapshot [ver=1, nodes=1, CPUs=8, heap=1.0GB]

ignite.sh启动ignite节点会使用默认的配置文件:config/default-config.xml
传递配置文件
要从命令行显式地传递一个配置文件,只需要在安装文件夹路径下输入ignite.sh <配置文件路径>,比如:

  1. $ bin/ignite.sh examples/config/example-cache.xml

配置文件的路径既可以是绝对路径,也可以是相对于IGNITE_HOME的相对路径,也可以是相对于类路径的META-INF文件夹。

交互式模式
要在一个交互模式传递配置文件,可以加上-i参数,像这样:ignite.sh -i

1.2.4.从Maven获得

在项目里使用Apache Ignite的另一个方式是使用Maven2依赖管理。
Ignite只需要一个ignite-core强依赖,通常还需要添加ignite-spring,来做基于spring的XML配置,还有ignite-indexing,来做SQL查询。
确保将${ignite-version}替换为实际的版本号。

  1. <dependency>
  2. <groupId>org.apache.ignite</groupId>
  3. <artifactId>ignite-core</artifactId>
  4. <version>${ignite.version}</version>
  5. </dependency>
  6. <dependency>
  7. <groupId>org.apache.ignite</groupId>
  8. <artifactId>ignite-spring</artifactId>
  9. <version>${ignite.version}</version>
  10. </dependency>
  11. <dependency>
  12. <groupId>org.apache.ignite</groupId>
  13. <artifactId>ignite-indexing</artifactId>
  14. <version>${ignite.version}</version>
  15. </dependency>

Maven设置
关于如何包含个别的ignite maven模块的更多信息,可以参考1.3.Maven设置章节。

1.2.5.第一个计算应用

我们写第一个计算应用,他会计算一句话中非空白字符的字符数量。作为一个例子,我们首先将一句话分割为多个单词,然后通过每个计算作业来计算每一个独立单词中的字符数量。最后,我们将从每个作业获得的结果简单相加来获得整个的数量。
Java8:

  1. try (Ignite ignite = Ignition.start("examples/config/example-ignite.xml")) {
  2. Collection<IgniteCallable<Integer>> calls = new ArrayList<>();
  3. // Iterate through all the words in the sentence and create Callable jobs.
  4. for (final String word : "Count characters using callable".split(" "))
  5. calls.add(word::length);
  6. // Execute collection of Callables on the grid.
  7. Collection<Integer> res = ignite.compute().call(calls);
  8. // Add up all the results.
  9. int sum = res.stream().mapToInt(Integer::intValue).sum();
  10. System.out.println("Total number of characters is '" + sum + "'.");
  11. }

Java7:

  1. try (Ignite ignite = Ignition.start("examples/config/example-ignite.xml")) {
  2. Collection<IgniteCallable<Integer>> calls = new ArrayList<>();
  3. // Iterate through all the words in the sentence and create Callable jobs.
  4. for (final String word : "Count characters using callable".split(" ")) {
  5. calls.add(new IgniteCallable<Integer>() {
  6. @Override public Integer call() throws Exception {
  7. return word.length();
  8. }
  9. });
  10. }
  11. // Execute collection of Callables on the grid.
  12. Collection<Integer> res = ignite.compute().call(calls);
  13. int sum = 0;
  14. // Add up individual word lengths received from remote nodes.
  15. for (int len : res)
  16. sum += len;
  17. System.out.println(">>> Total number of characters in the phrase is '" + sum + "'.");
  18. }

零部署
注意,由于Ignite的零部署特性,当从IDE运行上面的程序时,远程节点没有经过显式地部署,就获得了计算作业。

1.2.6.第一个数据网格应用

我们再来一个小例子,它从/往分布式缓存中获取/添加数据,并且执行基本的事务。
因为在应用中使用了缓存,要确保他是经过配置的,我们可以用Ignite自带的示例配置,他已经做了一些缓存的配置。

  1. $ bin/ignite.sh examples/config/example-cache.xml

Put和Get:

  1. try (Ignite ignite = Ignition.start("examples/config/example-ignite.xml")) {
  2. IgniteCache<Integer, String> cache = ignite.getOrCreateCache("myCacheName");
  3. // Store keys in cache (values will end up on different cache nodes).
  4. for (int i = 0; i < 10; i++)
  5. cache.put(i, Integer.toString(i));
  6. for (int i = 0; i < 10; i++)
  7. System.out.println("Got [key=" + i + ", val=" + cache.get(i) + ']');
  8. }

原子化操作:

  1. // Put-if-absent which returns previous value.
  2. Integer oldVal = cache.getAndPutIfAbsent("Hello", 11);
  3. // Put-if-absent which returns boolean success flag.
  4. boolean success = cache.putIfAbsent("World", 22);
  5. // Replace-if-exists operation (opposite of getAndPutIfAbsent), returns previous value.
  6. oldVal = cache.getAndReplace("Hello", 11);
  7. // Replace-if-exists operation (opposite of putIfAbsent), returns boolean success flag.
  8. success = cache.replace("World", 22);
  9. // Replace-if-matches operation.
  10. success = cache.replace("World", 2, 22);
  11. // Remove-if-matches operation.
  12. success = cache.remove("Hello", 1);

事务:

  1. try (Transaction tx = ignite.transactions().txStart()) {
  2. Integer hello = cache.get("Hello");
  3. if (hello == 1)
  4. cache.put("Hello", 11);
  5. cache.put("World", 22);
  6. tx.commit();
  7. }

分布式锁:

  1. // Lock cache key "Hello".
  2. Lock lock = cache.lock("Hello");
  3. lock.lock();
  4. try {
  5. cache.put("Hello", 11);
  6. cache.put("World", 22);
  7. }
  8. finally {
  9. lock.unlock();
  10. }

1.2.7.Ignite Visor管理控制台

最简单的检查Ignite数据网格中的内容,以及执行其他的一系列的管理和监控操作的方式就是使用Ignite Visor命令行工具。
要启动Visor,简单地执行如下命令即可:

  1. $ bin/ignitevisorcmd.sh

1.3.Maven配置

1.3.1.摘要

如果项目里用Maven管理依赖,可以单独地导入各个Ignite模块,

注意,在下面的例子中,要将${ignite.version}替换为实际的版本。

1.3.2.常规依赖

Ignite强依赖于ignite-core.jar

  1. <dependency>
  2. <groupId>org.apache.ignite</groupId>
  3. <artifactId>ignite-core</artifactId>
  4. <version>${ignite.version}</version>
  5. </dependency>

然而,很多时候需要其他更多的依赖,比如,要使用Spring配置或者SQL查询等。
下面就是最常用的可选模块:

  1. <dependency>
  2. <groupId>org.apache.ignite</groupId>
  3. <artifactId>ignite-core</artifactId>
  4. <version>${ignite.version}</version>
  5. </dependency>
  6. <dependency>
  7. <groupId>org.apache.ignite</groupId>
  8. <artifactId>ignite-spring</artifactId>
  9. <version>${ignite.version}</version>
  10. </dependency>
  11. <dependency>
  12. <groupId>org.apache.ignite</groupId>
  13. <artifactId>ignite-indexing</artifactId>
  14. <version>${ignite.version}</version>
  15. </dependency>

1.3.3.导入独立模块

可以一个个地导入Ignite模块,唯一必须的就是ignite-core,其他的都是可选的,所有可选模块都可以像核心模块一样导入,只是构件Id不同。
现在提供如下模块:

构件版本
注意,导入若干Ignite模块时,他们的版本号应该相同,比如,如果使用ignite-core1.7,所有其他的模块也必须导入1.7版本。

1.3.4.LGPL依赖

下面的Ignite模块有LGPL依赖,因此无法部署到Maven中央仓库:

要使用这些模块,需要手工从源代码进行构建然后加入自己的项目,比如,要将ignite-hibernate安装到本地库,可以在Ignite的源代码包中运行如下的命令:

  1. mvn clean install -DskipTests -Plgpl -pl modules/hibernate -am

第三方仓库
GridGain提供自己的Maven仓库,包含了Apache Ignite的LGPL构件,比如ignite-hibernate
注意位于GridGain的Maven库中的构件仅仅为了方便使用,并不是官方的Apache Ignite构件。

1.4.Ignite生命周期

1.4.1.摘要

Ignite是基于JVM的,一个JVM可以运行一个或者多个逻辑Ignite节点(大多数情况下,一个JVM运行一个Ignite节点)。在整个Ignite文档中,会交替地使用术语Ignite运行时以及Ignite节点,比如说可以该主机运行5个节点,技术上通常意味着主机上启动5个JVM,每个JVM运行一个节点,Ignite也支持一个JVM运行多个节点,事实上,通常作为Ignite内部测试用。

Ignite运行时 == JVM进程 == Ignite节点(多数情况下)

1.4.2.Ignition类

Ignition类在网络中启动各个Ignite节点,注意一台物理服务器(网络中的一台计算机)可以运行多个Ignite节点。
下面的代码是在全默认配置下在本地启动网格节点;

  1. Ignite ignite = Ignition.start();

或者传入一个配置文件:

  1. Ignite ignite = Ignition.start("examples/config/example-cache.xml");

配置文件的路径既可以是绝对路径,也可以是相对于IGNITE_HOME的相对路径,也可以是相对于类路径的META-INF文件夹。

1.4.3.LifecycleBean

有时可能希望在Ignite节点启动和停止的之前和之后执行特定的操作,这个可以通过实现LifecycleBean接口实现,然后在spring的配置文件中通过指定IgniteConfigurationlifecycleBeans属性实现。

  1. <bean class="org.apache.ignite.IgniteConfiguration">
  2. ...
  3. <property name="lifecycleBeans">
  4. <list>
  5. <bean class="com.mycompany.MyLifecycleBean"/>
  6. </list>
  7. </property>
  8. ...
  9. </bean>

LifecycleBean也可以像下面这样通过编程的方式实现:

  1. // Create new configuration.
  2. IgniteConfiguration cfg = new IgniteConfiguration();
  3. // Provide lifecycle bean to configuration.
  4. cfg.setLifecycleBeans(new MyLifecycleBean());
  5. // Start Ignite node with given configuration.
  6. Ignite ignite = Ignition.start(cfg)

一个LifecycleBean的实现可能如下所示:

  1. public class MyLifecycleBean implements LifecycleBean {
  2. @Override public void onLifecycleEvent(LifecycleEventType evt) {
  3. if (evt == LifecycleEventType.BEFORE_NODE_START) {
  4. // Do something.
  5. ...
  6. }
  7. }
  8. }

也可以将Ignite实例以及其他有用的资源注入LifecycleBean实现,查看1.7.资源注入章节可以了解更多的信息。

1.4.4.生命周期事件类型

当前支持如下生命周期事件类型:

1.5.异步支持

1.5.1.摘要

Ignite的多数API即可以支持同步模式,也可以支持异步模式,异步方法后面追加了Async后缀。

  1. // Synchronous get
  2. V get(K key);
  3. // Asynchronous get
  4. IgniteFuture<V> getAsync(K key);

异步操作返回的是一个IgniteFuture或其子类的实例,通过如下方式可以获得异步操作的结果,或者调用阻塞的IgniteFuture.get()方法,或者通过IgniteFuture.listen()方法或者IgniteFuture.chain()方法注册一个闭包,然后等待当操作完成后调用闭包。

1.5.2.支持的接口

下面列出的接口可以用于同步或者异步模式:

1.5.3.监听器和Future链

要在非阻塞模式下等待异步操作的结果(IgniteFuture.get()),可以使用IgniteFuture.listen()方法或者IgniteFuture.chain()方法注册一个闭包,当操作完成后,闭包会被调用,比如:

  1. IgniteCompute compute = ignite.compute();
  2. // Execute a closure asynchronously.
  3. IgniteFuture<String> fut = compute.callAsync(() -> {
  4. return "Hello World";
  5. });
  6. // Listen for completion and print out the result.
  7. fut.listen(f -> System.out.println("Job result: " + f.get()));

闭包执行和线程池
异步操作完成后,如果通过IgniteFuture.listen()或者IgniteFuture.chain()方法传递了闭包,那么闭包就会被调用线程以同步的方式执行,否则,闭包就会随着操作的完成异步地执行。
根据操作的类型,闭包可能被系统线程池中的线程调用(异步缓存操作),或者被公共线程池中的线程调用(异步计算操作)。因此需要避免在闭包实现中调用同步的缓存和计算操作,否则可能导致死锁。
要实现Ignite计算操作异步嵌套执行,可以使用自定义线程池,相关内容可以查看1.8.线程池中的相关内容。

1.6.客户端和服务端

1.6.1.摘要

Ignite有一个可选的概念,就是客户端节点服务端节点,服务端节点参与缓存、计算执行、流式处理等等,而原生的客户端节点提供了远程连接服务端的能力。Ignite原生客户端可以使用完整的Ignite API集合,包括近缓存、事务、计算、流、服务等等。
所有的Ignite节点默认都是以服务端模式启动的,客户端模式需要显式地启用。

1.6.2.配置客户端和服务端

可以通过IgniteConfiguration.setClientMode(...)属性配置一个节点,或者为客户端,或者为服务端。
XML:

  1. <bean class="org.apache.ignite.configuration.IgniteConfiguration">
  2. ...
  3. <!-- Enable client mode. -->
  4. <property name="clientMode" value="true"/>
  5. ...
  6. </bean>

Java:

  1. IgniteConfiguration cfg = new IgniteConfiguration();
  2. // Enable client mode.
  3. cfg.setClientMode(true);
  4. // Start Ignite in client mode.
  5. Ignite ignite = Ignition.start(cfg);

方便起见,也可以通过Ignition类来打开或者关闭客户端模式作为替代,这样可以使客户端和服务端共用一套配置。

  1. Ignition.setClientMode(true);
  2. // Start Ignite in client mode.
  3. Ignite ignite = Ignition.start();

1.6.3.创建分布式缓存

当在Ignite中创建缓存时,不管是通过XML方式,还是通过Ignite.createCache(...)或者Ignite.getOrCreateCache(...)方法,Ignite会自动地在所有的服务端节点中部署分布式缓存。

当分布式缓存创建之后,他会自动地部署在所有的已有或者未来的服务端节点上。

  1. // Enable client mode locally.
  2. Ignition.setClientMode(true);
  3. // Start Ignite in client mode.
  4. Ignite ignite = Ignition.start();
  5. CacheConfiguration cfg = new CacheConfiguration("myCache");
  6. // Set required cache configuration properties.
  7. ...
  8. // Create cache on all the existing and future server nodes.
  9. // Note that since the local node is a client, it will not
  10. // be caching any data.
  11. IgniteCache<?, ?> cache = ignite.getOrCreateCache(cfg);

1.6.4.客户端或者服务端计算

IgniteCompute默认会在所有的服务端节点上执行作业,然而,也可以通过创建相应的集群组来选择是只在服务端节点还是只在客户端节点上执行作业。
服务端节点执行:

  1. IgniteCompute compute = ignite.compute();
  2. // Execute computation on the server nodes (default behavior).
  3. compute.broadcast(() -> System.out.println("Hello Server"));

客户端节点执行:

  1. ClusterGroup clientGroup = ignite.cluster().forClients();
  2. IgniteCompute clientCompute = ignite.compute(clientGroup);
  3. // Execute computation on the client nodes.
  4. clientCompute.broadcast(() -> System.out.println("Hello Client"));

1.6.5.管理慢客户端

很多部署环境中,客户端节点是在主集群外启动的,机器和网络都比较差,在这些场景中服务端可能产生负载(比如持续查询通知)而客户端没有能力处理,导致服务端的输出消息队列不断增长,这可能最终导致服务端出现内存溢出的情况,或者如果打开背压控制时导致整个集群阻塞。
要管理这样的状况,可以配置允许向客户端节点输出消息的最大值,如果输出队列的大小超过配置的值,该客户端节点会从集群断开以防止拖慢整个集群。
下面的例子显示了如何通过XML或者编程的方式配置慢客户端队列限值:
Java:

  1. IgniteConfiguration cfg = new IgniteConfiguration();
  2. // Configure Ignite here.
  3. TcpCommunicationSpi commSpi = new TcpCommunicationSpi();
  4. commSpi.setSlowClientQueueLimit(1000);
  5. cfg.setCommunicationSpi(commSpi);

XML:

  1. <bean id="grid.cfg" class="org.apache.ignite.configuration.IgniteConfiguration">
  2. <!-- Configure Ignite here. -->
  3. <property name="communicationSpi">
  4. <bean class="org.apache.ignite.spi.communication.tcp.TcpCommunicationSpi">
  5. <property name="slowClientQueueLimit" value="1000"/>
  6. </bean>
  7. </property>
  8. </bean>

1.6.6.客户端重连

有几种情况客户端会从集群中断开:

当一个客户端发现它与一个集群断开时,会为自己赋予一个新的节点id然后试图与该服务端重新连接。注意:这会产生一个副作用,就是当客户端重建连接时本地ClusterNodeid属性会发生变化,这意味着,如果业务逻辑依赖于这个id,就会受到影响。
当客户端处于一个断开状态并且试图重建与集群的连接过程中时,Ignite API会抛出一个特定的异常:IgniteClientDisconnectedException,这个异常提供了一个future,当客户端重连成功后他会完成(IgniteCacheAPI会抛出CacheException,他有一个IgniteClientDisconnectedException作为他的cause)。这个future也可以通过IgniteCluster.clientReconnectFuture()方法获得。
此外,客户端重连也有一些特定的事件(这些事件是本地化的,也就是说他们只会在客户端节点触发):

下面的例子显示IgniteClientDisconnectedException如何使用:
计算:

  1. IgniteCompute compute = ignite.compute();
  2. while (true) {
  3. try {
  4. compute.run(job);
  5. }
  6. catch (IgniteClientDisconnectedException e) {
  7. e.reconnectFuture().get(); // Wait for reconnection.
  8. // Can proceed and use the same IgniteCompute instance.
  9. }
  10. }

缓存:

  1. IgniteCache cache = ignite.getOrCreateCache(new CacheConfiguration<>());
  2. while (true) {
  3. try {
  4. cache.put(key, val);
  5. }
  6. catch (CacheException e) {
  7. if (e.getCause() instanceof IgniteClientDisconnectedException) {
  8. IgniteClientDisconnectedException cause =
  9. (IgniteClientDisconnectedException)e.getCause();
  10. cause.reconnectFuture().get(); // Wait for reconnection.
  11. // Can proceed and use the same IgniteCache instance.
  12. }
  13. }
  14. }

客户端自动重连可以通过TcpDiscoverySpiclientReconnectDisabled属性禁用,如果重连被禁用那么当发现与集群断开时客户端节点就会停止。
下面的例子显示了如何禁用客户端重连:

  1. IgniteConfiguration cfg = new IgniteConfiguration();
  2. // Configure Ignite here.
  3. TcpDiscoverySpi discoverySpi = new TcpDiscoverySpi();
  4. discoverySpi.setClientReconnectDisabled(true);
  5. cfg.setDiscoverySpi(discoverySpi);

1.6.7.客户端节点强制服务端模式

客户端节点需要网络中有存活的服务端节点才能启动。
然而,如果在没有运行中的服务端节点时还要启动一个客户端节点,可以通过如下方式在客户端节点强制服务端模式发现。
如果不管服务端节点是否存活都要启动客户端节点非常必要,可以以如下的方式在客户端强制服务端模式发现:

  1. IgniteConfiguration cfg = new IgniteConfiguration();
  2. cfg.setClientMode(true);
  3. // Configure Ignite here.
  4. TcpDiscoverySpi discoverySpi = new TcpDiscoverySpi();
  5. discoverySpi.setForceServerMode(true);
  6. cfg.setDiscoverySpi(discoverySpi);

这种情况下,如果网络中的所有节点都是服务端节点时发现就会发生。

这种情况下为了发现能正常工作,发现SPI在所有节点上使用的所有地址应该是可以相互访问的。

1.7.资源注入

1.7.1.摘要

Ignite中,预定义的资源都是可以进行依赖注入的,同时支持基于属性和基于方法的注入。任何加注正确注解的资源都会在初始化之前注入相对应的任务、作业、闭包或者SPI。

1.7.2.基于属性和基于方法

可以通过在一个属性或者方法上加注注解来注入资源。当加注在属性上时,Ignite只是在注入阶段简单地设置属性的值(不会理会该属性的访问修饰符)。如果在一个方法上加注了资源注解,他会访问一个与注入资源相对应的输入参数的类型,如果匹配,那么在注入阶段,就会将适当的资源作为输入参数,然后调用该方法。
基于属性:

  1. Ignite ignite = Ignition.ignite();
  2. Collection<String> res = ignite.compute().broadcast(new IgniteCallable<String>() {
  3. // Inject Ignite instance.
  4. @IgniteInstanceResource
  5. private Ignite ignite;
  6. @Override
  7. public String call() throws Exception {
  8. IgniteCache<Object, Object> cache = ignite.getOrCreateCache(CACHE_NAME);
  9. // Do some stuff with cache.
  10. ...
  11. }
  12. });

基于方法:

  1. public class MyClusterJob implements ComputeJob {
  2. ...
  3. private Ignite ignite;
  4. ...
  5. // Inject Ignite instance.
  6. @IgniteInstanceResource
  7. public void setIgnite(Ignite ignite) {
  8. this.ignite = ignite;
  9. }
  10. ...
  11. }

1.7.3.预定义的资源

有很多的预定义资源可供注入:

资源 描述
CacheNameResource CacheConfiguration.getName()提供,注入网格缓存名
CacheStoreSessionResource 注入当前的CacheStoreSession实例
IgniteInstanceResource 注入当前的Ignite实例
JobContextResource 注入ComputeJobContext的实例。作业的上下文持有关于一个作业执行的有用的信息。比如,可以获得包含与作业并置的条目的缓存的名字。
LoadBalancerResource 注入ComputeLoadBalancer的实例,注入后可以用于任务的负载平衡。
LoggerResource 注入IgniteLogger的实例,他可以用于向本地节点的日志写消息。
ServiceResource 通过指定服务名注入Ignite的服务。
SpringApplicationContextResource 注入Spring的ApplicationContext资源。
SpringResource 从Spring的ApplicationContext注入资源,当希望访问在Spring的ApplicationContext XML配置中指定的一个Bean时,可以用它。
TaskContinuousMapperResource 注入一个ComputeTaskContinuousMapper的实例,持续映射可以在任何时点从任务中发布作业,即使过了map的初始化阶段。
TaskSessionResource 注入ComputeTaskSession资源的实例,它为一个特定的任务执行定义了一个分布式的会话。

1.8.线程池

1.8.1.摘要

Ignite创建并且维护着一组线程池,根据使用的API不同分别用于不同的目的。本章节中会列出一些众所周知的内部线程池,然后会展示如何自定义线程池。在IgniteConfiguration的javadoc中,可以看到Ignite中可用的完整线程池列表。

1.8.2.系统线程池

系统线程池处理所有与缓存相关的操作,除了SQL以及其他的查询类型,它们会使用查询线程池,同时这个线程池也负责处理Ignite计算任务的取消操作。
默认的线程池数量为CPU总核数*2,使用IgniteConfiguration.setSystemThreadPoolSize(...)可以进行调整。

1.8.3.公共线程池

公共线程池负责Ignite的计算网格,所有的计算任务都由这个线程池接收然后处理。
默认的线程池数量为CPU总核数*2,使用IgniteConfiguration.setPublicThreadPoolSize(...)可以进行调整。

1.8.4.查询线程池

查询线程池处理集群内所有的SQL、扫描和SPI查询。
默认的线程池数量为CPU总核数*2,使用IgniteConfiguration.setQueryThreadPoolSize(...)可以进行调整。

1.8.5.服务线程池

Ignite的服务网格调用使用的是服务线程池,Ignite的服务和计算网格组件都有专用的线程池,可以避免当一个服务实现希望调用一个计算(或者反之)时的线程争用和死锁。
默认的线程池数量为CPU总核数*2,使用IgniteConfiguration.setServiceThreadPoolSize(...)可以进行调整。

1.8.6.平行线程池

平行线程池通过将操作展开为多个平行的执行,有助于显著加速基本的缓存操作以及事务,因为可以避免相互竞争。
默认的线程池数量为CPU总核数*2,使用IgniteConfiguration.setStripedPoolSize(...)可以进行调整。

1.8.7.数据流处理器线程池

数据流处理器线程池用于处理来自IgniteDataStreamer的所有消息和请求,各种内置的使用IgniteDataStreamer的流适配器也可以。
默认的线程池数量为CPU总核数*2,使用IgniteConfiguration.setDataStreamerThreadPoolSize(...)可以进行调整。

1.8.8.自定义线程池

对于Ignite的计算任务,也可以配置自定义的线程池,当希望同步地从一个计算任务调用另一个的时候很有用,因为可以避免死锁。要保证这一点,需要确保执行嵌套任务的线程池不同于上级任务的线程池。
自定义线程池需要在IgniteConfiguration中进行定义,并且需要有一个唯一的名字:
Java:

  1. IgniteConfiguration cfg = ...;
  2. cfg.setExecutorConfiguration(new ExecutorConfiguration("myPool").setSize(16));

XML:

  1. <bean id="grid.cfg" class="org.apache.ignite.configuration.IgniteConfiguration">
  2. ...
  3. <property name="executorConfiguration">
  4. <list>
  5. <bean class="org.apache.ignite.configuration.ExecutorConfiguration">
  6. <property name="name" value="myPool"/>
  7. <property name="size" value="16"/>
  8. </bean>
  9. </list>
  10. </property>
  11. ...
  12. </bean>

这样,假定下面的计算任务由上面定义的myPool线程池中的线程执行:

  1. public class InnerRunnable implements IgniteRunnable {
  2. @Override public void run() {
  3. System.out.println("Hello from inner runnable!");
  4. }
  5. }

怎么做呢,需要使用IgniteCompute.withExecutor(),他会被上级任务的实现马上执行,像下面这样:

  1. public class OuterRunnable implements IgniteRunnable {
  2. @IgniteInstanceResource
  3. private Ignite ignite;
  4. @Override public void run() {
  5. // Synchronously execute InnerRunnable in custom executor.
  6. ignite.compute().withExecutor("myPool").run(new InnerRunnable());
  7. }
  8. }

上级任务的执行可通过如下方式触发,对于这个场景,它会由公共线程池执行:

  1. ignite.compute().run(new OuterRunnable());

未定义线程池
如果应用请求在自定义线程池执行计算任务,而该线程池在Ignite节点中未定义,那么一个特定的警告消息就会在节点的日志中输出,然后任务就会被公共线程池接管执行。

1.9.FAQ

1.堆内和堆外内存存储有何不同?
当处理很大的堆时,通过在Java主堆空间外部缓存数据,可以使缓存克服漫长的JVM垃圾收集(GC)导致的暂停,但是数据仍然在内存中。
更多信息
2.Apache Ignite是一个键值存储么?
Apache Ignite是一个具有计算能力的、有弹性的内存中的分布式对象存储。在其最简单的形式中,是的,Apache Ignite可以作为一个键/值存储(缓存),但是也暴露了更丰富的API来与数据交互,比如完整的ANSI99兼容的SQL查询、文本检索、事务等等。
更多信息
3.Apache Ignite是否支持JSON文档?
当前,Apache Ignite并不完整支持JSON文档,但是当前处于beta阶段的Node.js客户端会支持JSON文档。
4.Apache Ignite是否可以用于Apache Hive?
是,Apache Ignite的Hadoop加速器提供了一系列的组件,支持在任何的Hadoop发行版中执行内存中的Hadoop作业执行和文件系统操作,包括Apache Hive。
在Ignite化的Hadoop中运行Apache Hive
5.在事务隔离的悲观模式中,是否锁定键的读和写?
是的,主要的问题在于,在悲观模式中,访问是会获得锁,而在乐观模式中,锁是在提交阶段获得的。
更多信息
6.是否可以用Hibernate访问Apache Ignite?
是的,Apache Ignite可以用作Hibernate的二级缓存(或者L2缓存),他可以显著地提升应用的持久化层的速度。
更多信息
7.Apache Ignite是否支持JDBC?
是的,Apache Ignite提供了JDBC驱动,可以在缓存中使用标准SQL查询和JDBC API获得分布式的数据。
更多信息
8.Apache Ignite是否保证消息的顺序?
是的,如果希望收到消息的顺序与发送消息的顺序一致,可以使用sendOrdered(...)方法。可以传递一个超时时间来指定一条消息在队列中的等待时间,他会等待本来应在其之前发送的消息。如果超时时间过期,所有的还没有到达该节点中一个给定主题的消息都会被忽略。
更多信息
9.是否可以运行Java和.Net闭包?他是如何工作的?
.Net节点可以同时执行Java和.Net闭包,而标准Java节点只能执行Java闭包。当启动ApacheIgnite.exe时,他会使用位于IGNITE_HOME/platforms/dotnet/bin的一个脚本在同一个进程下同时启动JVM和CLR,.Net闭包会被CLR处理执行。
10.Java和.Net之间的转换成本是什么?
仅有的最小可能的开销是一个额外的数组复制+JNI调用,在本地测试时这个开销可能降低性能,但在真正的分布式负载环境下可以忽略不计。
11.闭包是如何传输的?
每个闭包都是一个特定类的对象。当它要被发送时会序列化成二进制的形式,通过线路发送到一个远程节点然后在那里反序列化。该远程节点在类路径中应该有该闭包类,或者开启peerClassLoading以从发送端加载该类。
12.SQL查询是否被负载平衡?
SQL查询总是被广播到保存有要查询的数据的每个节点,例外就是本地SQL查询(query.setLocal(true)),他只是在一个本地节点执行。
13.用户是否可以控制资源分配?即,是否可以限制用户A为50个节点,但是用户B可以在所有的100个节点上执行任务?
多租户只在缓存中存在,他们可以在创建在一个节点的子集上(可以看CacheConfiguration.setNodeFilter)以及在每个缓存基础上安全地赋予权限。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注