【Spark内存计算框架】SparkStreaming调优策略

007SparkStreaming


SparkStream的核心抽象是DStream
调优策略:
Sparkstreaming+kafka,用不到receiver,选择direct方式

  1. 基于receiver
  2. 基于direct
    shuffle上游
    shuffle下游
  3. 调整数据处理的并行度(task)
  4. 数据的序列化
    SparkStreaming两种需要序列化的数据:
    a. 输入的数据:默认是以StorageLevel.MEMORY_AND_DISK_SER_2的形式存储在executor上的内存中
    b. 缓存的数据:默认是以StorageLevel.MEMORY_ONLY_SER的形式存储的内存中
    使用Kryo序列化机制,比Java序列化机制性能好
val conf = new SparkConf().setMaster(...).setAppName(...)
conf.set("spark.serializer", "org.apache.spark.serializer.KryoSerializer")
conf.registerKryoClasses(Array(classOf[MyClass1], classOf[MyClass2]))
val sc = new SparkContext(conf)
  1. 内存调优
    (1)需要内存大小
    和transformation的类型有关,如果使用的是updateStateByKey,Window这样的算子,那么内存就要设置得偏大
    (2)数据存储级别
    如果把接收到的数据设置的存储级别是MEMORY_DISK这种级别,也就是说如果内存不够可以把数据存储到磁盘上,其实性能还是不好的,性能最好的就是所有的数据都在内存里面,所以如果在资源允许的情况下,把内存调大一点,让所有的数据都存在内存里面。

  2. output性能
    数据存储到,mysql、redis/codis、hbase、kafka->sparkstreaming(实时ETL)->kafka
    工作中遇到过的问题
    两个kafka集群,一个是0.8版本的,一个是1.0版本,写了一个sparkstreaming程序将数据处理完了通过foreachRDD然后读到每个分区,写回0.8kafka。数据处理很慢,经常会受到延时告警
    1.0kafka内部有批处理提交功能
    0.8kafka没有批量处理功能,需要手动实现批量提交

  3. Backpressure(压力反馈)
    Spark1.5版本spark.streaming.backpressure.enabled = true
    有点问题是:会对kafka限制数据接收的速率,导致kafka数据积压,然后不实时了。

  4. Elastic Scaling(资源动态分配)
    稳定高效(解决不了数据倾斜的问题)
    动态分配资源:
    批处理动态的决定这个application中需要多少个Executors:
    1.当一个Executor空闲的时候,将这个Executor杀掉
    2.当task太多的时候,动态的启动Executors
    Streaming分配Executor的原则是比对 process time / batchInterval 的比率,如果延迟了,那么就自动增加资源
    从Spark2.0有这个功能: spark.streaming.dynamicAllocation.enabled = true

  5. 数据倾斜调优(重要)
    SparkStreaming底层就是RDD,SparkCore的所有数据倾斜调优策略都适合于SparkStreaming。

以下并不重要(除非你们用到了)

  1. 调整BlockReceiver的数量
object MultiReceiverNetworkWordCount {
  def main(args: Array[String]) {
    val sparkConf = new SparkConf().setAppName("WordCount")
    val sc = new SparkContext(sparkConf)
    // Create the context with a 1 second batch size
    val ssc = new StreamingContext(sc, Seconds(5))

    //创建多个接收器(ReceiverInputDStream),这个接收器接收一台机器上的某个端口通过socket发送过来的数据并处理
    val lines1 = ssc.socketTextStream("master", 9998, StorageLevel.MEMORY_AND_DISK_SER)
    val lines2 = ssc.socketTextStream("master", 9997, StorageLevel.MEMORY_AND_DISK_SER)
    val lines = lines1.union(lines2)
    lines.repartition(100)

    //处理的逻辑,就是简单的进行word count
    val words = lines.repartition(100).flatMap(_.split(" "))
    val wordCounts = words.map(x => (x, 1)).reduceByKey((a: Int, b: Int) => a + b, new HashPartitioner(10))

    //将结果输出到控制台
    wordCounts.print()
    //启动Streaming处理流
    ssc.start()
    //等待Streaming程序终止
    ssc.awaitTermination()
    ssc.stop(false)
  }
}
  1. 调整Block的数量
    batchInterval : 触发批处理的时间间隔
    blockInterval :将接收到的数据生成Block的时间间隔,spark.streaming.blockInterval(默认是200ms),那么,BlockRDD的分区数 = batchInterval / blockInterval,即一个Block就是RDD的一个分区,就是一个task
    比如,batchInterval是2秒,而blockInterval是200ms,那么task数为10,如果task的数量太少,比一个executor的core数还少的话,那么可以减少blockInterval,blockInterval最好不要小于50ms,太小的话导致task数太多,那么launch task的时间久多了
  2. 调整Receiver的接收速率 QPS
    pps:permits per second 每秒允许接受的数据量(QPS -> queries per second)
    Spark Streaming默认的PPS是没有限制的,可以通过参数spark.streaming.receiver.maxRate来控制,默认是Long.Maxvalue
  3. 调整数据处理的并行度
    BlockRDD的分区数
    a. 通过Receiver接受数据的特点决定
    b. 也可以自己通过repartition设置
    ShuffleRDD的分区数
    a. 默认的分区数为spark.default.parallelism(core的大小)
    b. 通过我们自己设置决定
val wordCounts = words.map(x => (x, 1)).reduceByKey((a: Int, b: Int) => a + b, new HashPartitioner(10))
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值