消费者(Consumer)在Kafka的体系结构中是用来负责订阅Kafka中的主题(Topic),并从订阅的主题中拉取消息后进行处理。
与其他消息中间件不同,Kafka引入一个逻辑概念------消费组(Consumer Group),我们可以理解为消费者的分类,每个消费者都对应一个消费组,消费组与消费组之间的关系是完全独立的,互不影响。
1 消费组
我对消费组的理解是这样的:(为了便于理解)我将它看做一个"大号的消费者",既然它是一个"消费者",那它就能订阅主题(即从主题那里拉取消息),所以对于主题中的一个消息来说,订阅了该主题的所有"大号的消费者(即消费组)"们都能拉取到该消息(实际上是消费组中的消费者),如下图:
- 图①的理解是:将消费组A和消费组B看做两个"大号的消费者",并且都订阅了主题A。
- 图②的理解是:由于"大号的消费者A"和"大号的消费者B"都订阅了主题A,所以【消息A-1】会发送给这两个"大号的消费者(实际是消费组)"。
- 图③的理解是:实际上【消息A-1】是被"大号消费者A"(即消费组A)和"大号消费者B"(即消费组B)中的【消费者A-1】和【消费者B-1】拉取了并处理了。
再进一步来说,消费组内的消费者们实质上都处理相同的业务(可以将他们理解为同一个消费者的多个副本),而不同消费组的消费者通常来说处理的都是不同的业务。 我们再举个例子来解释下:
假设这样一个场景:
一个请假的审批流程,请假审批通过后,会分别通知请假申请人和人力资源部门。
从中我们定义出一个主题和二个消费者:
- 主题:请假审批结果
- 消费者A0:通知请假申请人
- 消费者B0:通知人力资源部门
期初公司人员较少请假审批的申请并不多(也就是说要消费的消息并不多),此时一个处理"通知请假申请人"的消费者节点和一个处理"通知人力资源部门"的消费者节点就可以支撑业务了,如下图:
假设公司团队迅速扩张(员工人数大量增加),请假也越来越多,之前分别处理"通知请假申请人"、"通知人力资源部门"的单节点无法快速的处理消息,所以这个时候我们就需要增加节点,如下图:
2 分区分配逻辑
基于默认的分区分配策略,我们再来看下消费组内的消费者数量变化会对分区分配有怎样的影响(也就是分配逻辑是什么样的),如下图:
- 图①表示:消费组内只有一个消费者时,所有分区的消息将都分配给该消费者。
- 图②、图③表示:将原本分配给【消费者A-0】的部分分区分配给【消费者A-1】和【消费者A-2会】。
- 图④表示:当消费组内消费者的数量等于分区数量的时候,则每个分区都会被分配一个对应消费者。
- 图⑤表示:当消费组内的消费者数量大于分区数量的时候,并不能提高消费的效率,因为多出来的消费者分配不到任何分区也就无法消费任何消息。
3 Kafka的消息投递模式
消息的投递方式主要有以下两种:
- 点对点(P2P,Point-to-Point)模式:点对点模式是基于队列的,消息生产者(Producer)将消息发送给队列,消息消费者(Consumer)从队列中接收消息并进行消费。
- 发布/订阅(Pub/Sub)模式:发布/订阅模式是基于主题(Topic)的,消息生产者(Producer)将消息发送给主题,消息消费者(Consumer)接收所订阅主题的消息并进行消费。
这两种消息投递方式Kafka同时支持,那么Kafka是如何实现的点对点模式和订阅/发布模式的呢?
- 点对点模式:将所有订阅某主题的消费者放到一个消费组中,这样的话该主题的每条消息就只会被消费组中的一个消费者消费掉,也就相当于点对点模式的应用了。
以上图为例,被分配到【分区0】的消息,只能被【消费者A-0】拉取到。 - 订阅/发布模式:使订阅某主题的所有消费者都隶属一个专属的消费组,这样的话该主题的每条消息将会被所有消费者都处理一遍,也就相当于发布/订阅模式的应用了。
以上图为例,被分配到【分区0】的消息,会被【消费者0】、【消费者1】、【消费者2】...【消费者N】拉取到。
下一篇:《Kafka之消费者客户端开发》