sparkstreaming数据丢失和重复消费问题

sparkstreaming优化总结

一方面关于数据丢失和重复消费问题

1.数据丢失问题

receiver模式:

(该部分比较简单,可以跳过)

丢失原因:

首先,receiver task 接收 kafka 中的数据,并备份到其他 executor 中的blockmanager里,然后将偏移量提交给 zookeeper ,接着 存在备份的 executor 将数据的地址封装并发送到 driver 中的 receiver tracker,然后由 driver 发送 task ,以及监测任务执行和回收结果。

在这个过程中,如果数据已经提交到了 zookeeper ,此时,driver 挂了,executor 也会被 kill 掉,当 driver 重启时,内存中就没有数据的地址信息了,而且kafka 会从新的偏移量处发送数据,即发生数据丢失。

解决方案:

开启 WAL 机制,在数据备份的时候,同时将数据拷贝一份到 hdfs ,等数据备份完成之后,再提交偏移量。同时,driver启动时,如果 hdfs 上存在未消费的数据,则先消费该数据。

这样,即使zookeeper 提交偏移量之后 driver 挂了,当driver重启之后,依旧能从hdfs 上消费数据。

存在问题:

开启WAL机制可能导致数据重复消费等问题。

direct模式:

sparkstreaming 2.2 direct 模式采用的是kafka的 simple consumer api,该情况下,偏移量可以手动管理,只要保证数据都消费之后再提交偏移量,就不存在数据丢失问题。

2.数据重复消费问题:

receiver模式:

原因:

开启 WAL 机制后,如果数据成功备份到 hdfs 之后,driver 挂了,此时偏移量还未提交给 zookeeper,重启时,

driver会先消费 hdfs 中的数据,由于偏移量未提交,该数据会再次接收并消费。

解决方案:

以Receiver基于ZooKeeper的方式,当读取数据时去访问Kafka的元数据信息,在处理代码中例如foreachRDD或
transform时,将信息写入到内存数据库中(memorySet)
,在计算时读取内存数据库信息,判断是否已处理过,如果以处理过则跳过计算。这些元数据信息可以保存到内存数据结构或者memsql,sqllite中。

direct模式:

原因

偏移量手动提交到 redis ,这种情况下,当数据处理完成之后,还未提交偏移量,此时如果发生故障,则会导致数据重复消费。

解决方案

通过事务控制,如写一个 jdbc 事务。将业务逻辑,偏移量的提交放在一个事务中。

val fromOffsets = selectOffsetsFromYourDatabase.map { resultSet =>
  new TopicPartition(resultSet.string("topic"), resultSet.int("partition")) -> resultSet.long("offset")
}.toMap

val stream = KafkaUtils.createDirectStream[String, String](
  streamingContext,
  PreferConsistent,
  Assign[String, String](fromOffsets.keys.toList, kafkaParams, fromOffsets)
)

stream.foreachRDD { rdd =>
  val offsetRanges = rdd.asInstanceOf[HasOffsetRanges].offsetRanges

  val results = yourCalculation(rdd)

  // begin your transaction

  // update results
  // update offsets where the end of existing offsets matches the beginning of this batch of offsets
  // assert that offsets were updated correctly

  // end your transaction
}

3.其他优化点

1.采用 direct 模式代替 receiver 模式,在数据堆积、处理延迟、偏移量管理等的问题上direct 模式更具优势。

2.基于sparkcore优化。

增加并行度;采用 Kryo 序列化机制,流失计算生成RDD可能会持久化到内存,默认持久化级别是memory_only_ser,默认就会减少GC开销;采用 CMS垃圾回收器降低 GC 开销 ;选择高性能的算子(mapPartitions,foreachPartitions,aggregateByKey等);3.repartition的使用

由于sparkstreaming程序中一批数据量一般较小,repartition 的时间短,可以解决一些由于 topicpartition中数据分配不均匀导致的数据倾斜问题。

4.任务启动优化
如果每一秒钟启动的task数量太多,假设50个,即1s的batch时间间隔和50ms的block时间间隔。如果发送这些task去worker上的executor,那么性能开销会比较大,这是很难到到毫秒级的延迟了。

4.1task序列化
使用Kryo序列化类库来序列化task,可以减小task的大小从而减少driver发送这些task到各个executor的发送时间,即节省网络资源

4.2 执行模式
在standalone模式下运行spark,可以达到更少的task启动时间

5.batch时间间隔优化
batch应该在生成之后就尽可能块的处理掉,对于一个应用来说,可以通过观察Spark UI上batch的处理时间来定。batch的处理时间必须小于batch 时间间隔,假设batch 时间间隔1s, 那么这个批次的处理时间不应超过1s

为应用计算正确batch比较好的办法:

给定一个很保守的batch interval,比如5s-10s,以很慢的数据接受速率进行测试,要检查应用是否你跟的上这个数据接收速率,可以检查每一个batch的处理时间的延迟,如果处理时间与batch interval基本吻合,那么应用就是稳定的,否则如果batch调度延迟持续增长,那么就意味着应用无法跟得上这个速率,也就是不稳定的。记住,由于临时性的数据增长导致的暂时的延迟增长,可以合理的,只要延迟情况可以在短时间内恢复即可。

6.内存调优
如果想要使用一个窗口长度为10分钟的window操作,那么集群就必须有足够的内存来保存10分钟内的数据。如果想要使用updateStateByKey来维护许多key的state,那么你的内存资源就必须足够大。反过来说,如果想要做一个简单的map-filter-store操作,那么需要使用的内存就很少。

通常来说,通过Receiver接收到的数据,会使用MEMORY_AND_DISK_SER_2持久化级别来进行存储,因此无法保存在内存中的数据会溢写到磁盘上。而溢写到磁盘上,是会降低应用的性能的。因此,通常是建议为应用提供它需要的足够的内存资源。建议在一个小规模的场景下测试内存的使用量,并进行评估。

内存调优的另外一个方面是垃圾回收。对于流式应用来说,如果要获得低延迟,肯定不想要有因为JVM垃圾回收导致的长时间延迟。有很多参数可以帮助降低内存使用和GC开销:

5.1DStream的持久化
默认持久化的时候会序列化为字节,与非序列化的方式相比,这会降低内存和GC开销。使用Kryo序列化机制可以进一步减少内存使用和GC开销。如果还要进一步降低内库存是用了,可以进行数据压缩,spark.rdd.compress参数控制(默认false)。

但是CPU资源的消耗可能就大了。

5.2 清理旧数据
默认情况下,所有输入数据和通过DStreamtransformation操作生成的持久化RDD,会自动被清理。Spark Streaming会决定何时清理这些数据,取决于transformation操作类型。

例如,你在使用窗口长度为10分钟内的window操作,Spark会保持10分钟以内的数据,时间过了以后就会清理旧数据。但是在某些特殊场景下,比如Spark SQL和Spark Streaming整合使用时,在异步开启的线程中,使用Spark SQL针对batch RDD进行执行查询。那么就需要让Spark保存更长时间的数据,直到Spark SQL查询结束。可以使用streamingContext.remember()方法来实现。

5.3CMS垃圾回收器
使用并行的mark-sweep垃圾回收机制,被推荐使用,用来保持GC低开销。虽然并行的GC会降低吞吐量,但是还是建议使用它,来减少batch的处理时间(降低处理过程中的GC开销)。如果要使用,那么要在driver端和executor端都开启。

在spark-submit中使用–driver-java-options设置使spark.executor.extra

JavaOptions参数设置-XX:+UseConcMarkSweepGC。
————————————————
参考链接:https://blog.csdn.net/zhanglh046/article/details/78505192

发布了4 篇原创文章 · 获赞 0 · 访问量 512

猜你喜欢

转载自blog.csdn.net/The_Inertia/article/details/104944349