我正在尝试使用Java 8 map-reduce框架在java中编写一个分布式Map-reduce程序,该框架具有以下设计:
一个客户端将数据发送到3个Mappers(每个都是不同的机器/独立Java应用程序)。映射器通过从数据列表中创建parallelStream()
来并行处理数据。
现在每个映射器都应该在其parallelStream上调用.map(...)
。然后,想法是将映射的数据发送到另一个节点Reducer。
reducer将获取Stream并在其上调用.reduce(...)
,最后.get()
获取最终结果,然后发送回客户端。
如果我在同一个程序上调用.map(...).reduce(...).get()
,我的程序可以工作,但我希望能够有一个单独的reducer节点。
由于我是套接字编程和使用Java 8的新手,我在通过Socket发送流时遇到了麻烦,因为它抛出了“java.io.NotSerializableException:java.util.stream.ReferencePipeline $ 3”我尝试使用WriteObject
编写流。
这里最好的方法是什么?我可以将流转换为其他内容,发送它然后再在我的Reducer
节点上将其转换为流吗?是否有更好的方式来发送流而不是通过ObjectOutputStream
?
非常感谢任何想法。非常感谢你!
P.S。:流是Stream<Map<String, Integer>>
。
答案 0 :(得分:0)
一种方法是使用将数据推入套接字的forEach来终止map节点。如果集合可能非常大(或理论上无限大),这种策略优于集合方法;它的空间效率很高,它是缓冲的,下游节点没有空闲等待收集过程完成。
接下来为Spliterator中的reduce节点包装套接字读取器(扩展AbstractSpliterator)。 Spliterator的tryAdvance方法从套接字读取数据,并通过调用者提供的Consumer使其可用于流。当没有更多数据(您的流结束标记,流套接字结束或套接字异常)时,tryAdvance返回false。 AbstractSpliterator.trySplit实现了有限的并行性。
使用StreamSupport.stream(Spliterator spliterator,boolean parallel)从Spliterator实现构造流。您的reduce操作会从此流中提取数据。
您可以保留套接字,并且您的流末尾标记可能更像是消息结束标记(让我想起管道中的批处理猪)。