[Kafka权威指南] Chapter 4. Kafka消费者:消费数据

Consumer Group

What is Consumer Group ?

Case:前端采集的数据通过Kafka Topic回传至后端分析程序,但是单个分析线程(Consumer)很有可能忙不过来。

既然单个消费者忙不过来,那就多来几个消费者。此时,这些消费者就构成了一个小团队。

Topic中的消息在被分割、摊派后,每个成员(消费者)就自顾自地忙自己那部分。

在Kafka中,这个团队称为”Consumer Group”。

[Kafka权威指南] Chapter 4. Kafka消费者:消费数据_第1张图片[Kafka权威指南] Chapter 4. Kafka消费者:消费数据_第2张图片[Kafka权威指南] Chapter 4. Kafka消费者:消费数据_第3张图片

How to distribute Messages ?

至于同一个Topic中的Message如何摊派呢? 

一个Partition给一个消费者。 一对一的形式,易于Partition offset的管理。

当然,Consumer可以同时处理多个Partition。

[Kafka权威指南] Chapter 4. Kafka消费者:消费数据_第4张图片

But there is no point in adding more consumers than the partitions in a topic. : )

 

Between Consumer Groups ?

Another Case:前端采集的数据,可能不仅仅传给分析系统A,还可能传给B,传给C...

在这种场景中,每套系统都要有一份完整的数据,而不是割分出的一个子集。

当然,单套系统内部可以有多个消费者协同工作。

[Kafka权威指南] Chapter 4. Kafka消费者:消费数据_第5张图片

此时,分析程序A就对应一个Consumer Group,而分析程序B对应另一个Consumer Group...

在实现上,Kafka不需要将原始消息流拷贝一份,每个消费者只需要记住自己当前的offset即可。

 

 

Partition Reblance(Reassign) ?

Case 1: consumer crash Or new consumer becomes online

Case 2: new partitions are added to the topic

无论是消费者个数有变动,还是分区的个数有变动,消费者-分区之间的平衡都已被打破。

此时,分区需要在消费者之间重新分配,这一过程就叫做Partition Reblance。

 

对应每个consumer group,会有一个broker(Kafka服务器)作为协调者(group coordinator),负责Partition分配等事务。

每次reblance时触发下述流程:

  1. 当一个Consumer想要加入Group时,发送请求给Group Coordinator,首个成员自然而然就是队长Group Leader;
  2. 队长将会从Group coordinator那里得到 当前所有存活消费者的列表,并负责为他们分配分区。
  3. 分区分配的结果,会经由Group Coordinator,转发至所有成员。(当然,每个人只能看见自己的那部分)

当一个consumer被关闭时,consumer会立即通知group coordinator,主动触发rebalance操作。

此外,由于crash、网络等原因,consumer可能会静悄悄地挂了。

为此,Group Coordinator通过消费者定时发送的心跳包来监测消费者的存活情况。

当等待超过指定时间时,Group Coordinator将会将其标注为down,并触发reblance。

 

通过上述reblance的流程可见,reblance过程中整个Group的工作都将stall(毕竟不知道要干啥)

 

Consumer Properties

 

设置项 含义
fetch.min.bytes

限定消费者单次拉取的最小数据 (降低频率),减少网络、Broker、消费者三方的压力

fetch.max.wait.ms

避免fetch.min.bytes造成的长时间等待,限定等待时间(默认500ms)

max.partition.fetch.bytes

消费者从单个partition拉取的最大数据量

下界:大于单条消息

上界:避免消息处理时间过长。consumer需要及时调用poll(),更新心跳等

session.timeout.ms

多久没发送心跳,可被视为down

auto.offset.reset

当消费者缺乏有效的offset时,从何处开始读取。 选项:latest or earlist

enable.auto.commit

true: 消费者自动提交offset false: 人为控制offset提交时机

partition.assignment.strategy

Topic 1: P0, P1, P2    Topic 2: P0, P1,  P2 

Group: C1, C2

 

Range分配策略:

C1: T1P0, T1P1 -> T2P0, T2P1

C2:  T1P2             ->  T2P2

 

RoundRobin分配策略:

C1: T1P0 -> T1P2 -> T2P1

C2: T1P1 -> T2P0 -> T2P2

client.id 任意字符串,用于区分Kafka Client
max.poll.records 单次poll()操作能返回的最多记录个数

 

Commits and Offsets ?

consumer通过offset来追踪分区当前的处理进度。

如果consumer永远不挂(或者Partition没有变动),其实就是没有触发Reblance操作,

offset在consumer内部自行维护即可,我自己知道就行。

但实际情况就是,reblance总是有可能发生的。

为了能让其他consumer能够接手,就需要把该分区的进度(offset)存在一个大家都能访问的地方。

一种比较简单的方式就是,往__consumer_offsets topic这个特殊Topic上,发送offset消息。

当发生reblance时,其他consumer只需要根据保存的offset开始处理即可。

但是,这里涉及两种边界情况: 重复处理和漏处理。

 

Case 1: 重复处理

如果我们处理了一部分消息,但还没来得及提交这部分的offset。

那么下一个consumer在接手时,就会从已经处理过的部分开始处理,使得数据被处理两次。

无论我们提交的多么频繁,总是有几率发生“重复处理”的情形,只是说重复处理所涉及的消息个数可能更少。

[Kafka权威指南] Chapter 4. Kafka消费者:消费数据_第6张图片

 

Case 2: 漏处理

上面的case,不是因为不及时的commit造成“重复处理”嘛?

那么我们在处理完之前就提前commit呢?

这种方法虽然避免了“重复处理”,但是可能造成一部分消息"压根没处理"。

[Kafka权威指南] Chapter 4. Kafka消费者:消费数据_第7张图片

Automatic Commit

如果enable.auto.commit为true,那么Kafka客户端每隔5秒就会提交一次offset,把上一次Poll()拉取的消息都给committed掉。

commit的逻辑,被放在poll()函数内部。每次poll()调用,都会检查距离上次提交是否过去了5s。

老生常谈的一点,就是如果消息处理逻辑和poll()放在一个循环时,就需要保证消息处理逻辑不能消耗太多时间。

 

Manual Commit

Sync style

当auto.commit.offset为false时,调用commitSync()函数将会提交上次poll()拉取的消息(提交成功返回,否则抛出异常)

同步提交的缺点就是,系统的处理速度将很大程度上受RTT影响。

优点就是,同步API会自动进行retry,直到认为无法补救了才抛异常。

Async style

异步提交,在提交完commit请求之后就返回,不会阻塞业务逻辑。

缺点就是,异步API不会进行retry。其背后的设计逻辑认为,后续的提交可以弥补单个commit的缺失。

 

 

 

你可能感兴趣的:(kafka)