这个问题有好多人都写了解释(但我看基本都是一个人写的样子。。。后面会加一些不同的解释)
简单说就是根据官方文档的direct样例启动kafkadatastream,直接就是一一对应的。
而其他方式就可能不是了,所以说说其他不是要怎么做到一一对应(毕竟这样才是最高效率的消费方式)——
1)修改kafkaRDD类的getPartition方法:
就是通过设置 topic.partition.subconcurrency 参数,如果这个参数等于1,整个函数的执行效果和之前一样。但是如果这个参数大于1,则之前一个 Kafka 分区由一个 Spark 分区消费的数据变成由 topic.partition.subconcurrency 个 Spark 分区去消费,每个 Spark 分区消费的数据量相等。这个无疑会加快 Kafka 数据的消费,但是这种方法的问题也很明显:
如果数据的顺序很重要,这种方法会存在乱序的问题。
Spark 设计的 KafkaRDD 目的是让 Kafka Partition 和 Spark RDD Partition 一一对应,这样可以保证同一个分区里面的数据顺序,但是这种方法实现变成了 Kafka Partition 和 Spark RDD Partition 一对多的关系,无疑破坏了官方的原有设计。
2)通过 repartition 或 coalease 对数据进行重分区:
优点:对同一类型的数据,先后顺序是不会乱的,因为同一类型的数据,经过重分区还是会分发到同一分区中。
(这俩结论也是直接粘贴过来的)
个人总结
对于第一个结论
开始我理解成
但这是不可能的,因为
前俩天刚写了kafka消费者组和重平衡机制,里面就说到了,kafka一个分区只能被消费者组中的一个消费者消费,然后就看到了有人问怎么做到消费者与分区一一对应的问题。
如果真是一个分区启动了俩个消费者去消费,那么
参见spring-kafka文档的这句说明:
If the concurrency
is greater than the number of TopicPartitions
, the concurrency
is adjusted down such that each container gets one partition.
就可得知,如果并发性大于总分区数,那么kafka会自动下调concurrency来保证一个线程一个分区,所以就算你开了10个线程,实际上其实也就是1个线程在消费数据。
对于第二个结论
相较下我是建议使用这个方式来提高并发性的,但是要注意重分区所带来的影响:
1、在进行重分区的时候,生产和消费都会停止
2、重分区如果数据量特别多,会消耗大量时间
所以是否可以创建新的topic和分区数,然后先中断生产者,然后生产者向新topic发送数据,然后等消费者将原topic数据消费完之后,更改topic继续消费,这样中间停止的时间其实要比重分区短的多,当然也要看业务,有的业务可能一个topic被多个消费者组消费,那这样就不太好弄。
或者
消费topic以正则的方式消费,然后增加topic的之后,生产者切换topic的时候直接不用修改消费者代码。