将Spark Streaming输出写入套接字

时间:2014-11-05 11:50:42

标签: java sockets socket.io apache-spark

我有一个DStream“Crowd”,我想将“Crowd”中的每个元素写入套接字。当我尝试从该套接字读取时,它不会打印任何东西。我正在使用以下代码行:

val server = new ServerSocket(4000,200);
val conn = server.accept()
val out = new PrintStream(conn.getOutputStream());
crowd.foreachRDD(rdd => {rdd.foreach(record=>{out.println(record)})})

但是如果使用(虽然这不是我想要的):

crowd.foreachRDD(rdd => out.println(rdd)) 

它确实向套接字写了一些内容。

我怀疑使用rdd.foreach()时出现问题。虽然它应该工作。我不确定我错过了什么。

3 个答案:

答案 0 :(得分:4)

DStream闭包之外的代码在驱动程序中执行,而rdd.foreach(...)将在RDD的每个分布式分区上执行。 所以,在驱动程序的机器上创建了一个套接字,并且该作业试图在另一台机器上写入 - 这显然不会起作用。

DStream.foreachRDD在驱动程序上执行,因此在该实例中,套接字和计算在同一主机中执行。因此它有效。

由于RDD计算的分布式特性,这种服务器套接字方法难以实现,因为动态服务发现成为挑战,即“我的服务器套接字在哪里打开?”。查看一些允许您集中访问分布式数据的系统。 Kafka是这种流媒体流程的不错选择。

答案 1 :(得分:0)

crowd.foreachRDD(rdd => {rdd.collect.foreach(record=>{out.println(record)})})

您的评论中建议的代码可以正常工作,但在这种情况下,您必须收集驱动程序中RDD的所有记录。如果记录数量很小就可以,但是如果记录数量大于驱动程序的内存,那将成为瓶颈。您的第一次尝试应始终在客户端处理数据。记住RDD是在工作机器上分发的,这意味着首先需要将RDD中的所有记录都带到驱动程序中,从而增加通信,这在分布式计算中是一种杀戮。如上所述,只有当RDD中的记录有限时,您的代码才会正常。

我正在处理类似的问题,我一直在搜索如何将连接池连接并将它们序列化到客户端计算机。如果某个机构对此有任何答案,那就太棒了。

答案 2 :(得分:0)

Here in the official documentation你有答案!

您必须在foreachRDD功能内部创建连接,如果您想以最佳方式进行连接,则需要创建一个"池"连接,然后在foreachPartition函数内部带来所需的连接,并调用foreach函数通过该连接发送元素。这是以最佳方式执行此操作的示例代码:

dstream.foreachRDD { rdd =>
  rdd.foreachPartition { partitionOfRecords =>
    // ConnectionPool is a static, lazily initialized pool of connections
    val connection = ConnectionPool.getConnection()
    partitionOfRecords.foreach(record => connection.send(record))
    ConnectionPool.returnConnection(connection)  // return to the pool for future reuse
  }
}

在任何情况下,请检查其他评论,因为它们提供了有关问题背景的良好知识。