Spark Streaming+Kafka+ES使用笔记

emm

非专业开发,一点笔记

Kafka

  1. 当Kafka内容特别大时会报错,此时设置下fetch.message.max.bytes为一个比较大的值就好。
val kafkaParams = Map[String, String]("metadata.broker.list" -> brokers,"fetch.message.max.bytes" -> "10485760" )
  1. 关于partitions
    KafkaDirectStream提供的分片数与Kafka的分片数相同
    如果运算量远远超过了重新分片的消耗,可以用repartition,否则还是增加同时运行的Jobs数量。

Spark Streaming

  1. 增加同时运行的任务数量

SparkStreaming默认只启动一个Job,所以使用核心再多如果任务数量不够的话核心也不能充分利用。

为了提高任务个数需要使用设置spark.streaming.concurrentJobs参数:

spark-submit --conf spark.streaming.concurrentJobs=8 ....

实际上一个Job会分成多个Tasks,每个CPU核心执行一个Task,Task执行完成则Core被释放,也就是说8个partitions的Streaming,使用32个核心并不是只能执行4个Jobs,可以根据Spark WebUI的executor页面核心的使用量,适当的增大concurrentJobs或减少核心使用量。
像我这就是利用率比较低,并且Streaming任务一直跟得上,就可以适当降低Cores的数量。
在这里插入图片描述
2. GC优化
使用CMS内存收集器:

spark-submit --conf "spark.executor.extraJavaOptions=-XX:+UseConcMarkSweepGC" 

自从使用了这个收集器,GC时间下来了,内存也不容易超限了,一口气上五楼都不费劲了~具体原理不清楚,回头补。

  1. 有关cache
    数据有复用的位置一定要记得cache,否则会从头开始执行处理流程。
    被cache的类型需要能够进行序列化。

  2. 有关序列化与反序列化
    Driver会将Task的内容打包序列化发给Executor,所以需要Task中所有被引用的类型都可以序列化。
    如果类型不可序列化则会报object not serializable的错误,此时需要自己实现序列化与反序列化方法,一般只需要实现反序列化方法(readObject)
    scala需要加上serializable注解,java实现serializable接口。

private def readObject(in: ObjectInputStream):Unit = {
		//调用默认的ReadObject函数
        in.defaultReadObject()
        //重新初始化一些无法被序列化的内容
        this.init(this.config_map)
    }

对于无法序列化的属性(Mysql连接、Redis连接等等等)需要在属性前加上transient修饰符,表示在序列化时忽略,然后在readObject中再进行构造。

scala还有一个lazy修饰符,表明使用时再进行构建,所以也可以使用lazy+transient修饰符,让其在使用时重新进行构建。

 @transient lazy val logger:Logger = LogManager.getLogger(this.getClass.getName)

如下例子进行参考,一个包装的Kafka的类:

class KafkaSink[K, V](createProducer: () => KafkaProducer[K, V]) extends Serializable {
  /* This is the key idea that allows us to work around running into
     NotSerializableExceptions. */
  lazy val producer = createProducer()
  def send(topic: String, key: K, value: V): Future[RecordMetadata] =
    producer.send(new ProducerRecord[K, V](topic, key, value))
  def send(topic: String, value: V): Future[RecordMetadata] =
    producer.send(new ProducerRecord[K, V](topic, value))
}

object KafkaSink {
  import scala.collection.JavaConversions._
  def apply[K, V](config: Map[String, Object]): KafkaSink[K, V] = {
    val createProducerFunc = () => {
      val producer = new KafkaProducer[K, V](config)
      sys.addShutdownHook {
        // Ensure that, on executor JVM shutdown, the Kafka producer sends
        // any buffered messages to Kafka before shutting down.
        producer.close()
      }
      producer
    }
    new KafkaSink(createProducerFunc)
  }
  def apply[K, V](config: java.util.Properties): KafkaSink[K, V] = apply(config.toMap)
}

5.广播变量
Task过程中使用的变量每次都会序列化传输一次,如果想验证可以使用上面的方法重写readObject打印一些调试信息进行记录。

而一些长时间不变并且比较大、复杂的内容可以使用广播变量进行保存,保证每个executor只存在一份该变量。

比如 Redis连接、MySQL连接、规则配置什么的就可以使用广播变量。

广播变量包裹的类同样需要能够序列化。

广播变量为只读变量。

详细广播变量的使用可以看如下文章:
https://www.jianshu.com/p/3bd18acd2f7f

  1. 利用广播变量进行配置更新:

详细可以看这篇文章:
https://www.cnblogs.com/liuliliuli2017/p/6782687.html
某个大佬写的包装类:

// This wrapper lets us update brodcast variables within DStreams' foreachRDD
// without running into serialization issues
case class BroadcastWrapper[T: ClassTag](
                                          @transient private val ssc: StreamingContext,
                                          @transient private val _v: T) {

  @transient private var v = ssc.sparkContext.broadcast(_v)

  def update(newValue: T, blocking: Boolean = false): Unit = {
    // 删除RDD是否需要锁定
    v.unpersist(blocking)
    v = ssc.sparkContext.broadcast(newValue)
  }

  def value: T = v.value

  private def writeObject(out: ObjectOutputStream): Unit = {
    out.writeObject(v)
  }

  private def readObject(in: ObjectInputStream): Unit = {
    v = in.readObject().asInstanceOf[Broadcast[T]]
  }
}

ElasticSearch

  1. index名字只能小写,赤裸裸的教训啊= =
  2. 如果只使用单个ES账号,可以使用全局配置的es.nodes等参数,如果使用多个ES源的话可以写入多个配置MAP:
 var esin_setting = Map[String,String]("es.nodes"->"es1"
     ,"es.port"->"7001"
   )
 var esout_setting = Map[String,String]("es.nodes"->"es2"
   ,"es.port"->"7001"
   ,"es.scroll.size"->"5000")
val rdd = sc.esRDD("indexin", query,esin_setting)
rdd.saveToEs("esout/type1",esout_setting)

3.更多复杂的配置项,可以参考ElasticSearch的官网配置文档:
https://www.elastic.co/guide/en/elasticsearch/hadoop/current/configuration.html

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
spark streaming 是基于 spark 引擎的实时数据处理框架,可以通过集成 kafka 来进行数据流的处理。然而,在使用 spark streaming 进行 kafka 数据流处理时,可能会遇到一些坑。 首先,要注意 spark streamingkafka 版本的兼容性。不同版本的 spark streamingkafka 可能存在一些不兼容的问题,所以在选择版本时要特别留意。建议使用相同版本的 spark streamingkafka,以避免兼容性问题。 其次,要注意 spark streaming 的并行度设置。默认情况下,spark streaming 的并行度是根据 kafka 分区数来决定的,可以通过设置 spark streaming 的参数来调整并行度。如果并行度设置得过高,可能会导致任务处理过慢,甚至出现 OOM 的情况;而设置得过低,则可能无法充分利用集群资源。因此,需要根据实际情况进行合理的并行度设置。 另外,要注意 spark streamingkafka 的性能调优。可以通过调整 spark streaming 缓冲区的大小、批处理时间间隔、kafka 的参数等来提高性能。同时,还可以使用 spark streaming 的 checkpoint 机制来保证数据的一致性和容错性。但是,使用 checkpoint 机制可能会对性能产生一定的影响,所以需要权衡利弊。 最后,要注意处理 kafka 的消息丢失和重复消费的问题。由于网络或其他原因,可能会导致 kafka 的消息丢失;而 spark streaming 在处理数据时可能会出现重试导致消息重复消费的情况。可以通过配置合适的参数来解决这些问题,例如设置 KafkaUtils.createDirectStream 方法的参数 enable.auto.commit,并设置适当的自动提交间隔。 总之,在使用 spark streaming 进行 kafka 数据流处理时,需要留意版本兼容性、并行度设置、性能调优和消息丢失重复消费等问题,以免踩坑。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值