kafka 消费者
——总结自《kafka 权威指南》
kafka 消费者从属于消费者群组,一个群组里的消费者订阅的是同一个主题,每个消费者接收主题一部分分区的消息。如果群组里的消费者超出主题的分区数量,那么就有一部分消费者会被闲置,不会接收到任何信息。
分区的所有权从一个消费者转移到另一个消费者,这种行为成为再均衡
。在再均衡期间,消费者无法读取消息,造成整个群组一小段时间的不可用。当分区被重新分配给另一个消费者时,消费者当前的读取状态会丢失,它有可能还需要去刷新缓存,在它重新恢复状态之前会拖慢应用程序。
消费者通过被指派为群组协调器的 broker 发送心跳来维持它们和群组的从属关系以及它们对分区的所有权关系。如果一个消费者发生崩溃,并停止读取消息,群组协调器会等待几秒钟,确认它死亡后才会触发再均衡,在这几秒钟内,死掉的消费者不会读取分区里的消息。在清理消费者时,消费者会通知协调器它将要离开群组,协调器会立即触发一次再均衡。
在 0.10.1 版本里,kafka 引入了一个独立的心跳线程,可以在轮询消息的空档发送心跳。这样一来,发送心跳的频率与消息轮询的频率之间就是相互独立的。可以指定消费者在离开群组并触发再均衡之前可以有多长时间不进行消息轮询,这样可以避免出现活锁。
当消费者要加入群组时,它会向群组协调器发送一个 JoinGroup 请求。第一个加入群组的消费者将成为群主,群主从协调器那里获得群组的成员列表,并负责给每一个消费者分配分区。它使用了一个实现了 PartitionAssignor 接口的类来决定哪些分区应该分配给哪个消费者。
public class ConsumerTest {
public static void main(String[] args) {
Properties kafkaProperties = new Properties();
kafkaProperties.setProperty("bootstrap.servers", "127.0.0.1:9092");
kafkaProperties.put("group.id", "group-1");
kafkaProperties.setProperty("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
kafkaProperties.setProperty("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
KafkaConsumer<String, String> kafkaConsumer = new KafkaConsumer<String, String>(kafkaProperties);
// 订阅主题,可以在 subscribe 传入一个正则表达式,匹配多个主题,即 consumer.subscribe("test.*")
kafkaConsumer.subscribe(Collections.singleton("CustomerCountry"));
// 轮序读取数据
try {
while (true){
ConsumerRecords<String, String> records = kafkaConsumer.poll(100);
for (ConsumerRecord<String, String> record : records){
String printStr = String.format("topic=%s, partition=%s, offset=%s, customer=%s, country=%s\n",
record.topic(), record.partition(), record.offset(), record.key(), record.value());
System.out.println(printStr);
}
}
} catch (Exception e){
e.printStackTrace();
} finally {
kafkaConsumer.close();
}
}
}
Properties
-
fetch.min.bytes:指定了消费者从服务器获取记录的最小字节数。broker 在收到消费者的数据请求时,如果可用的数据量小于该值,它就会等到有足够的可用数据时才把它返回给消费者。
-
fetch.max.wait.ms:指定 broker 的等待时间,默认是500ms,当 broker 数据量达到 fetch.min.bytes 或延时时间达到 fetch.max.wait.ms 时数据返回。
-
max.partition.fetch.bytes:指定了服务器从每个分区返回给消费者的最大字节数总量,默认值是 1MB。max.partition.fetch.bytes 的值必须要比 broker 能够接收的最大消息的字节数(通过 max.message.size 属性配置)大,否则消费者可能无法读取消息,导致消费者一直挂起重试。
-
session.timeout.ms:指定了消费者在被认为死亡之前可以与服务器断开连接的时间,默认是3s。该属性与 hearbeat.interval.ms 紧密相关,hearbeat.i