我有一个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()时出现问题。虽然它应该工作。我不确定我错过了什么。
答案 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
}
}
在任何情况下,请检查其他评论,因为它们提供了有关问题背景的良好知识。