使用场景:
设置并行度参数spark.streaming.concurrentJobs >1 时候,使用spark streaming消费kafka
异常信息:
There may be two or more tasks in one executor will use the same kafka consumer at the same time, then it will throw an exception: "KafkaConsumer is not safe for multi-threaded access"
JIRA-SPARK中已经提出的问题
https://issues.apache.org/jira/browse/SPARK-22606?jql=text ~ "spark.streaming.concurrentJobs"
解决办法:
第一种方案
PR地址:https://github.com/apache/spark/pull/19819
spark streaming消费kafka时候,默认开启了对kafkaconsumer进行缓存,通过存放到HashMap中实现,因此就需要有相应的key,才能找到具体到kafkaconsumer。
//原生的代码中是没有threadId变量的,通过加入线程id ,使得不同的线程不能同时使用同一个kafkaconsumer
private case class CacheKey(groupId: String, topic: String, partition: Int, threadId: Long)
private var cache: ju.LinkedHashMap[CacheKey, CachedKafkaConsumer[_, _]] = null
CachedKafkaConsumer.get[K, V](groupId, part.topic, part.partition, threadId, kafkaParams)
这个办法其实就是为缓存在map中的CachedKafkaConsumer对应的key增加了一个参数是线程id,使得不让多个线程使用同一个consumer,但是这种情况每一个task都需要去创建一个consumer,是消耗资源的。
PR中这样一句评论:
It will create a new consumer for each thread. This could be quite resource consuming when several topics shared with thread pools.
第二种方案
对spark-streaming-kafka中的CacheKafkaConsumer进行了重构,首先介绍几个类