Spark Streaming
spark stream是流式计算框架,支持可扩展,高吞吐量,容错的准实时
的数据流处理.
1.SparkStreaming与storm的区别
- Storm是实时的流式处理框架,SparkStreaming是准实时的处理框架(微批处理),因为是微批处理,所以SparkStreaming的吞吐量比Storm高
- Storm的事务机制要相对完善
- Storm支持动态资源调度(spark1.2之后也支持)
- Sparkstreaming擅长处理复杂的业务处理,storm相比较不擅长,更擅长简单的汇总型计算
2.sparkStreaming的内部执行
- 要点注意
- receive task是7*24小时在执行,一直接受数据.讲一段时间内接收到的数据保存到一个batch中,可以设置batchInterval的时间,那么会将接收过来的数据按照设置的时间封装到一个batch中,batch是没有分布式计算的,这一个batch又被封装到一个RDD中,然后在封装到一个Dstream中.
- 计算job的时间大于batchInterval的时间会以下问题
- 如果接收过来的数据设置的级别仅是内存,那么就会形成数据堆积,最后导致OOM,
- 如果数据设置的级别包含disk,则内存存放不下的数据会溢写到diak中,加大延迟
3.SparkStreaming 算子
- output operation算子
- foreachRDD
- 对抽取出来的RDD执行action类算子
- foreachRDD
- transformation类算子
- transform
- 对Dstream做RDD到RDD的任意操作
- updateStateByKey
- 为sparkstreaming中的每一个Key维护一个state状态,state类型可以是任何类型的,也可以是一个自定义对象,更新函数也可以是自定义的
- 通过更新函数来对key进行不断的更新,对于每个新的batch而言,sparkStreaming会使用updateStateBykey为已经存在的key进行state的状态进行更新
- 使用updateStateByKey要开启checkpoint机制和功能
- 多长时间会将内存中的数据写入的磁盘中
- 如果batchInterval设置的时间小于10秒,那么10秒写入一次
- 如果设置的大于10秒,那么就会以设置的时间间隔写入磁盘一份
- transform
- 窗口操作
- 示意图
- 窗口长度和滑动间隔必须要是batchInterval的整数倍,如果不是整数倍会检测报错.
- 优化后的窗口操作示意图
- 优化后的window操作要保存状态,所以要设置checkpoint路径,没有优化的window操作可以不设置checkpoint路径
3.driver的HA(standalone或者是Mesos)
- sparkStreaming是一直不间断的运行中,driver是一个简单的进程,随时会挂掉.所以要设置driver的HA.client模式无法实现HA,只有集群模式可以.yarn模式下的AM相当于driver.挂掉之后master会查询启动,
- 提交代码是假–supervise,当driver挂掉的时候会重新启动
- 使用javastreamingcontext.getorcreat(checkpoint的路径,JavaStreamingContextFactor)
4.SparkStreaming2.2(包含以前)+Kafka0.8之间的整合
- receive模式
- sparkstreaming程序运行后,executor里会有一个receive tasks接收kafka推送过来的数据.
- 根据设置的持久化类型对数据进行备份memory_and_disk_ser_2(2个备份,可以修改),
- 备份ok后,去zookeeper中更新偏移量,然后向driver中的receive tasks发送数据的位置
- 最后driver根据数据本地化将task发送到不同的节点
- receive存在的问题
- 当drvier进程挂掉之后,同样的driver下的executor也会挂掉,当更新zookeeper消费偏移量时,就会存在找不到数据,向当于数据丢失
- 解决办法:
- 开启WAL机制,当数据备份的时候同时提交一份到HDFS上,当driver挂掉重启之后,会自动计算hdfs上遗留下来的数据,虽然它可以解决数据丢失的问题,但是因为是同时将数据放到HDFS上,会造成流计算性能下降,可以改变默认的备份级别来提高一点性能
- 开启WAL机制会照成的问题:
- 数据保存到HDFS上后,要提交偏移量到zookeeper上,但是driver挂了,会导致偏移量提交失败,重启driver之后,会先计算hdfs上面的数据,在读取zookeeper上的偏移量,在读取kafka上面的数据,这时就会造成数据的重复消费.
- receive的并行设置
- 并行度由spark.streaming.blockInterva来决定的,默认为200ms,向提高并行度可以减少它的参数,但是不要低于50ms
- direct模式
- direct模式是将kafka看成存数据的一方,不是被动接受数据,而是主动去拉取数据,消费者偏移量由sparkstreaming内部自己管理,如果设置了checkpoint,那么偏移量也会保存在checkpoint中
- direct模式并行度由读取的kafka中topic的partition决定的
- receive模式&direct模式总结
- receive模式
- 采用了receive接收器模式,需要一个线程一直接收数据,将数据接收到executor中,默认存储级别MEMORY_AND_DISK_SER_2
- 自动使用zookeeper管理消费者offest
- receiver模式底层读取Kafka 采用High Level Consumer API 实现,这种模式不关心offset,只要数据
- receiver模式当Driver挂掉时,有丢失数据问题,可以开启WAL机制 避免丢失数据,但是开启之后加大了数据处理延迟 ,并且存在数据重复消费风险
- receiver模式并行度由spark.streaming.blockInterval = 200ms ,可以减少这个参数增大并行度,最小不能低于50ms
- Receiver模式不被使用
- 被动将数据接收到Executor,当有任务堆积时,数据存储问题
- 这种模式不能手动维护消费者offset
- direct模式
- 有使用receiver接收器模式,每批次处理数据直接获取当前批次数据处理
- 没有使用zookeeper管理消费者offset,使用的是Spark自己管理,默认存在内存中,可以设置checkpoint,也会保存到checkpoint中一份
- 底层读取Kafka使用 Simple Consumer API ,可以手动维护消费者offset
- direct模式并行度 与读取的topic的partition 一一对应
- 可以使用设置checkpoint的方式管理消费者offset, 使用StreamingContext.getOrCreate(ckDir,CreateStreamingContext) 恢复
- 这种方式有两种缺点
- 第一:当代码逻辑改变时,无法从checkpoint中来恢复offse
- 第二:当从checkpoint中恢复数据时,有可能造成重复的消费,需要我们写代码来保证数据的输出幂等
- 这种方式有两种缺点
- 如果代码逻辑改变,就不能使用checkpoint模式管理offset,可以手动维护消费者offset,可以将offset存储到外部系统
- receive模式
5.kafka0.11与kafka0.8的差异
-
kafka0.8
- 消费者offset由zookeeper管理,对于zookeeper来说每次写操作代价很昂贵,而zookeeper集群是不能扩展写能力
-
kafka0.11
-
消费者offset默认使用新的消费者api,offset会更新到kafka的自带的topic中[_consumer_offset],以消费者组groupid为单位,可以查询每一个组的消费情况
-
#查看所有消费者组 ./kafka-consumer-groups.sh --bootstrap-server node1:9092, node2:9092, node3:9092 --list #查看消费者消费的offset位置信息 ./kafka-consumer-groups.sh --bootstrap-server node1:9092, node2:9092, node3:9092 --describe --group MyGroupId #重置消费者组的消费offset信息 ,--reset-offsets –all-topics 所有offset。--to-earliest 最小位置。 # --execute 执行 ./kafka-consumer-groups.sh --bootstrap-server c7node1:9092,c7node2:9092,c7node3:9092 --group MyGroupId --reset-offsets --all-topics --to-earliest --execute
-
6.sparkstreaming2.3+kafka0.11之间的整合
- 丢弃了之前的receiver模式
- 采用了新的消费者api实现,类似于之前Sparkstreaming读取kafka卡的direct模式,并行度一样
- 一般情况下,sparkstreaming读取数据使用locationStrategies.Prefersistent,这种策略会将分区均匀的分布在集群的Executor之间
- 如果executor在kafka的某些节点上,可以使用locationStrategies.PreferBrokers,那么当前这个executor中的数据会来自这个broker节点
- 如果加点明显分布不均,可以使用locationStrategies.preferFixed,可以通过一个map指定topic分区分布在哪些节点上
- 新的消费者api可以将kafka中的数据预读取到缓存区中,默认为64k,默认的缓存区在Executor.可以通过设置参数spark.streaming.kafka.consumer.cache.maxCapacity 来增大,也可以通过spark.streaming.kafka.consumer.cache.enabled 设置成false 关闭缓存机制
- 新的消费者offset
- 设置checkpoint,那么偏移量存储在checkpoint中,
- 当代码逻辑改变时,无法从checkpoint中恢复偏移量
- 当从checkpoint中获取偏移量时,可能会出现重复消费,需要写代码来保证数据的输出幂等.
- 依靠kafka来存储偏移量,kafka中有一个topic来存储消费者offset,在新的消费者api中,偏移量会定期自动提交,自动提交offset的频率由参数auto.commit.interval.ms来决定,默认为5s,为了数据的精确性,可以改为异步手动提交
- offset存储在kafka中由参数offsets.retention.minutes=1440控制是否过期删除,默认是保存一天,如果停机没有消费达到时长,存储在kafka中的消费者组会被清空,offset也就被清除了
- 无法保证有且只有一次语义,因为偏移量的提交是异步的,所有若结果的输出依然要自己实现幂等性。
s.retention.minutes=1440控制是否过期删除,默认是保存一天,如果停机没有消费达到时长,存储在kafka中的消费者组会被清空,offset也就被清除了 - 无法保证有且只有一次语义,因为偏移量的提交是异步的,所有若结果的输出依然要自己实现幂等性。
- 自己存储offset,这样在处理逻辑时,保证数据处理的事务,如果处理数据失败,就不保存offset,处理数据成功则保存offset.这样可以做到精准的处理一次处理数据
- 设置checkpoint,那么偏移量存储在checkpoint中,