Spark Streaming性能调优

膜拜大佬,转载记录一下

数据接收并行度调优

  1. Receiver并行化接收数据
    每一个输入DStream都会在某个Worker的Executor上启动一个Receiver,可以创建多个输入DStream,并且配置它们接收数据源不同的分区数据,达到接收多个数据流的效果。
    比如,一个接收两个Kafka Topic的输入DStream,可以被拆分为两个输入DStream,每个分别接收一个topic的数据。多个DStream可以使用union算子进行聚合,从而形成一个DStream。后续使用transformation算子操作

    int numStreams = 5;
    List<JavaPairDStream<String, String>> kafkaStreams = new ArrayList<JavaPairDStream<String, String>>(numStreams);
    for (int i = 0; i < numStreams; i++) {
      kafkaStreams.add(KafkaUtils.createStream(...));
    }
    JavaPairDStream<String, String> unifiedStream = streamingContext.union(kafkaStreams.get(0), kafkaStreams.subList(1, kafkaStreams.size()));
    unifiedStream.print();
    复制代码
  2. 调节block interval
    spark.streaming.blockInterval:设置block interval,默认是200ms
    对于大多数Receiver来说,在将接收到的数据保存到Spark的BlockManager之前,都会将数据切分为一个一个的block。而每个batch中的block数量,则决定了该batch对应的RDD的partition的数量,以及针对该RDD执行transformation操作时,创建的task的数量。每个batch对应的task数量是大约估计的,即task ≈ batch interval / block interval,比如batch interval为2s,block interval为200ms,则创建10个task
    调优目的是让batch的task数量大于每台机器的cpu core数量,尽量利用cpu core,推荐task数量是cpu core数量的2~3倍

    如果集群中有多个spark程序在跑,应该设置成所有应用的task数量总和是cpu core数量的2~3倍

    推荐的block interval最小值是50ms,如果低于这个数值,那么大量task的启动时间,可能会变成一个性能开销点。

  3. 重分区
    inputStream.repartition(<number of partitions>):可以将接收到的batch分布到指定数量的机器上再操作。

任务启动调优

发送task去Worker节点上的Executor的有延迟,耗时

  1. Task序列化:使用Kryo序列化机制来序列化task,可以减小task的大小,从而减少发送这些task到各个Worker节点上的Executor的时间

官网上并未提出这一点

  1. 执行模式:在Standalone/ coarse-grained Mesos模式下运行Spark,比fine-grained Mesos 模式有更少的task启动时间

These changes may reduce batch processing time by 100s of milliseconds

数据处理并行度调优

让在stage中使用的并行task的数量足够多,充分利用集群资源
如reduce,默认的并行task的数量是由spark.default.parallelism决定,为全局变量;也可以手动指定该操作的并行度

数据序列化调优

两种场景会序列化

  1. 默认情况下,接收到的输入数据,是存储在Executor的内存中的,使用的持久化级别是StorageLevel.MEMORY_AND_DISK_SER_2,Receiver反序列化从网络接收到的数据,再使用Spark的序列化格式序列化数据
  2. 流式计算操作生成的持久化RDD会持久化到内存中,默认持久化级别是StorageLevel.MEMORY_ONLY_SER

优化
目标:减少用于序列化和反序列化的CPU性能开销和GC开销

  1. 使用Kryo序列化
  2. 禁止序列化:数据总量并不是很多,可以将数据以非序列化的方式进行持久化

batch interval调优

batch处理时间(可以通过观察Spark UI上的batch处理时间)必须小于batch interval时间,否则会堆积数据
由于临时性的数据增长导致的暂时的延迟增长是合理的,只要延迟情况可以在短时间内恢复即可

内存调优

增大内存

在窗口时间内通过Receiver接收到的数据,会使用StorageLevel.MEMORY_AND_DISK_SER_2持久化级别来进行存储,因此无法保存在内存中的数据会溢写到磁盘上,会降低应用性能

另外,若窗口操作中要使用大量 keys 的updateStateByKey,同样会消耗大量内存

垃圾回收

  1. DStream的持久化
    输入数据和某些操作生产的中间RDD,默认持久化时都会序列化为字节,可以使用Kryo序列化,也可以设置spark.rdd.compress=true压缩数据,代价是 CPU 时间
  2. 清理旧数据
    默认隔一段时间会清理数据,如按窗口时间长度清理,可以使用streamingContext.remember()延长清理时间,以便给其他操作使用数据
  3. CMS垃圾回收器
    并行的GC会降低吞吐量,但GC低开销,减少batch的处理时间
    • driver端
      spark-submit中使用--driver-java-options:-XX:+UseConcMarkSweepGC
    • executor端
      spark.executor.extraJavaOptions:-XX:+UseConcMarkSweepGC
  4. 其他
    使用 OFF_HEAP 存储级别的保持 RDDs
    使用更小的 heap sizes 的 executors.这将降低每个 JVM heap 内的 GC 压力

作者:fengye
链接:https://juejin.cn/post/6844903567405350920
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
posted @ 2021-01-22 14:40  白给大队队长  阅读(248)  评论(0)    收藏  举报
复制代码