一、消费消息

1、旧版高级消费者
Kafka的消费者以Pull的方式获取消息,同时Kafka采用了消费组的模式,每个消费者都属于某一个消费组。在创建消费者时,若不指定消费者的groupId,则该消费者属于默认消费组。消费组是一个全局的概念,因此在设置group.id时,要确保该值在Kafka集群中唯一。
同一个消费组下的各消费者在消费消息时是互斥的,也就是说,对于一条消息而言,就同一个消费组下的消费者来讲,只能被同组下的某一个消费者消费,但不同消费组的消费者能同时消费同一条消息,正是如此,我们可以通过消费组来实现消息的单播和广播。

kafka-console-consumer.sh --zookeeper 172.20.10.3:2181,172.20.10.4:2181,172.20.10.5:2181 --topic kafka-action --consumer-property group.id=old-consumer-test --consumer-property consumer.id=old-consumer-cl --from-beginning --delete-consumer-offsets

以上启动消费者命令的各参数说明如下。

  • zookeeper:用于指定连接Kafka的ZooKeeper地址设置。
  • topic:指定消费者消费的主题。
  • consumer-property:该参数后面以健值对的形式指定消费者级别的配置。例如,在启动消费者时可以通过配置group.id设置消费组名,若不设置该值,执行该脚本时会随机创建一个以"console-consumer-"为前缀,之后连接一个100000以内的随机整数组成字符串作为消费组名;通过consumer.id设置消费者的Id,启动一个旧版高级消费者会在ZooKeeper中注册该消费者的Id,在ZooKeeper中会创建一个以${gruop.id}_${consumer.id}的节点,若不指定consumer.id,启动消费者时会创建一个以代理hostname-当前时间戳-UUID前8位字符构成的字符串作为consumer.id。
  • from-beginning:该参数用来设置从消息起始位置开始消费。默认是从最新消息位置(latest)开始消费。执行该版本时老版本的消费者并不支持–offset参数,也就是说,使用老版本消费者时只能指定是从消息起始位置还是最新消息位置,而不能指定从任意偏移量开始消费。
  • delete-consumer-offsets:该参数用于删除在ZooKeeper中记录的已消费的偏移量。假设有多个消费者属于该消费组,则再创建一个属于该消费组的消费者时若指定了from-beginning参数,则必须指定该参数,以删除其他消费者在ZooKeeper中记录的已被消费的最大偏移量,因为对于一条消息而言,只能被同一个消费组下的某一个消费者消费。

每个消费者被创建时都会向ZooKeeper中注册相应的元数据信息,若该消费者所属的消费组在ZooKeeper中不存在,则首先在/consumers 目录下创建一个${group.id}的节点,即消费组节点,并创建3个子节点(ids、owners、offsets)

  • ids:记录该消费组下正在运行的消费者列表。
  • owners:记录该消费组消费的主题列表。
  • offsets:记录该消费组下每个消费者所消费主题的各个分区的偏移量,若在启动消费者时指定offsets.storage=kafka 则偏移量会保存到Kafka内部主题中,就不会有该节点。

一个新的消费者被创建时会在ZooKeeper中与之对应的消费组节点的ids节点下注册一个临时节点,该临时节点名为${group.id}_${consumer.id},当消费者退出时该节点就会被删除。当消费者发生变化时,通过ZooKeeper的Watch机制感知消费者的变化,从而进行消费者平衡操作,根据分区分配策略重庆分配每个消费者消费的分区。
在ZooKeeper客户端查看该消费组ids节点信息,执行命令及输出信息如下:

[zk: localhost:2181(CONNECTED) 30] ls /consumers/old-consumer-test/ids
[old-consumer-test_old-consumer-cl]

同时,通过get命令查看old-consumer-test-old-consumer-cl节点存储的元数据信息如下:

get /consumers/old-consumer-test/ids/old-consumer-test_old-consumer-cl
{"version":1,"subscription":{"kafka-action":1},"pattern":"white_list","timestamp":"1604038620484"}

其中version为固定值1;subscription 记录该消费者订阅的主题列表及每个主题对应的消费者线程数;pattern目前支持white_list、black_list和static这3个值;timestamp 记录消费者启动时的时间戳。
在消费组节点 owners 子节点中记录该消费组所消费的主题列表以及每个主题的每个分区对应的消费者线程。当主题元数据信息发生变化时,如分区Leader发生变化时,将触发所有的消费组进行平衡操作。
3个消费者线程时:

[zk: localhost:2181(CONNECTED) 44] get /consumers/old-consumer-test/owners/kafka-action/0
old-consumer-test_old-consumer-cl-0
[zk: localhost:2181(CONNECTED) 45] get /consumers/old-consumer-test/owners/kafka-action/2
old-consumer-test_old-consumer-cl2-0
[zk: localhost:2181(CONNECTED) 46] get /consumers/old-consumer-test/owners/kafka-action/1
old-consumer-test_old-consumer-cl1-0

两个消费者线程时:

[zk: localhost:2181(CONNECTED) 47] get /consumers/old-consumer-test/owners/kafka-action/0
old-consumer-test_old-consumer-cl-0
[zk: localhost:2181(CONNECTED) 48] get /consumers/old-consumer-test/owners/kafka-action/1
old-consumer-test_old-consumer-cl-0
[zk: localhost:2181(CONNECTED) 49] get /consumers/old-consumer-test/owners/kafka-action/2
old-consumer-test_old-consumer-cl1-0

在offsets子节点记录了该消费组订阅的每个主题的各分区已消费的最大偏移量。

[zk: localhost:2181(CONNECTED) 50] get /consumers/old-consumer-test/offsets/kafka-action/0
52
[zk: localhost:2181(CONNECTED) 51] get /consumers/old-consumer-test/offsets/kafka-action/1
47
[zk: localhost:2181(CONNECTED) 52] get /consumers/old-consumer-test/offsets/kafka-action/2
57

2、旧版低级消费者
Kafka自带了一个kafka-simple-consumer-shell.sh脚本,用于调用Kafka的低级消费者(simple Consumer)低级消费者需要自己管理消费偏移量,同时只能消费某个主题的某个分区的消息,因此当我们执行该脚本启动一个消费者时,该消费者并不会向ZooKeeper 注册相应元数据信息,执行以下命令,启动一个消费者,从主题kafka-action编号为0的分区拉取消息。

kafka-simple-consumer-shell.sh --broker-list 172.20.10.3:9092,172.20.10.4:9092,172.20.10.5:9092  --clientId simple-consumer-test --offset -1 --partition 0  --topic kafka-action
  • broker-list:用于指定代理地址列表。从该参数可以看出Low-Level消费者并不依赖ZooKeeper。
  • offset:用于指定消费的起始位置。该参数支持任意非负整数,同时支持-1和-2两个负数,分表表示消息起始位置和最新消息位置,默认为-2。
  • partition:用于指定分区,若不指定默认是编号为0的分区。

3、新版本消费者
新版本的消费者去掉了对ZooKeeper 的依赖,当启动一个消费者时不再向ZooKeeper注册,而是由消费组协调器统一管理。消费者已消费的偏移量提交后会保存到名为"__consumer_offsets"的内部主题中。
执行以下命令启动一个新版消费者:

kafka-console-consumer.sh --bootstrap-server 172.20.10.3:9092,172.20.10.4:9092,172.20.10.5:9092  --consumer-property group.id=new-consumer-test --consumer-property client.id=new-consumer-cl --topic kafka-action

4、消费多主题
Kafka自带的脚本kafka-console-consumer.sh 的 topic参数并不支持同时指定多个主题,但该脚本提供了另外一个参数whitelist(白名单),该参数可同时指定多个主题,且支持正则表达式。
注意,主题名表达式需要加引号。执行以下命令:

kafka-console-consumer.sh --bootstrap-server 172.20.10.3:9092,172.20.10.4:9092,172.20.10.5:9092  --consumer-property group.id=old-consumer-test --consumer-property consumer.id=old-consumer-cl --whitelist "kafka-action|producer-perf-test"

kafka 创建消费组 kafka新建消费组_kafka

二、单播与多播

Kafka引入了消费组,每个消费者都属于一个特定的消费组,通过消费组就可以实现消息的单播与多播。
1、单播
一条消息只能被某一个消费者消费的模式成为单播。要实现消息单播,只要让这些消费者属于同一个消费组即可。
首先启动一个生产者向kafka-action主题发送消息,执行命令如下:

kafka-console-producer.sh --broker-list 172.20.10.3:9092,172.20.10.4:9092,172.20.10.5:9092 --topic kafka-action

在终端分别执行以下命令,启动两个消费者:

kafka-console-consumer.sh --bootstrap-server 172.20.10.3:9092,172.20.10.4:9092,172.20.10.5:9092  --consumer-property group.id=single-consumer-group  --topic kafka-action

当生产者发送一条消息时,两个消费者中只有一个能收到信息,如下图所示:

kafka 创建消费组 kafka新建消费组_kafka_02


2、多播

一条消息能够被多个消费者消费的模式称为多播。之所以不称之为广播,是因为一条消息只能被Kafka同一个分组下某一个消费者消费,而不是所有消费者都能消费,所以从严格意义上来讲并不能算是广播模式,当然如果希望实现广播模式只要保证每个消费者均属于不同的消费组。针对Kafka同一条只能被同一个消费组下的某一个消费者消费的特性,要实现多播只要保证这些消费者属于不同的消费组即可。例如,我们再增加一个消费者,该消费者属于multi-consumer-group消费组,命令如下:

kafka-console-consumer.sh --bootstrap-server 172.20.10.3:9092,172.20.10.4:9092,172.20.10.5:9092  --consumer-property group.id=multi-consumer-group  --topic kafka-action

然后通过生产者发送几条消息,可以看到不同消费组的消费者同时消费到消息,然而同一个消费组下的消费者却只能有一个消费者消费到消息,如下图所示:

kafka 创建消费组 kafka新建消费组_kafka 创建消费组_03

三、查看消费者偏移量

Kafka提供了一个查看某个消费组消费者偏移量的Kafka-consumer-offset-checker.sh 脚本。不过在0.9版本以后已不再建议使用该脚本,而建议使用kafka-consumer-groups.sh。

启动一个新版消费者,该消费者消费主题kafka-action 的消息,同时该消费者隶属于消费组consumer-offset-test。

kafka-console-consumer.sh --bootstrap-server 172.20.10.3:9092,172.20.10.4:9092,172.20.10.5:9092  --consumer-property group.id=consumer-offset-test  --topic kafka-action

describe用于查看消费组当前的消费情况,若待查看的消费组是以老版本方式创建的,则通过该脚本查看消费情况时应以–zookeeper方式运行。反之,若查看的是新消费者的消费情况,则应以–bootstrap-server 方式运行该脚本
执行以下命令查看该消费组消费情况:

kafka-consumer-groups.sh --bootstrap-server 172.20.10.3:9092,172.20.10.4:9092,172.20.10.5:9092 --describe --group consumer-offset-test
TOPIC                          PARTITION  CURRENT-OFFSET  LOG-END-OFFSET  LAG        CONSUMER-ID                                       HOST                           CLIENT-ID
kafka-action                   0          62              62              0          consumer-1-29a19424-e8ca-4474-b3d0-01d94c3c16f1   /172.20.10.3                   consumer-1
kafka-action                   1          56              56              0          consumer-1-29a19424-e8ca-4474-b3d0-01d94c3c16f1   /172.20.10.3                   consumer-1
kafka-action                   2          66              66              0          consumer-1-29a19424-e8ca-4474-b3d0-01d94c3c16f1   /172.20.10.3                   consumer-1

再其他节点再启动一个消费者:

TOPIC                          PARTITION  CURRENT-OFFSET  LOG-END-OFFSET  LAG        CONSUMER-ID                                       HOST                           CLIENT-ID
kafka-action                   0          62              62              0          consumer-1-29a19424-e8ca-4474-b3d0-01d94c3c16f1   /172.20.10.3                   consumer-1
kafka-action                   1          56              56              0          consumer-1-29a19424-e8ca-4474-b3d0-01d94c3c16f1   /172.20.10.3                   consumer-1
kafka-action                   2          66              66              0          consumer-1-cf1f6394-a4e4-4ee2-8a0f-02cd515efbc1   /172.20.10.4                   consumer-1

若是以bootstrap-server 方式运行该脚本时,只能查看运行着的消费组,若消费组状态为“Dead”,则由于再Metadata中查询不到相应的元数据信息而导致不会返回任务消费信息。

Consumer group 'consumer-offset-test' has no active members.

TOPIC                          PARTITION  CURRENT-OFFSET  LOG-END-OFFSET  LAG        CONSUMER-ID                                       HOST                           CLIENT-ID
kafka-action                   1          56              56              0          -                                                 -                              -
kafka-action                   0          62              62              0          -                                                 -                              -
kafka-action                   2          66              66              0          -                                                 -                              -

该脚本支持删除不包括任务消费者的消费组。需要注意的是,该脚本只能删除消费组为老版本消费者对应的消费组。

kafka-consumer-groups.sh --zookeeper 172.20.10.3:2181,172.20.10.4:2181,172.20.10.5:2181 --list
old-consumer-test1
old-consumer-test

登录ZooKeeper客户端查看该消费组节点信息如下:

[zk: localhost:2181(CONNECTED) 0] ls /consumers/old-consumer-test/ids
[]

该消费组下没有任务消费者,因此执行以下命令该消费组将被成功删除。

kafka-consumer-groups.sh --zookeeper 172.20.10.3:2181,172.20.10.4:2181,172.20.10.5:2181 --delete --group old-consumer-test
Deleted all consumer group information for group 'old-consumer-test' in zookeeper.

四、消费者性能测试工具

该脚本支持多线程(–threads参数)设置,例如,以broker-list 的方式启动该脚本,并指定3个线程,消费50玩条消息,每条消息大小为默认的100字节,同时指定num-fetch-threads为2,默认是1个线程,消费的主题为“producer-perf-test”。该主题在生产者性能测试时已写入了超过50万条消息。执行命令如下:

kafka-consumer-perf-test.sh --broker-list 172.20.10.3:9092,172.20.10.4:9092,172.20.10.5:9092 --threads 3 --messages 500000  --num-fetch-threads 2 --group consumer-perf-test --topic producer-perf-test
start.time, end.time, data.consumed.in.MB, MB.sec, data.consumed.in.nMsg, nMsg.sec, rebalance.time.ms, fetch.time.ms, fetch.MB.sec, fetch.nMsg.sec
2020-11-01 13:45:35:586, 2020-11-01 13:45:38:673, 477.0498, 154.5351, 500223, 162041.7881, 15, 3072, 155.2897, 162833.0078

启动5个线程进行对比:

1个线程:2020-11-01 13:57:30:915, 2020-11-01 13:57:33:398, 477.0269, 192.1172, 500199, 201449.4563, 19, 2464, 193.5986, 203002.8409
3个线程:2020-11-01 13:45:35:586, 2020-11-01 13:45:38:673, 477.0498, 154.5351, 500223, 162041.7881, 15, 3072, 155.2897, 162833.0078
5个线程:2020-11-01 13:53:37:776, 2020-11-01 13:53:40:289, 477.0489, 189.8324, 500222, 199053.7207, 14, 2499, 190.8959, 200168.8675
10个线程:2020-11-01 13:58:12:107, 2020-11-01 13:58:14:469, 477.0498, 201.9686, 500223, 211779.4242, 14, 2348, 203.1728, 213042.1635

测试结果共展示了6列信息,依次为运行起始时间、结束时间、消费的消息总量(单位为MB)、按消息总量统计的吞吐量(单位为MB/s)、消费的消息总条数、按消息总数统计的吞吐量(单位为条/s)