使用Akka实现MapReduce

时间:2013-06-25 07:46:26

标签: java mapreduce akka

我正在尝试在Akka之上实现MapReduce,很幸运能找到本书的代码Akka Essentials。但是,我发现这个示例实现有两个主要问题,两者看起来都像基本的并发设计缺陷,在一本关于Akka的书中找到它是非常令人震惊的:

  1. 完成后,客户端将调用shutdown(),但此时无法保证消息通过WCMapReduceServer。我看到WCMapReduceServer在任何时候只获取部分数量的客户端消息,然后WCMapReduceServer输出[INFO] [06/25/2013 09:30:01.594] [WCMapReduceApp-5] [ActorSystem(WCMapReduceApp)] REMOTE: RemoteClientShutdown@akka://ClientApplication@192.168.224.65:2552,意味着客户端shutdown()在客户端实际设法刷新所有未决消息之前发生。在客户端代码line 41中,我们看到shutdown()发生时没有先刷新。在关闭系统之前,Akka是否有办法强制执行刷新出站邮件?

  2. 另一个实际上更大的缺陷,我已经修复了,是用于向MapReduce服务器发出EOF信号的方式,主要任务(文字文件)完成后给定所有子任务(文件的每一行)完成。他发送一个特殊的字符串消息DISPLAY_LIST,此消息排队的优先级最低see code。这里的一个重大缺陷是即使DISPLAY_LIST具有最低优先级,如果任何Map(或Reduce)任务任意长,DISPLAY_LIST消息将在所有MapReduce子任务完成之前通过,因此此MapReduce示例的结果是非确定性的,即您可以在每次运行中获得不同的字典。可以通过用以下内容替换MapActor#onReceive implementation来揭示问题,即将一个Map步骤任意长一点:

    public void onReceive(Object message) {
        System.out.println("MapActor -> onReceive(" + message + ")");
        if (message instanceof String) {
            String work = (String) message;
            // ******** BEGIN SLOW DOWN ONE MAP REQUEST
            if ("Thieves! thieves!".equals(work)) {
                try {
                    System.out.println("*** sleeping!");
                    Thread.sleep(5000);
                    System.out.println("*** back!");
                }
                catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            // ******** END SLOW DOWN ONE MAP REQUEST
    
            // perform the work
            List<Result> list = evaluateExpression(work);
    
            // reply with the result
            actor.tell(list);
    
        } else throw new IllegalArgumentException("Unknown message [" + message + "]");
    }
    
  3. 进一步阅读这本书后发现:

      

    我们有Thread.sleep(),因为无法保证订单的顺序   消息被处理。第一个Thread.sleep()方法 确保   以前完全处理所有字符串句子消息   我们发送结果消息。

    我很抱歉,Thread.sleep()从未成为确保并发性的方法。因此,难怪这样的书会在他们的例子中充满基本的并发缺陷。

1 个答案:

答案 0 :(得分:1)

我已经解决了这两个问题,并且还将代码迁移到最新的Akka 2.2-M3版本。

第一个问题的解决方案是让MapReduce远程MasterActor在收到所有消息发送后从客户端发送的TaskInfo通知后立即发回ShutdownInfo通知。 TaskInfo包含MapReduce任务具有多少子任务的信息,例如:在这种情况下,文本文件中有多少行。

第二个问题的解决方案是发送具有子任务总数的TaskInfo。在这里,AggregatorActor计算它已经处理的子任务的数量,将它与TaskInfo进行比较,并表示作业在匹配时完成(当前只是打印一条消息)。

输出中显示了有趣且正确的行为:

  • ClientActor发送一堆“子任务”消息。请注意,Identity请求模式用于访问远程MapReduce MasterActor的ActorRef。
  • ClientActor最后发送TaskInfo消息,说明之前发送了多少个子任务。
  • MasterActor将字符串消息转发给MapActor,然后转发给ReduceActor
  • 一个MapActor是一个冗长的,即内容为“Thieves!thieves!”的MapActor。这会减慢MapReduce计算的速度。
  • 同时MasterActor收到TaskInfo最后一条消息,并将ShudownInfo发送回ClientActor
  • ClientActor运行system.shutdown()并终止客户端。请注意,MapReduce仍处于处理过程中,客户端关闭不会干扰。
  • 漫长的MapActor返回,消息处理继续。
  • AggregatorActor接收TaskInfo,并通过计算子任务确认子任务的总数已经完成并发出完成信号。

可以从我的存储库中获取代码: https://github.com/bravegag/akka-mapreduce-example

随时欢迎反馈。