如果觉得不错,请给博主点个赞呗!!! 谢谢
如果觉得不错,请给博主点个赞呗!!! 谢谢
如果觉得不错,请给博主点个赞呗!!! 谢谢
目录
1、Caching / Persistence 缓存/持久化
2.1、When to enable Checkpointing 何时启用检查点
2.2、How to configure Checkpointing 如何配置检查点
3、Accumulators, Broadcast Variables, and Checkpoints 累加器、广播变量和检查点
1、Caching / Persistence 缓存/持久化
与 RDDs 类似,DStreams 也允许开发人员将流的数据保存在内存中。也就是说,在 DStream 上使用 persist ()方法将自动地在内存中保存该DStream的每个RDD,如果 DStream 中的数据将被多次计算(例如,对同一数据进行多次操作) ,对于基于窗口的操作这将非常有用。,如 reduceByWindow 和 reduceByKeyAndWindow,以及基于状态的操作,如 updateStateByKey,这是隐式的。因此,基于窗口的操作生成的 DStreams 会自动保存在内存中,而不需要开发人员调用 persist ()。
对于通过网络接收数据的输入流(例如 Kafka、 sockets 等) ,默认的持久性级别被设置为将数据复制到两个节点以实现容错。
请注意,与 RDDs 不同,DStreams 的默认持久性级别将数据序列化在内存中。这个问题将在《性能调优部分进一步讨论。有关不同持久性级别的更多信息,请参见《spark编程指南》。
2、Checkpointing 检查点
流式应用程序必须全天候运行,因此必须对与应用程序逻辑无关的故障(例如,系统故障、 JVM 崩溃等)具有恢复的能力。为了实现这一点,Spark Streaming 需要向容错存储系统提供足够的检查点信息,以便能够从故障中恢复。有两种类型的数据进行检查。
- Metadata checkpointing - 将定义流计算的信息保存到容错存储器,如 HDFS。这用于从运行流应用程序的驱动程序的节点的失败中恢复(稍后将详细讨论)。元数据包括:
- Configuration 用于创建流应用程序的配置
- DStream operations -定义流式应用程序的一组 DStream 操作
- Incomplete batches - 工作已排队但尚未完成的批次
- Data checkpointing - 保存生成的rdd到可靠的存储。在一些跨多个批组合数据的有状态转换中,这是必要的。在这种转换中,生成的rdd依赖于以前批次的rdd,这导致依赖链的长度随着时间不断增加。为了避免恢复时间的无限增长(与依赖链成正比),有状态转换的中间rdd会定期被检查到可靠的存储(例如HDFS),以切断依赖链。
总之,元数据检查点主要用于从驱动程序故障中恢复,而数据或 RDD 检查点甚至在使用有状态转换的情况下对于基本功能都是必要的。
2.1、When to enable Checkpointing 何时启用检查点
对于具有以下任何需求的应用程序,必须启用检查点:
- Usage of stateful transformations-如果在应用程序中使用了updateStateByKey或reduceByKeyAndWindow(带有逆函数),那么必须提供检查点目录以允许定期的RDD检查点。
- 从运行应用程序的驱动程序的故障中恢复-元数据检查点用于使用进度信息进行恢复。
注意,没有上述有状态转换的简单流应用程序可以在不启用检查点的情况下运行。在这种情况下,来自驱动程序故障的恢复也将是部分的(一些收到但未处理的数据可能会丢失)。这通常是可以接受的,很多应用程序都是这样运行的。对非hadoop环境的支持有望在未来得到改善。
2.2、How to configure Checkpointing 如何配置检查点
检查点可以通过在容错、可靠的文件系统(例如 HDFS、 S3等)中设置一个目录来启用,检查点信息将保存到该目录中。这是通过使用 streamingContext.checkpoint (checkpointDirectory)完成的。这将允许您使用前面提到的有状态转换。此外,如果希望使应用程序从驱动程序故障中恢复,则应该重写流应用程序,使其具有以下行为。
- 当程序首次启动时,它将创建一个新的 StreamingContext,设置所有的流,然后调用 start ()
- 当程序在失败后重新启动时,它将从检查点目录中的检查点数据重新创建 StreamingContext
通过使用 StreamingContext.getOrCreate,可以简化此行为。
// Function to create and setup a new StreamingContext
def functionToCreateContext(): StreamingContext = {
val ssc = new StreamingContext(...) // new context
val lines = ssc.socketTextStream(...) // create DStreams
...
ssc.checkpoint(checkpointDirectory) // set checkpoint directory
ssc
}
// Get StreamingContext from checkpoint data or create a new one
val context = StreamingContext.getOrCreate(checkpointDirectory, functionToCreateContext _)
// Do additional setup on context that needs to be done,
// irrespective of whether it is being started or restarted
context. ...
// Start the context
context.start()
context.awaitTermination()
如果 checkpointDirectory 存在,那么将从检查点数据重新创建context 。如果目录不存在(即,第一次运行) ,那么将调用函数 functionToCreateContext 来创建新的context 并设置 DStreams。参见 Scala 示例 RecoverableNetworkWordCount。此示例将网络数据的字数追加到文件中。
除了使用 getOrCreate 之外,还需要确保驱动程序进程在故障时自动重新启动。这只能由用于运行应用程序的部署基础结构来完成。这将在部署一节中进一步讨论。
注意,rdd 的检查点会导致节省到可靠存储的成本。这可能会导致 rdd 被检查的那些批处理时间的增加。因此,检查点的间隔需要小心设置。在小批量情况下(比如1秒钟) ,检查点可以显著降低操作的吞吐量。相反,过于频繁的检查点会导致沿袭和任务大小增加,这可能会产生不利影响。对于需要 RDD 检查点的有状态转换,默认间隔是至少为10秒的批间隔的倍数。可以通过使用 dstream.checkpoint (checkpointInterval)来设置它。通常,DStream 的检查点间隔为5-10个滑动间隔是一个很好的尝试设置。
3、Accumulators, Broadcast Variables, and Checkpoints 累加器、广播变量和检查点
在 Spark Streaming 中,累加器和广播变量无法从检查点恢复。如果您启用检查点并使用 accumulator 或 Broadcast 变量,那么您必须为 accumulator 和 Broadcast 变量创建延迟实例化的单例实例,以便在驱动程序失败后重新启动它们时重新实例化它们。下面的示例显示了这一点。
object WordExcludeList {
@volatile private var instance: Broadcast[Seq[String]] = null
def getInstance(sc: SparkContext): Broadcast[Seq[String]] = {
if (instance == null) {
synchronized {
if (instance == null) {
val wordExcludeList = Seq("a", "b", "c")
instance = sc.broadcast(wordExcludeList)
}
}
}
instance
}
}
/**
* Use this singleton to get or register an Accumulator.
*/
object DroppedWordsCounter {
@volatile private var instance: LongAccumulator = null
def getInstance(sc: SparkContext): LongAccumulator = {
if (instance == null) {
synchronized {
if (instance == null) {
instance = sc.longAccumulator("DroppedWordsCounter")
}
}
}
instance
}
}
/**
* Counts words in text encoded with UTF8 received from the network every second. This example also
* shows how to use lazily instantiated singleton instances for Accumulator and Broadcast so that
* they can be registered on driver failures.
*
* Usage: RecoverableNetworkWordCount <hostname> <port> <checkpoint-directory> <output-file>
* <hostname> and <port> describe the TCP server that Spark Streaming would connect to receive
* data. <checkpoint-directory> directory to HDFS-compatible file system which checkpoint data
* <output-file> file to which the word counts will be appended
*
* <checkpoint-directory> and <output-file> must be absolute paths
*
* To run this on your local machine, you need to first run a Netcat server
*
* `$ nc -lk 9999`
*
* and run the example as
*
* `$ ./bin/run-example org.apache.spark.examples.streaming.RecoverableNetworkWordCount \
* localhost 9999 ~/checkpoint/ ~/out`
*
* If the directory ~/checkpoint/ does not exist (e.g. running for the first time), it will create
* a new StreamingContext (will print "Creating new context" to the console). Otherwise, if
* checkpoint data exists in ~/checkpoint/, then it will create StreamingContext from
* the checkpoint data.
*
* Refer to the online documentation for more details.
*/
object RecoverableNetworkWordCount {
def createContext(ip: String, port: Int, outputPath: String, checkpointDirectory: String)
: StreamingContext = {
// If you do not see this printed, that means the StreamingContext has been loaded
// from the new checkpoint
println("Creating new context")
val outputFile = new File(outputPath)
if (outputFile.exists()) outputFile.delete()
val sparkConf = new SparkConf().setAppName("RecoverableNetworkWordCount")
// Create the context with a 1 second batch size
val ssc = new StreamingContext(sparkConf, Seconds(1))
ssc.checkpoint(checkpointDirectory)
// Create a socket stream on target ip:port and count the
// words in input stream of \n delimited text (e.g. generated by 'nc')
val lines = ssc.socketTextStream(ip, port)
val words = lines.flatMap(_.split(" "))
val wordCounts = words.map((_, 1)).reduceByKey(_ + _)
wordCounts.foreachRDD { (rdd: RDD[(String, Int)], time: Time) =>
// Get or register the excludeList Broadcast
val excludeList = WordExcludeList.getInstance(rdd.sparkContext)
// Get or register the droppedWordsCounter Accumulator
val droppedWordsCounter = DroppedWordsCounter.getInstance(rdd.sparkContext)
// Use excludeList to drop words and use droppedWordsCounter to count them
val counts = rdd.filter { case (word, count) =>
if (excludeList.value.contains(word)) {
droppedWordsCounter.add(count)
false
} else {
true
}
}.collect().mkString("[", ", ", "]")
val output = s"Counts at time $time $counts"
println(output)
println(s"Dropped ${droppedWordsCounter.value} word(s) totally")
println(s"Appending to ${outputFile.getAbsolutePath}")
Files.append(output + "\n", outputFile, Charset.defaultCharset())
}
ssc
}
def main(args: Array[String]): Unit = {
if (args.length != 4) {
System.err.println(s"Your arguments were ${args.mkString("[", ", ", "]")}")
System.err.println(
"""
|Usage: RecoverableNetworkWordCount <hostname> <port> <checkpoint-directory>
| <output-file>. <hostname> and <port> describe the TCP server that Spark
| Streaming would connect to receive data. <checkpoint-directory> directory to
| HDFS-compatible file system which checkpoint data <output-file> file to which the
| word counts will be appended
|
|In local mode, <master> should be 'local[n]' with n > 1
|Both <checkpoint-directory> and <output-file> must be absolute paths
""".stripMargin
)
System.exit(1)
}
val Array(ip, IntParam(port), checkpointDirectory, outputPath) = args
val ssc = StreamingContext.getOrCreate(checkpointDirectory,
() => createContext(ip, port, outputPath, checkpointDirectory))
ssc.start()
ssc.awaitTermination()
}
}