Apache Ignite(七):基于Ignite的企业级分布式并行计算

原创
2016/05/04 19:51
阅读数 7.7K

[TOC]

1.传统的方案

在各行各业中,批量业务处理都是常规需求,非常常见。它的特点是,离线处理、运行时间长、计算密集。传统的解决方式是,或者使用多线程技术,或者使用数据库计算,比如调用数据库的存储过程技术实现等等。 在以Hadoop为首的分布式计算技术出现后,情况有了很大的变化,MapReduce范式为大规模离线数据处理提供了新的思路,性能得到了很大的提升,也提供了很好的线性扩展解决方案。

2.面临的问题

多线程或者类似于存储过程这样的技术,共有的缺陷是,扩展性差,性能依赖于单一硬件性能,大幅提升性能困难,无法实现分布式计算。 而以Hadoop为首的大数据处理解决方案,近段时间发展迅速,性能指标也在不断地提升,但是设计的目标,或者说适用的场景,主要还是在互联网的大规模非结构化数据的分析业务上,虽然也可以用于传统的批量业务处理,但是一方面批量业务处理并不需要那么多的功能,杀鸡用了牛刀;另一方面,这些新一代的计算平台属于异构系统,需要在具体应用之外单独部署,如果要实现高可用,整体的架构也会变得非常复杂,整体的运维成本也会上升,增加了对应的服务器之后,如果计算不多,资源利用率也会下降,采用这样技术的投入产出比,是需要考虑的。

3.Ignite计算网格

Ignite计算网格实现了分布式的闭包和ExecutorService,同时它还提供了一个轻量级的MapReduce(或ForkJoin)实现。 本文重点讲一下轻量级MapReduce,其它的可以参照相关的手册。

3.1.MapReduce和ForkJoin

ComputeTask接口是Ignite的简化版内存MapReduce的抽象,它也非常接近于ForkJoin范式。这个接口可以对作业到节点的映射做细粒度的控制以及定制故障转移的策略,如果不需要这些,可以使用更简单的分布式闭包实现,代码将会更加精炼。

3.1.1.ComputeTask

ComputeTask定义了要在集群内执行的作业以及这些作业到节点的映射,它还定义了如何处理作业的返回值(Reduce)。所有的IgniteCompute.execute(...)方法都会在集群上执行给定的任务,应用只需要实现ComputeTask接口的map(...)reduce(...)方法即可,其中:

  • map(...)方法负责将作业实例化然后将它们映射到工作节点,这个过程通过ComputeTaskSplitAdapter,还可以进一步简化;
  • result(...)方法在每次作业在集群节点上执行时都会被调用,它接收计算作业返回的结果,以及迄今为止收到的作业结果的列表,该方法会返回一个ComputeJobResultPolicy的实例,说明下一步要做什么;
  • 当所有作业完成后,reduce(...)方法在Reduce阶段被调用。该方法接收到所有计算结果的一个列表然后返回一个最终的计算结果。

3.1.2.更简单的适配器ComputeTaskSplitAdapter

定义计算时每次都实现ComputeTask的所有三个方法并不是必须的,通过Ignite提供的适配器,可以进一步简化开发,我着重介绍下ComputeTaskSplitAdapter,它增加了将作业自动分配给节点的功能。它隐藏了map(...)方法然后增加了一个新的split(...)方法,使得开发者只需要提供一个待执行的作业集合即可,这非常适用于批量业务处理。这个适配器对于所有节点都适于执行作业的同质化环境是非常有用的,这样的话映射阶段就可以隐式地完成。

3.1.3.ComputeJob

任务触发的所有作业都要实现ComputeJob接口,这个接口的execute()方法定义了作业的逻辑然后返回一个作业的结果。

3.1.4.简单示例

下面这段代码,作为一个简单示例,显示了如何计算一段话中的字母的总数量:

    IgniteCompute compute = ignite.compute();
    // 在集群上执行任务。
    int cnt = grid.compute().execute(CharacterCountTask.class, "Hello Grid Enabled World!");
    private static class CharacterCountTask extends ComputeTaskSplitAdapter<String, Integer> {
      // 1. 将收到的字符串拆分为字符串数组
      // 2. 为每个单词创建一个作业
      // 3. 将每个作业发送给工作节点进行处理
      @Override 
      public List<ClusterNode> split(List<ClusterNode> subgrid, String arg) {
        String[] words = arg.split(" ");
        List<ComputeJob> jobs = new ArrayList<>(words.length);
        for (final String word : arg.split(" ")) {
          jobs.add(new ComputeJobAdapter() {
            @Override public Object execute() {
              return word.length();
            }
          });
        }
        return jobs;
      }
      @Override 
      public Integer reduce(List<ComputeJobResult> results) {
        int sum = 0;
        for (ComputeJobResult res : results)
          sum += res.<Integer>getData();
        return sum;
      }
    }

是不是非常简单?

3.2.容错

Ignite支持作业的自动故障转移,当一个节点故障时,作业会被转移到其它可用节点再次执行。故障转移是通过FailoverSpi实现的,FailoverSpi负责选择一个新的节点来执行失败的作业。它会检查发生故障的作业以及该作业可以尝试执行的所有可用的网格节点的列表。它会确保该作业不会再次映射到出现故障的同一个节点。故障转移是在ComputeTask.result(...)方法返回ComputeJobResultPolicy.FAILOVER策略时触发的。Ignite内置了一些故障转移SPI的实现,开发者也可以进行定制。另外,Ignite保证,只要有一个节点是有效的,作业就不会丢失。

3.3.负载平衡

Ignite中的负载平衡是通过LoadBalancingSpi实现的。它控制所有节点的负载以及确保集群中的每个节点负载水平均衡。对于同质化环境中的同质化的任务,负载平衡采用的是随机或者循环的策略。然而在很多其它场景中,特别是在一些不均匀的负载下,就需要更复杂的自适应负载平衡策略。Ignite内置了若干中负载平衡实现,比如循环式负载平衡RoundRobinLoadBalancingSpi以及随机或者加权负载平衡WeightedRandomLoadBalancingSpi,这部分开发者也可以定制开发,满足个性化需求。

3.4.作业调度

Ignite中,作业是在客户端侧的任务拆分初始化或者闭包执行阶段被映射到集群节点上的,但是一旦作业到达被分配的节点,就会有序地执行。默认情况下,作业会被提交到一个线程池然后随机地执行,如果要对作业执行顺序进行细粒度控制的话,需要启用CollisionSpi,比如,可以按照FIFO排序或者按照优先级排序。

3.5.事务

在企业级批量业务处理中,通常要对数据库进行频繁的更新操作,在分布式计算环境下,将整个任务配置为一个事务显然是不合适的。最佳实践是将每个作业配置成一个事务,这样如果某个作业失败,只是该作业回滚,其它成功的作业还是正常提交的,然后故障转移机制会使该失败的作业再次执行,直到成功提交。

3.6.其它

Ignite的内存MapReduce实现还支持会话,这个机制可以在任务和作业之间共享一些数据,还支持节点局部状态共享,这个其实是节点的局部变量,它可以用于任务在不同的执行过程中共享状态。还有,通过计算和缓存数据的并置,可以极大地提高性能,它还支持检查点,可以在一个长时间执行的作业中保存一些中间状态,这个机制在重启一个故障节点后,作业可以从保存的检查点载入然后从故障处继续执行。等等,在这里就不一一介绍了。

4.Ignite的优势

在之前的关于Ignite的集群部署的文章中我对Ignite的集群特性做了简要的介绍,该文中推荐了一种混合式的集群部署方案,如下图:

在这个架构中,如果能够在应用集群组中进行分布式计算来实现批量业务处理,那么这会是一个很优雅的解决方案,幸运的是,Ignite真的实现了,这个解决方案整体上来讲,具有如下的优势:

  • **开发简单:**很简单的几段代码就实现了MapReduce,入门门槛极低,经过很短时间的学习,就可以把注意力放在复杂业务的处理上;
  • 调试简单: Ignite单机就可以启动一个只有一个节点的集群,可以在IDE中直接单步调试,不需要为了开发调试构建任何复杂的环境;
  • **部署简单:**只要将Ignite的几个jar包嵌入应用内部,就可以利用Ignite的发现机制自动建立集群,实现分布式计算,而其它分布式计算平台,基本都需要部署单独的计算服务器,整个部署架构也变得复杂,运维成本也会上升;
  • **资源利用率高:**通常批量业务处理都是在夜间系统空闲时,如果还是在这些设备上进行分布式计算,可以充分利用计算资源,如果采用需要单独增加服务器的计算方案,因为大部分时间设备闲置,整体设备成本上升,资源利用效率也会大幅下降。
展开阅读全文
打赏
2
30 收藏
分享
加载中
谢谢你的翻译.真是太感谢了
2016/05/27 16:09
回复
举报

引用来自“李玉珏”的评论

引用来自“fir01”的评论

楼主您好,非常感谢您的多次回复。我想买4台服务器做下内部一些应用的测试,测试没问题转正式使用。请问什么配置比较划算呢?我目前的考虑的是:集群的单机要求内核主频低点可以,重要是线程数多,内存管够。 有个疑问?以前有个了解就是如果程序不是针对多线程内核的多线程优化的话,线程多对单软件而言性能没什么影响。 请问这个配置考虑是对的吗? 还是主频尽量高,线程少可以,内存管够?

内存的需求量是可以计算的,CPU的要求看你的业务需求了,资源少运行时间就长呗,整个的硬件需求,你需要根据测试环境的性能测试结果做估算

引用来自“fir01”的评论

嗯。cpu就是想知道lgnite对多线程支持怎么样?假设场景10000个任务,进入系统处理,假定下面两方案总价一样,其它所有硬件都样。 方案A---是酷睿2.0的8核采购4台; 方案B---3.2的2核采购4台; 这两个哪个方案执行效率更高呢?

引用来自“李玉珏”的评论

https://www.zybuluo.com/liyuj/note/264800 你看下8.10章节,按照这个内容的描述,他默认是只支持2个线程同时运行,所以这个地方是可以根据你的硬件情况进行调优的。
太好了。非常感谢先生指导
2016/05/27 15:29
回复
举报
李玉珏博主

引用来自“李玉珏”的评论

引用来自“fir01”的评论

楼主您好,非常感谢您的多次回复。我想买4台服务器做下内部一些应用的测试,测试没问题转正式使用。请问什么配置比较划算呢?我目前的考虑的是:集群的单机要求内核主频低点可以,重要是线程数多,内存管够。 有个疑问?以前有个了解就是如果程序不是针对多线程内核的多线程优化的话,线程多对单软件而言性能没什么影响。 请问这个配置考虑是对的吗? 还是主频尽量高,线程少可以,内存管够?

内存的需求量是可以计算的,CPU的要求看你的业务需求了,资源少运行时间就长呗,整个的硬件需求,你需要根据测试环境的性能测试结果做估算

引用来自“fir01”的评论

嗯。cpu就是想知道lgnite对多线程支持怎么样?假设场景10000个任务,进入系统处理,假定下面两方案总价一样,其它所有硬件都样。 方案A---是酷睿2.0的8核采购4台; 方案B---3.2的2核采购4台; 这两个哪个方案执行效率更高呢?
https://www.zybuluo.com/liyuj/note/264800 你看下8.10章节,按照这个内容的描述,他默认是只支持2个线程同时运行,所以这个地方是可以根据你的硬件情况进行调优的。
2016/05/26 20:59
回复
举报

引用来自“李玉珏”的评论

引用来自“fir01”的评论

楼主您好,非常感谢您的多次回复。我想买4台服务器做下内部一些应用的测试,测试没问题转正式使用。请问什么配置比较划算呢?我目前的考虑的是:集群的单机要求内核主频低点可以,重要是线程数多,内存管够。 有个疑问?以前有个了解就是如果程序不是针对多线程内核的多线程优化的话,线程多对单软件而言性能没什么影响。 请问这个配置考虑是对的吗? 还是主频尽量高,线程少可以,内存管够?

内存的需求量是可以计算的,CPU的要求看你的业务需求了,资源少运行时间就长呗,整个的硬件需求,你需要根据测试环境的性能测试结果做估算
嗯。cpu就是想知道lgnite对多线程支持怎么样?假设场景10000个任务,进入系统处理,假定下面两方案总价一样,其它所有硬件都样。 方案A---是酷睿2.0的8核采购4台; 方案B---3.2的2核采购4台; 这两个哪个方案执行效率更高呢?
2016/05/26 18:04
回复
举报
李玉珏博主

引用来自“fir01”的评论

楼主您好,非常感谢您的多次回复。我想买4台服务器做下内部一些应用的测试,测试没问题转正式使用。请问什么配置比较划算呢?我目前的考虑的是:集群的单机要求内核主频低点可以,重要是线程数多,内存管够。 有个疑问?以前有个了解就是如果程序不是针对多线程内核的多线程优化的话,线程多对单软件而言性能没什么影响。 请问这个配置考虑是对的吗? 还是主频尽量高,线程少可以,内存管够?

内存的需求量是可以计算的,CPU的要求看你的业务需求了,资源少运行时间就长呗,整个的硬件需求,你需要根据测试环境的性能测试结果做估算
2016/05/26 11:58
回复
举报
楼主您好,非常感谢您的多次回复。我想买4台服务器做下内部一些应用的测试,测试没问题转正式使用。请问什么配置比较划算呢?我目前的考虑的是:集群的单机要求内核主频低点可以,重要是线程数多,内存管够。 有个疑问?以前有个了解就是如果程序不是针对多线程内核的多线程优化的话,线程多对单软件而言性能没什么影响。 请问这个配置考虑是对的吗? 还是主频尽量高,线程少可以,内存管够?
2016/05/26 11:17
回复
举报
13抱个大腿,抽空好好研究下
2016/05/05 12:05
回复
举报

引用来自“李玉珏”的评论

引用来自“寻梦2012”的评论

有没有实战过

正在做解决方案验证,这个方案要想形成最佳实践,还需要很长时间,很多经验数据还需要积累。
理论上这是个很优雅的解决方案,胆大的可以先试试,我这要出总结文章,至少半年以后,但是小项目,估计也没啥大问题。
国内用这个做并行计算的,估计非常少甚至没有,找不到相关资料,这个技术也相对较新。
最近看了您的文章。我也在慢慢研究
2016/05/05 09:38
回复
举报
李玉珏博主

引用来自“寻梦2012”的评论

有没有实战过

正在做解决方案验证,这个方案要想形成最佳实践,还需要很长时间,很多经验数据还需要积累。
理论上这是个很优雅的解决方案,胆大的可以先试试,我这要出总结文章,至少半年以后,但是小项目,估计也没啥大问题。
国内用这个做并行计算的,估计非常少甚至没有,找不到相关资料,这个技术也相对较新。
2016/05/05 09:33
回复
举报
有没有实战过
2016/05/05 09:18
回复
举报
更多评论
打赏
11 评论
30 收藏
2
分享
OSCHINA
登录后可查看更多优质内容
返回顶部
顶部