案例:

  topic:my-topic,分区:6

  消费者:部署三台机器,每台机器上面开启6个线程消费。

  消费结果:只有一台机器可以正常消费,另外两台机器直接输出六条告警日志:

No broker partitions consumed by consumer thread my-topic-group_adfc6be4a509-1496976531798-d70f9a43-3 for topic my-topic
No broker partitions consumed by consumer thread my-topic-group_adfc6be4a509-1496976531798-d70f9a43-1 for topic my-topic
No broker partitions consumed by consumer thread my-topic-group_adfc6be4a509-1496976531798-d70f9a43-2 for topic my-topic
No broker partitions consumed by consumer thread my-topic-group_adfc6be4a509-1496976531798-d70f9a43-4 for topic my-topic
No broker partitions consumed by consumer thread my-topic-group_adfc6be4a509-1496976531798-d70f9a43-6 for topic my-topic
No broker partitions consumed by consumer thread my-topic-group_adfc6be4a509-1496976531798-d70f9a43-5 for topic my-topic

在源码分析之前,先给个图示吧,花了两个小时才画完。

源码分析:

for (topic <- ctx.myTopicThreadIds.keySet) {
   // curConsumers = 6*3 = 18,当前消费者数量
val curConsumers = ctx.consumersForTopic(topic)
   // curPartitions = 6,当前分区数量
val curPartitions: Seq[Int] = ctx.partitionsForTopic(topic)
   // nPartsPerConsumer = 6/18 = 0,平均每个消费者能分到的分区数【取整】
val nPartsPerConsumer = curPartitions.size / curConsumers.size
   /*
nConsumersWithExtraPart = 6%18 = 6,如果分割不均匀(消费者和分区数不是倍数关系),那么前N个消费者将会消费一个额外的分区
这里得出结果是6,那么其含义可以理解为前6个消费者可以比其他消费多消费一个分区,前6个各占有一个分区,后面12个消费者各占有0个分区
*/
val nConsumersWithExtraPart = curPartitions.size % curConsumers.size info("Consumer " + ctx.consumerId + " rebalancing the following partitions: " + curPartitions +
" for topic " + topic + " with consumers: " + curConsumers) for (consumerThreadId <- curConsumers) {
    // myConsumerPosition是指当前consumerThreadId在消费者集合中的位置
val myConsumerPosition = curConsumers.indexOf(consumerThreadId)
assert(myConsumerPosition >= 0)
    /*
startPart = 0*6 + myConsumerPosition.min(6),min函数表示取两个数值中小的一个,那么startPart的值就分成了两个部分:[0-5] -> 0-5,[6-17] -> 6
分区升序排列之后,startPart表示当前消费者从哪个分区开始消费。
*/
val startPart = nPartsPerConsumer * myConsumerPosition + myConsumerPosition.min(nConsumersWithExtraPart)
    /*
nParts = 0 + (myConsumerPosition + 1 > 6 ) ? 0 : 1 ,这里nParts的值也分成了两部分,[0-5] -> 1 , [6-17] -> 0
如果消费者数量小于分区数量,则前nConsumersWithExtraPart个消费者的分区数量会是2,nParts只会有三种值【0,1,2】,
表示当前消费者可以消费分区的数量。 */
val nParts = nPartsPerConsumer + (if (myConsumerPosition + 1 > nConsumersWithExtraPart) 0 else 1) /**
* Range-partition the sorted partitions to consumers for better locality.
* The first few consumers pick up an extra partition, if any.
*/
    // 这里myConsumerPosition在[6-17]的comsumer都会直接告警,也就是上文提到的【额外部分消费者】
if (nParts <= 0)
warn("No broker partitions consumed by consumer thread " + consumerThreadId + " for topic " + topic)
else {
      // 这里myConsumerPosition在[0-5]的comsumer进入topic分区分配
for (i <- startPart until startPart + nParts) {
val partition = curPartitions(i)
info(consumerThreadId + " attempting to claim partition " + partition)
// record the partition ownership decision
val assignmentForConsumer = partitionAssignment.getAndMaybePut(consumerThreadId.consumer)
assignmentForConsumer += (TopicAndPartition(topic, partition) -> consumerThreadId)
}
}
}
}

结果:topic里面的每个partition只会由一个线程消费,在分配的时候就已经指定好,如果有消费者线程加入或者退出,则会重新开始分配。

kafka多线程消费topic的问题的更多相关文章

  1. kafka多线程消费及处理和手动提交处理方案设计[转]

    转自:http://blog.csdn.net/haoyifen/article/details/54692503 kafka与其他消息队列不同的是, kafka的消费者状态由外部( 消费者本身或者类 ...

  2. kafka 多线程消费

    一. 1.Kafka的消费并行度依赖Topic配置的分区数,如分区数为10,那么最多10台机器来并行消费(每台机器只能开启一个线程),或者一台机器消费(10个线程并行消费).即消费并行度和分区数一致. ...

  3. kafka多线程消费

    建立kafka消费类ConsumerRunnable ,实现Runnable接口: import com.alibaba.fastjson.JSON; import com.alibaba.fastj ...

  4. Kafka创建&查看topic,生产&消费指定topic消息

    启动zookeeper和Kafka之后,进入kafka目录(安装/启动kafka参考前面一章:https://www.cnblogs.com/cici20166/p/9425613.html) 1.创 ...

  5. NET中解决KafKa多线程发送多主题

    NET中解决KafKa多线程发送多主题 一般在KafKa消费程序中消费可以设置多个主题,那在同一程序中需要向KafKa发送不同主题的消息,如异常需要发到异常主题,正常的发送到正常的主题,这时候就需要实 ...

  6. Kafka vs RocketMQ—— Topic数量对单机性能的影响-转自阿里中间件

    引言 上一期我们对比了三类消息产品(Kafka.RabbitMQ.RocketMQ)单纯发送小消息的性能,受到了程序猿们的广泛关注,其中大家对这种单纯的发送场景感到并不过瘾,因为没有任何一个网站的业务 ...

  7. Kafka重复消费和丢失数据研究

    Kafka重复消费原因 底层根本原因:已经消费了数据,但是offset没提交. 原因1:强行kill线程,导致消费后的数据,offset没有提交. 原因2:设置offset为自动提交,关闭kafka时 ...

  8. Flume简介与使用(三)——Kafka Sink消费数据之Kafka安装

    前面已经介绍了如何利用Thrift Source生产数据,今天介绍如何用Kafka Sink消费数据. 其实之前已经在Flume配置文件里设置了用Kafka Sink消费数据 agent1.sinks ...

  9. Kafka动态增加Topic的副本

    一.kafka的副本机制 由于Producer和Consumer都只会与Leader角色的分区副本相连,所以kafka需要以集群的组织形式提供主题下的消息高可用.kafka支持主备复制,所以消息具备高 ...

随机推荐

  1. HITS

    HITS 1 概述 HITS(hypertext induced topic search)超链接归纳主题搜索是由kleinbers在90年代提出的基于链接分析的网页排名算法.Hits算法是利用Hub ...

  2. checkbox数据回显问题

    一.问题 在用复选框的时候,最常用的无非就是全选,全不选,数据回显等问题!要做的比较灵活!最近做项目的时候,就遇到这些问题,下面从js和JQueyr两方面解决一下全选,全不选,数据回显的问题. 二.H ...

  3. require的路径问题(比较重要)

    dojo.baseUrl baseUrl用来存储dojo.js存放 的跟目录,例如dojo.js的路径是“/web/scripts/dojo-1.3/dojo/dojo.js”则baseUrl为“/w ...

  4. 项目中使用WCF替换asmx Web service总结

    以前项目解决方案中,用http协议的asmx Web service作服务器数据访问入口,在SoapHeader中写入用户名和加盐密码进行身份认证. http asmx服务是明文传输,传输过程中数据很 ...

  5. python面试题之如何计算一个字符串的长度

    在我们想计算长度的字符串上调用函数len()即可 >>> len('hhhhhhhhjg') 10 所属网站分类: 面试经典 > python 作者:外星人入侵 链接:http ...

  6. TSQL--集合处理

    UNION ALL 返回两个结果集中所有的行,返回结果集中会存在重复行 UNION 返回两个结果集中去重的行,返回结果集中无重复行 INTERSECT 返回两个结果集都有的行,返回结果集中无重复行 E ...

  7. sqlcmd 执行SQL语句或没有足够的内存来执行脚本

    win+r命令提示框里面输入cmd sqlcmd -S . -U username -P password -d database -i url -S 数据库地址 -U 登录名称 -P 密码 -d 数 ...

  8. WPF文字间距

    代码: <ItemsControl ItemsSource="{Binding Info}" FontFamily="微软雅黑" FontSize=&qu ...

  9. iOS Apple Watch 开发

    1. Watch OS 1 与 Watch OS 2 的区别 : OS 1 中界面运行在手表上,而代码(Extension)运行在手机端:OS 2 是纯正的手表原生(Native)应用 由于架构的改变 ...

  10. Ubuntu16.04 - 怎么能够更好设置PATH变量,便于管理?

    “/etc/profile”是linux里面的全局变量设置文件,加入这里的PATH变量,全局都可以使用,非常方便.加入时候很简单了,直接在PATH末尾加入":+要加入的变量"就可以 ...