官网原英文地址: http://spark.apache.org/docs/latest/streaming-custom-receivers.html
Spark Streaming可以从其内置支持(除了Kafka,Kinesis,文件,套接字等)之外的任何任意数据源接收流数据。这就要求开发人员实现一个为从相关数据源接收数据而定制的接收器。本指南介绍了实现自定义接收器并在Spark Streaming应用程序中使用它的过程。请注意,可以通过Scala或Java语言来实现自定义接收器。
用户如何实现自定义接收器
首先从实现Receiver (Scala doc, Java doc)开始。自定义接收方必须通过实现两个方法来扩展此抽象类
onStart()
:开始接收数据时要做的事情。onStop()
: 停止接收数据的操作。
双方onStart()
并onStop()
不能无限期地阻塞。通常,onStart()
将启动负责接收数据的线程,并onStop()
确保这些线程停止接收数据。接收线程也可以使用isStopped()
,一个Receiver
方法,以检查他们是否应该停止接收数据。
接收到数据后,可以通过调用将该数据存储在Spark内部store(data)
,这是Receiver类提供的方法。有多种类型,store()
它们可以一次存储记录的接收数据,也可以存储为对象/序列化字节的完整集合。请注意,store()
用于实现接收器的风格 会影响其可靠性和容错语义。稍后将对此进行详细讨论。
接收线程中的任何异常都应被捕获并正确处理,以避免接收器出现静默故障。restart(<exception>)
将通过异步调用onStop()
然后onStart()
延迟后调用来重新启动接收器。 stop(<exception>)
将呼叫onStop()
并终止接收器。此外,reportError(<error>)
无需停止/重新启动接收器即可向驱动程序报告错误消息(在日志和UI中可见)。
以下是一个自定义接收器,它通过套接字接收文本流。它将文本流中以'\ n'分隔的行视为记录,并将其存储在Spark中。如果接收线程在连接或接收时遇到任何错误,则重新启动接收器以进行另一次连接尝试。
class CustomReceiver(host: String, port: Int)
extends Receiver[String](StorageLevel.MEMORY_AND_DISK_2) with Logging {
def onStart() {
// Start the thread that receives data over a connection
new Thread("Socket Receiver") {
override def run() { receive() }
}.start()
}
def onStop() {
// There is nothing much to do as the thread calling receive()
// is designed to stop by itself if isStopped() returns false
}
/** Create a socket connection and receive data until receiver is stopped */
private def receive() {
var socket: Socket = null
var userInput: String = null
try {
// Connect to host:port
socket = new Socket(host, port)
// Until stopped or connection broken continue reading
val reader = new BufferedReader(
new InputStreamReader(socket.getInputStream(), StandardCharsets.UTF_8))
userInput = reader.readLine()
while(!isStopped && userInput != null) {
store(userInput)
userInput = reader.readLine()
}
reader.close()
socket.close()
// Restart in an attempt to connect again when server is active again
restart("Trying to connect again")
} catch {
case e: java.net.ConnectException =>
// restart if could not connect to server
restart("Error connecting to " + host + ":" + port, e)
case t: Throwable =>
// restart if there is any other error
restart("Error receiving data", t)
}
}
}
在Spark Streaming应用程序中使用自定义接收器
可以通过使用自定义接收器在Spark Streaming应用程序中使用 streamingContext.receiverStream(<instance of custom receiver>)
。这将使用自定义接收器实例接收的数据创建输入DStream,如下所示:
// Assuming ssc is the StreamingContext
val customReceiverStream = ssc.receiverStream(new CustomReceiver(host, port))
val words = customReceiverStream.flatMap(_.split(" "))
...
完整的源代码在示例CustomReceiver.scala中。
接收器可靠性
正如《Spark Streaming编程指南》中简要讨论的那样, 基于其可靠性和容错语义,有两种接收器。
- 可靠的接收器-对于允许确认已发送数据的可靠源, 可靠的接收器正确地向源确认已可靠地接收并存储了数据(即已成功复制)。通常,实现此接收器需要仔细考虑源确认的语义。
- 不可靠的接收器-一个不可靠的接收器并没有发送确认的资源等。可以将其用于不支持确认的来源,甚至可以用于不希望或不需要进入确认复杂性的可靠来源。
要实现可靠的接收器,您必须使用store(multiple-records)
存储数据。这种store
形式的阻塞调用仅在所有给定记录已存储在Spark中之后才返回。如果接收者的已配置存储级别使用复制(默认情况下启用),则复制完成后将返回此调用。因此,它可以确保可靠地存储数据,并且接收方现在可以适当地确认源。这样可以确保当接收方在复制数据的过程中发生故障时,不会丢失任何数据–缓冲的数据将不会被确认,因此稍后将由源重新发送。
一个不可靠的接收器没有实现任何这种逻辑的。它可以简单地从源接收记录,并使用一次插入它们store(single-record)
。尽管没有获得的可靠性保证store(multiple-records)
,但它具有以下优点:
- 系统负责将数据块分为适当大小的块(请在《Spark Streaming编程指南》中查找块间隔)。
- 如果已指定速率限制,则系统会控制接收速率。
- 由于这两方面的原因,不可靠的接收器比可靠的接收器更易于实现。
下表总结了两种类型的接收器的特性
接收器类型 | 特点 |
---|---|
不可靠的接收者 | 易于实现。 没有容错保证,会因接收器故障而丢失数据。 |
可靠的接收者 | 强大的容错保证,可以确保零数据丢失。 接收器实现要处理的块生成和速率控制。 实现的复杂性取决于源的确认机制。 |