Spark Streaming介绍
Spark Streaming是一个实时流处理计算平台,主要是针对流式数据进行统计分析。
Spark Streaming是针对流数据处理的框架,它的底层实现基于Spark Core,也有 Spark Core的相关概念,比如RDD的容错性,在Spark Streaming中,它的底层其实就在RDD上面实现了一种封装,将之前处理的RDD概念,转换成流的概念(DStream)
流处理组件:
对比 | 延迟性 | 吞吐量 | 计算方式 | 扩展性 | 使用率 |
---|---|---|---|---|---|
SparkStreaming | 低延迟 | 高 | 离线+实时 | 图计算/机器学习 | 频繁 |
Flink | 无 | 高 | 离线+实时 | 图计算/机器学习 | 居多 |
Storm | 无 | 低 | 实时 | 不支持 | 历史抛弃 |
实时流
Spark Streaming 基本工作原理
入门案例
注意:在本地进行测试跑任务的时候,要设置执行的批次时间间隔(Seconds(5)),并且线程数一定要大于等于2(“local[2]”),不能少于两个线程,如果少于两个线程,会发生没有数据结果的情况,这样统计没有意义,防止饥饿情况
SparkStreaming基本操作
输出方法:
Output Operation | Meaning |
---|---|
print() | 在运行流应用程序的 driver 节点上的DStream中打印每批数据的前十个元素。这对于开发和调试很有用。 |
Python API 这在 Python API 中称为 pprint()。 | |
saveAsTextFiles(prefix, [suffix]) | 将此 DStream 的内容另存为文本文件。每个批处理间隔的文件名是根据 前缀 和 后缀:"prefix-TIMEIN_MS[.suffix]"_ 生成的。 |
saveAsObjectFiles(prefix, [suffix]) | 将此 DStream 的内容另存为序列化 Java 对象的 SequenceFiles 。每个批处理间隔的文件名是根据 前缀 和 后缀:"prefix-TIMEIN_MS[.suffix]"_ 生成的。 |
Python API 这在Python API中是不可用的。 | |
saveAsHadoopFiles(prefix, [suffix]) | 将此 DStream 的内容另存为 Hadoop 文件。每个批处理间隔的文件名是根据 前缀 和 后缀:"prefix-TIMEIN_MS[.suffix]"_ 生成的。 |
Python API 这在Python API中是不可用的。 | |
foreachRDD(func) | 对从流中生成的每个 RDD 应用函数 func 的最通用的输出运算符。此功能应将每个 RDD 中的数据推送到外部系统,例如将 RDD 保存到文件,或将其通过网络写入数据库。请注意,函数 func 在运行流应用程序的 driver 进程中执行,通常会在其中具有 RDD 动作,这将强制流式传输 RDD 的计算。 |
转换方法:
Transformation(转换) | Meaning(含义) |
---|---|
map(func) | 利用函数 func 处理原 DStream 的每个元素,返回一个新的 DStream。 |
flatMap(func) | 与 map 相似,但是每个输入项可用被映射为 0 个或者多个输出项。。 |
filter(func) | 返回一个新的 DStream,它仅仅包含原 DStream 中函数 func 返回值为 true 的项。 |
repartition(numPartitions) | 通过创建更多或者更少的 partition 以改变这个 DStream 的并行级别(level of parallelism)。 |
union(otherStream) | 返回一个新的 DStream,它包含源 DStream 和 otherDStream 的所有元素。 |
count() | 通过 count 源 DStream 中每个 RDD 的元素数量,返回一个包含单元素(single-element)RDDs 的新 DStream。 |
reduce(func) | 利用函数 func 聚集源 DStream 中每个 RDD 的元素,返回一个包含单元素(single-element)RDDs 的新 DStream。函数应该是相关联的,以使计算可以并行化。 |
countByValue() | 在元素类型为 K 的 DStream上,返回一个(K,long)pair 的新的 DStream,每个 key 的值是在原 DStream 的每个 RDD 中的次数。 |
reduceByKey(func, [numTasks]) | 当在一个由 (K,V) pairs 组成的 DStream 上调用这个算子时,返回一个新的,由 (K,V) pairs 组成的 DStream,每一个 key 的值均由给定的 reduce 函数聚合起来。注意:在默认情况下,这个算子利用了 Spark 默认的并发任务数去分组。你可以用 numTasks 参数设置不同的任务数。 |
join(otherStream, [numTasks]) | 当应用于两个 DStream(一个包含(K,V)对,一个包含 (K,W) 对),返回一个包含 (K, (V, W)) 对的新 DStream。 |
cogroup(otherStream, [numTasks]) | 当应用于两个 DStream(一个包含(K,V)对,一个包含 (K,W) 对),返回一个包含 (K, Seq[V], Seq[W]) 的 tuples(元组)。 |
transform(func) | 通过对源 DStream 的每个 RDD 应用 RDD-to-RDD 函数,创建一个新的 DStream。这个可以在 DStream 中的任何 RDD 操作中使用。 |
updateStateByKey(func) | 返回一个新的 “状态” 的 DStream,其中每个 key 的状态通过在 key 的先前状态应用给定的函数和 key 的新 valyes 来更新。这可以用于维护每个 key 的任意状态数据。 |
操作输出方法或者转换方法,其实内部都是在操作RDD,比如我们调用的foreachRDD,它就将我们的数据流,转换为RDD进行执行,完成数据结果输出,只不过是在流的内部完成的转换操作将RDD转回DStream,最后结果输出还是一个批次流
DStream(离散流)
它是SparkStreaming的数据抽象,一个批次会产生多个DStream,这点和RDD类似,同时在使用DStream的时候,其实底层会转换RDD操作,DStream操作,其实就是RDD在转换操作,SparkStreaming是一个准实时(秒级延迟)候流处理的计算引擎,达不到实时处理状态。
SparkStreaming对接Kafka(重点)
使用Kafka010版本后,我们Kafka内部自动维护Offset,看起来不错,主要Kafka不出问题,一切都没问题,但是你不能保证Kafka不会出现宕机情况,假如Kafka一旦出现宕机情况,那么你的Offset没法维护到Kafka内部,如果再次重启Kafka集群后,没有接收到上次提交的Offset,SparkStreaming再次消费数据的时候,就会发生数据重复消费的情况,这种情况是一定不允许,此时,我们需要将自动提交偏移量修改成false,找一个地方保存当前Offset,下次消费不去维护KafkaOffset,直接维护第三方保存Offset的数据库或者其他存储位置,这样就不会发生数据重复消费的情况。
对接kafka有两种方式:
1. Receiver:
优点:数据安全
缺点:Receiver方式会有一个WAL机制,会将预读取kafka上的数据,并将数据写入磁盘,虽然保证数据安全,但是不符合实时流计算的概念。
2. Direct(直连方式)
优点:效率高
缺点:需要自己配置offset偏移量保存的位置,可以保存再redis
可以配置序列化方式:使用Spark内部的序列化方式,默认的是Java序列化方式
.set("spark.serializer","org.apache.spark.serializer.KryoSerializer")
数据累加操作(UpdateStateByKey和MapWithState)了解
UpdateStateByKey:
可以对每批次的结果进行累加操作,得到每次的结果总数据集
统计全局的key的状态,但是就算没有数据输入,他也会在每一个批次的时候返回之前的key的状态。
这样的缺点:如果数据量太大的话,我们需要checkpoint数据会占用较大的存储。而且效率也不高
mapWithState:
也是用于全局统计key的状态,但是它如果没有数据输入,便不会返回之前的key的状态,有一点增量的感觉。
这样做的好处是,我们可以只是关心那些已经发生的变化的key,对于没有数据输入,则不会返回那些没有变化的key的数据。这样的话,即使数据量很大,checkpoint也不会像updateStateByKey那样,占用太多的存储。