Spark Streaming官方文档翻译Spark Streaming总览
Spark Streaming官方文档翻译基本概念之初始化与Dstream
Spark Streaming官方文档翻译基本概念之输入数据流和接收器
Spark Streaming官方文档翻译基本概念之转换操作
Spark Streaming官方文档翻译基本概念之输出操作
Spark Streaming官方文档翻译基本概念之sql与Mllib
Spark Streaming官方文档基本概念之缓存与检查点
Spark Streaming官方文档翻译基本概念之累加器、广播变量和检查点
Spark Streaming官方文档翻译Spark Streaming应用之部署,升级,监控
Spark Streaming官方文档翻译Spark Streaming性能调优
Spark Streaming官方文档翻译Spark Streaming容错
Spark Streaming官方文档翻译Spark Streaming +Kafka 集成指南
Spark Streaming官方文档翻译Spark Streaming自定义接收器
容错语义(Fault-tolerance Semantics)
在本节中,我们将讨论Spark Streaming应用程序在发生故障时的行为。
背景(Background)
为了理解Spark Streaming提供的语义,让我们记住Spark RDDs的基本容错语义。
- RDD是一个不可变的、可确定地重新计算,分布式的数据集。每个RDD都会以容错的方式记住输入数据集上创建的确定性操作的血缘关系。
- 如果RDD的任何分区由于工作节点故障而丢失,则可以使用血缘关系从原始容错数据集重新计算该分区。
- 假设所有的RDD转换都是确定的,那么不管Spark集群中的故障如何,最终转换的RDD中的数据总是相同的。
Spark操作容错文件系统(如HDFS或S3)中的数据。因此,从容错数据生成的所有RDDs都是容错的。但是,这与Spark Streaming 的情况不同,因为大多数情况下数据是通过网络接收的(使用fileStream时除外)。要为所有生成的RDDs实现相同的容错属性,需要在集群中工作节点的多个Spark执行器之间复制接收到的数据(默认的复制因子为2)。这将导致系统中有两种数据需要在发生故障时进行恢复:
- 接收和复制的数据——由于单个工作节点的副本存在于其他节点上,所以该数据在单个工作节点失败后仍然存在。
2.收到数据但已缓冲以进行复制(未复制)——由于这不是复制,因此恢复此数据的惟一方法是从源获取它。
此外,有两种失败是我们应该关注的:
- 工作节点失败——运行executor的任何工作节点都可能失败,这些节点上的所有内存数据都将丢失。如果任何接收器在失败的节点上运行,那么它们的缓冲数据将丢失。
- 驱动节点失败——如果运行Spark Streaming应用程序的驱动节点失败,那么很明显,SparkContext丢失了,所有执行器及其内存中的数据都丢失了。
有了这些基础知识,我们就可以理解Spark Streaming的容错语义。
定义(Definitions)
流系统的语义通常根据系统可以处理每个记录的次数来捕获。在所有可能的操作条件下(除了故障等),系统可以提供三种类型的保证。
- 最多一次: 每条记录要么处理一次,要么根本不处理。
- 至少一次:每个记录将被处理一次或多次。这比最多一次强,因为它确保不会丢失任何数据。但是可能有重复的。
- 精确一次:每条记录将被精确处理一次——没有数据会丢失,也没有数据会被多次处理。这显然是三者中最有力的保证。
基本语义(Basic Semantics)
一般来说,在任何流处理系统中,处理数据有三个步骤。
- 接收数据:数据从使用接收器或其他方式的源接收。
- 转换数据:使用DStream和RDD转换操作转换接收的数据。
- 输出数据:最终转换后的数据被发送到外部系统,如文件系统、数据库、仪表板等。
如果流应用程序必须实现端到端的精确一次保证,那么每个步骤必须提供精确一次保证。也就是说,每个记录必须精确地接收一次,精确地转换一次,精确地推送到下游系统一次。让我们在Spark流上下文中理解这些步骤的语义。
- 接收数据:不同的输入源提供不同的保证。这将在下一小节中详细讨论。
- 数据转换:由于RDDs提供的保证,所有接收到的数据都将被精确地处理一次。即使存在故障,只要接收的输入数据是可访问的,最终转换的RDDs将始终具有相同的内容。
- 输出数据:默认情况下,输出操作至少确保一次语义,因为它取决于输出操作的类型(幂等性,或非幂等性)和下游系统的语义(支持或不支持事务)。但是用户可以实现自己的事务机制来实现精确的一次语义。本节后面将更详细地讨论这一点。
接收数据的语义(Semantics of Received Data)
不同的输入源提供不同的保证,从至少一次到正好一次。阅读更多细节。
关于文件(With Files)
如果所有的输入数据都已经存在于HDFS这样的容错文件系统中,那么Spark Streaming始终可以从任何故障中恢复并处理所有的数据。这提供了严格的一次语义,这意味着所有的数据都将被精确地处理一次,无论怎么失败。
Receiver-based来源(Receiver-based来源)
对于基于接收器的输入源,容错语义取决于故障场景和接收器的类型。如前所述,有两种类型的接收器:
- 可靠的接收器–这些接收器只有在确认接收到的数据已被复制后才会向数据源确认。如果这样的接收器失败,源将不会收到缓冲(未复制)数据的确认。因此,如果重新启动接收方,则源将重新发送数据,并且不会因为失败而丢失任何数据。
- 不可靠的接收器–这类接收器不发送确认,因此,当它们由于执行器或驱动程序故障而失败时,可能会丢失数据。
根据所使用的接收器类型,我们可以实现以下语义。如果工作节点失败,那么可靠的接收器就不会丢失数据。对于不可靠的接收器,接收到但没有复制的数据可能会丢失。如果驱动节点失败,那么除了这些丢失之外,所有在内存中接收和复制的过去数据都将丢失。这将影响有状态转换的结果。
为了避免丢失过去接收到的数据,Spark 1.2引入了写前日志(ahead logs),将接收到的数据保存到容错存储中。启用了写前日志和可靠的接收器,数据丢失为零。在语义方面,它至少提供了一次保证。
布署场景 | 执行器失败 | 驱动程序失败 |
---|---|---|
Spark 1.1或更早,或Spark 1.2或更高版本没有提前写日志 | 缓冲数据丢失与不可靠的接收器零数据损失与可靠的接收器至少一次语义 | 缓冲数据丢失与不可靠的接收器过去的数据丢失与所有的接收器未定义的语义 |
Spark 1.2或更高版本的预写日志 | 零数据损失与可靠的接收器至少一次语义 | 零数据丢失与可靠的接收器和文件至少一次语义 |
使用Kafka Direct API(With Kafka Direct API)
在Spark 1.3中,我们引入了一个新的Kafka Direct API,它可以保证所有的Kafka数据被Spark Streaming一次接收。与此同时,如果希望实现精确一次输出操作,就可以实现端到端的精确一次输出保证。Kafka集成指南进一步讨论了这种方法。
输出操作的语义(Semantics of output operations)
输出操作(如foreachRDD)至少具有一次语义,也就是说,在执行器失败的情况下,转换后的数据可能被多次写入外部实体。虽然这对于使用saveAs***Files操作将文件保存到文件系统是可以接受的(因为文件将被相同的数据覆盖),但是为了实现精确的一次语义,可能需要额外的工作。有两种方法。
-
幂等更新:多次尝试总是写入相同的数据。例如,saveAs***文件总是将相同的数据写入生成的文件。
-
事务性更新:所有的更新都是通过事务方式进行的,这样就可以原子性地进行一次更新。一种方法是这样的。
- 使用批处理时间(在foreachRDD中可用)和RDD的分区索引来创建标识符。这个标识符惟一地标识流应用程序中的blob数据。
- 使用标识符以事务方式(即原子方式)更新外部系统。也就是说,如果还没有提交标识符,就自动提交分区数据和标识符。否则,如果已经提交,则跳过更新。
dstream.foreachRDD { (rdd, time) =>
rdd.foreachPartition { partitionIterator =>
val partitionId = TaskContext.get.partitionId()
val uniqueId = generateUniqueId(time.milliseconds, partitionId)
// use this uniqueId to transactionally commit the data in partitionIterator
}
}