Spring整合Kafka时在消费端为我们提供了一个参数concurrency,这个参数可主要是用来设置消费者的线程数,提高消费的能力,当然与所有线程数设置的套路一样,这个值并不是越大越好。
Spring中提供的这个参数其原理就和启动多个消费者一样,kafka在启动时会根据你的消费者数量与主题中的分区数进行匹配,比如你有3个消费者订阅了‘test_topic’主题,这个主题又有3个分区,那么kafka就会为每一个消费者分配一个分区,服务端再发送消息时,可以把消费均匀的发送到3个分区中,这样就可以实现3个消费者并行消费,提高整体消费的吞吐量。
concurrency这个参数实际上就是在模拟消费者,默认情况,一个消费者会启动一个线程去监听消息的到来,而concurrency意思就是一个消费者启动多个线程去监听消息,说白了就是充分利用多核CPU的优势,以此来提高消费端的消费能力。
接下来我们结合实际情况演示一下具体效果。
首先创建一个主题名为:test_order_topic,并且设置了三个分区。
设置concurrency=3,即一个客户端启动3个监听消费线程。
先启动一个客户端,可以看到客户端开启了3个线程,每个线程负责一个分区。
接着启动第二个客户端,也是开启了3个线程,但是很明显这时只有一个线程被分配了分区,其余两个线程实际上啥事也没有。
另外两个分区还是由第一个客户端负责
再启动第三个客户端,同样开启3个线程,也只分配到一个分区。
另外两个客户端分别负责一个分区
查看主要源码分析
@Override
protected void doStart() {
if (!isRunning()) {
checkTopics();
ContainerProperties containerProperties = getContainerProperties();
TopicPartitionInitialOffset[] topicPartitions = containerProperties.getTopicPartitions();
if (topicPartitions != null
&& this.concurrency > topicPartitions.length) {
this.logger.warn("When specific partitions are provided, the concurrency must be less than or "
+ "equal to the number of partitions; reduced from " + this.concurrency + " to "
+ topicPartitions.length);
this.concurrency = topicPartitions.length;
}
setRunning(true);
//客户端在启动时,会直接遍历concurrency,每次new KafkaMessageListenerContainer对象,然后调用start方法
//start方法,又会创建一个ListenerConsumer对象,消息就是由这个对象负责不停的拉取
for (int i = 0; i < this.concurrency; i++) {
KafkaMessageListenerContainer<K, V> container;
if (topicPartitions == null) {
container = new KafkaMessageListenerContainer<>(this, this.consumerFactory,
containerProperties);
}
else {
container = new KafkaMessageListenerContainer<>(this, this.consumerFactory,
containerProperties, partitionSubset(containerProperties, i));
}
String beanName = getBeanName();
container.setBeanName((beanName != null ? beanName : "consumer") + "-" + i);
if (getApplicationEventPublisher() != null) {
container.setApplicationEventPublisher(getApplicationEventPublisher());
}
container.setClientIdSuffix("-" + i);
container.setGenericErrorHandler(getGenericErrorHandler());
container.setAfterRollbackProcessor(getAfterRollbackProcessor());
container.start();
this.containers.add(container);
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
通过上面这个例子应该可以看出,此时的配置已经造成了线程资源的浪费,每个客户端都有两个线程完全不会消费到消息,但却依然占据着资源。
总结:
1、concurrency要根据实际情况设置,一个消费端的情况下设置的值不要大于分区数。
2、多个消费端的情况下,如果消费端数量>=分区数,就没有必要再去设置concurrency(concurrency默认值为1)
————————————————
版权声明:本文为CSDN博主「码拉松」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/CSDN_WYL2016/article/details/108848781