kafka官网示例说明--KafkaConsumer

Kafka client会消费kafka cluster中的记录。
它将透明地处理Kafka集群中的服务器故障,并透明地适应它在集群内迁移的数据分区。该客户机还与服务器交互,以允许用户组使用消费者组来负载平衡消费(如下所述)。
消费者维护TCP连接到必要的代理来获取数据。使用后未能关闭消费者会泄漏这些连接。消费者不是线程安全的。更多细节见多线程处理。

偏移量

Kafka为分区中的每个记录保留一个数值偏移量。这个偏移量充当该分区中记录的唯一标识符,并且表示该分区中的消费者的位置。也就是说,拥有5号位置的消费者使用偏移值为0到4的记录,并将使用偏移量5记录下一个记录。实际上,与使用者的使用者有关的位置有两个概念。
消费者的位置将提供下一个记录的偏移量。它将比消费者在该分区中看到的最高偏移量大一个。它在消费者每次接收数据调用poll(long)和接收消息时自动地前进。
已提交的位置是安全保存的最后一个偏移量。如果进程失败并重新启动,这将恢复到它将恢复的偏移量。消费者可以定期自动提交补偿;或者,它可以选择通过调用commitSync来手动控制这个提交的位置,它会阻塞,直到在提交过程中成功提交了补偿或致命错误,或者提交了非阻塞的commitAsync,并将触发OffsetCommitCallback,要么成功提交,要么失败。

消费者组和订阅主题

Kafka使用了消费者组(Consumer Groups)的概念来允许一个过程池来划分消费和处理记录的工作。这些进程可以在同一台机器上运行,或者,更有可能的是,它们可以分布在许多机器上,从而为处理提供额外的可伸缩性和容错。
每个Kafka消费者可以配置一个消费者团体,它属于,并且可以动态设置主题希望通过订阅订阅列表(列表,Consumer Rebalance Listener),或通过订阅订阅所有主题匹配特定的模式(模式,ConsumerRebalanceListener)。Kafka将在每个用户组中的一个流程中传递订阅主题中的每个消息。这是通过在每个组的消费者过程中平衡主题中的分区来实现的。因此,如果有一个带有四个分区的主题,以及一个有两个进程的消费者组,每个进程将从两个分区中消耗。这个组成员是动态维护的:如果进程失败,分配给它的分区将被重新分配给同一组中的其他进程,如果一个新进程加入这个组,那么分区将从现有的消费者转移到这个新的进程。
因此,如果两个进程订阅一个主题同时指定不同的组,则它们将在该主题中获得所有的记录;如果他们都指定相同的组,他们将会得到大约一半的记录。从概念上来说,您可以将消费者组看作是由多个进程组成的单个逻辑订阅者。作为一个多用户系统,Kafka自然支持在没有重复数据的情况下为给定的主题提供任意数量的用户组(额外的消费者实际上相当便宜)。这是对消息传递系统中常见的功能的轻微概括。
为了获得与传统消息传递系统中的队列相似的语义,所有流程都将是单个消费者组的一部分,因此记录交付将在组中与队列相同。与传统的消息传递系统不同,您可以拥有多个这样的组。要获得类似于传统消息传递系统中的pub-sub的语义,每个流程都有自己的消费者组,因此每个进程将订阅发布到该主题的所有记录。
此外,自动组分配时,消费者可以通过Consumer Rebalance Listener通知,这允许他们完成清理等必要的应用程序级的逻辑状态,手动抵消提交(注意,抵消总是承诺对于一个给定的消费者团体),等等的详细信息,请参阅存储抵消外部卡夫卡对消费者也可以手动指定分区分配给它分配(列表),禁用这个动态分区分配。

用法示例

1. 自动确认Offset
Properties props = new Properties();
/* 定义kakfa 服务的地址,不需要将所有broker指定上 */
props.put("bootstrap.servers", "localhost:9092");
/* 制定consumer group */
props.put("group.id", "test");
/* 是否自动确认offset */
props.put("enable.auto.commit", "true");
/* 自动确认offset的时间间隔 */
props.put("auto.commit.interval.ms", "1000");
props.put("session.timeout.ms", "30000");
/* key的序列化类 */
props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
/* value的序列化类 */
props.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
 /* 定义consumer */
KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props);
/* 消费者订阅的topic, 可同时订阅多个 */
consumer.subscribe(Arrays.asList("foo", "bar"));

 /* 读取数据,读取超时时间为100ms */
while (true) {
    ConsumerRecords<String, String> records = consumer.poll(100);
    for (ConsumerRecord<String, String> record : records)
        System.out.printf("offset = %d, key = %s, value = %s", record.offset(), record.key(), record.value());
}

说明: 
1. bootstrap.servers 只是代表kafka的连接入口,只需要指定集群中的某一broker; 
2. 一旦consumer和kakfa集群建立连接,consumer会以心跳的方式来高速集群自己还活着,如果session.timeout.ms 内心跳未到达服务器,服务器认为心跳丢失,会做rebalence。

2. 手工控制Offset

如果consumer在获得数据后需要加入处理,数据完毕后才确认offset,需要程序来控制offset的确认。举个栗子: 
consumer获得数据后,需要将数据持久化到DB中。自动确认offset的情况下,如果数据从kafka集群读出,就确认,但是持久化过程失败,就会导致数据丢失。我们就需要控制offset的确认。

Properties props = new Properties();
props.put("bootstrap.servers", "localhost:9092");
props.put("group.id", "test");
/* 关闭自动确认选项 */
props.put("enable.auto.commit", "false");
props.put("auto.commit.interval.ms", "1000");
props.put("session.timeout.ms", "30000");
props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
props.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");

KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props);
consumer.subscribe(Arrays.asList("foo", "bar"));
final int minBatchSize = 200;
List<ConsumerRecord<String, String>> buffer = new ArrayList<>();
while (true) {
    ConsumerRecords<String, String> records = consumer.poll(100);
    for (ConsumerRecord<String, String> record : records) {
        buffer.add(record);
    }
    /* 数据达到批量要求,就写入DB,同步确认offset */
    if (buffer.size() >= minBatchSize) {
        insertIntoDb(buffer);
        consumer.commitSync();
        buffer.clear();
    }
}

还可以精细的控制对具体分区具体offset数据的确认:

try {
    while(running) {
        ConsumerRecords<String, String> records = consumer.poll(Long.MAX_VALUE);
        for (TopicPartition partition : records.partitions()) {
            List<ConsumerRecord<String, String>> partitionRecords = records.records(partition);
            for (ConsumerRecord<String, String> record : partitionRecords) {
                System.out.println(record.offset() + ": " + record.value());
            }
            /* 同步确认某个分区的特定offset */
            long lastOffset = partitionRecords.get(partitionRecords.size() - 1).offset();
            consumer.commitSync(Collections.singletonMap(partition, new OffsetAndMetadata(lastOffset + 1)));
        }
    }
} finally {
  consumer.close();
}

说明:确认的offset为已接受数据最大offset+1。

3. 分区订阅

可以向特定的分区订阅消息。但是会失去partion的负载分担。有几种场景可能会这么玩: 
1. 只需要获取本机磁盘的分区数据; 
2. 程序自己或者外部程序能够自己实现负载和错误处理。例如YARN/Mesos的介入,当consumer挂掉后,再启动一个consumer。

String topic = "foo";
TopicPartition partition0 = new TopicPartition(topic, 0);
TopicPartition partition1 = new TopicPartition(topic, 1);
consumer.assign(Arrays.asList(partition0, partition1));

说明: 
1. 此种情况用了consumer Group,也不会做负载均衡。 
2. topic的订阅和分区订阅不可以在同一consumer中混用。

4. 外部存储offset

消费者可以自定义kafka的offset存储位置。该设计的主要目的是让消费者将数据和offset进行原子性的存储。这样可以避免上面提到的重复消费问题。举栗说明: 
订阅特定分区。存储所获得的记录时,将每条记录的offset一起存储。保证数据和offset的存储是原子性的。当异步存储被异常打断时,凡已经存储的数据,都有有相应的offset记录。这种方式可以保证不会有数据丢失,也不会重复的从服务端读取。 
如何配置实现: 
1. 去使能offset自动确认:enable.auto.commit=false; 
2. 从ConsumerRecord中获取offset,保存下来; 
3. Consumer重启时,调用seek(TopicPartition, long)重置在服务端的消费记录。

如果消费分区也是自定义的,这种方式用起来会很爽。如果分区是自动分配的,当分区发生reblance的时候,就要考虑清楚了。如果因为升级等原因,分区漂移到一个不会更新offset的consumer上,那就日了狗了。 
该情况下: 
1. 原consumer需要监听分区撤销事件,并在撤销时确认好offset。接口:ConsumerRebalanceListener.onPartitionsRevoked(Collection); 
2. 新consumer监听分区分配事件,获取当前分区消费的offset。接口:ConsumerRebalanceListener.onPartitionsAssigned(Collection); 
3. consumer监听到 ConsumerRebalance事件,还没有处理或者持久化的缓存数据flush掉。

5. 控制消费位置

大多数情况下,服务端的Consumer的消费位置都是由客户端间歇性的确认。Kafka允许Consumer自己设置消费起点,达到的效果: 
1. 可以消费已经消费过的数据; 
2. 可以跳跃性的消费数据; 
看下这样做的一些场景: 
1. 对Consumer来说,数据具备时效性,只需要获取最近一段时间内的数据,就可以进行跳跃性的获取数据; 
2. 上面自己存offset的场景,重启后就需要从指定的位置开始消费。 
接口上面已经提到过了,用seek(TopicPartition, long)。、 
麻蛋,说指针不就好了,这一小节就是多余的叨叨。

6. 控制消费流Consumption Flow Control

如果一个consumer同时消费多个分区,默认情况下,这多个分区的优先级是一样的,同时消费。Kafka提供机制,可以让暂停某些分区的消费,先获取其他分区的内容。场景举栗: 
1. 流式计算,consumer同时消费两个Topic,然后对两个Topic的数据做Join操作。但是这两个Topic里面的数据产生速率差距较大。Consumer就需要控制下获取逻辑,先获取慢的Topic,慢的读到数据后再去读快的。 
2. 同样多个Topic同时消费,但是Consumer启动是,本地已经存有了大量某些Topic数据。此时就可以优先去消费下其他的Topic。

调控的手段:让某个分区消费先暂停,时机到了再恢复,然后接着poll。接口:pause(TopicPartition…),resume(TopicPartition…)

7. 多线程处理模型 Multi-threaded Processing

Kafka的Consumer的接口为非线程安全的。多线程共用IO,Consumer线程需要自己做好线程同步。 
如果想立即终止consumer,唯一办法是用调用接口:wakeup(),使处理线程产生WakeupException。

public class KafkaConsumerRunner implements Runnable {
    /* 注意,这俩货是类成员变量 */
    private final AtomicBoolean closed = new AtomicBoolean(false);
    private final KafkaConsumer consumer;

    public void run() {
        try {
            consumer.subscribe(Arrays.asList("topic"));
            while (!closed.get()) {
                ConsumerRecords records = consumer.poll(10000);
                // Handle new records
            }
        } catch (WakeupException e) {
            // Ignore exception if closing
            if (!closed.get()) throw e;
        } finally {
            consumer.close();
        }
    }

    // Shutdown hook which can be called from a separate thread
    public void shutdown() {
        closed.set(true);
        consumer.wakeup();
    }
}

说明: 
1. KafkaConsumerRunner是runnable的,请自觉补脑多线程运行; 
2. 外部线程控制KafkaConsumerRunner线程的停止; 
3. 主要说的是多线程消费同一topic,而不是消费同一分区;

比较一下两种模型:

Consumer单线程模型

优点:实现容易; 
没有线程之间的协作。通常比下面的那种更快; 
单分区数据的顺序处理; 
缺点:多个TCP连接,但是关系不大,kafka对自己的server自信满满; 
太多的Request可能导致server的吞吐降低一丢丢; 
consumer数量受到分区数量限制,一个consumer一个分区;

Consumer多线程模型

优点:一个consumer任意多的线程,线程数不用受到分区数限制; 
缺点:如果有保序需求,自己要加控制逻辑; 
该模型中如果手动offset,自己要加控制逻辑; 
一种可行的解决办法:为每个分区分配独立的存储,获取的数据根据数据所在分区进行hash存储。这样可以解决顺序消费,和offset的确认问题。

官网地址: 
http://kafka.apache.org/090/javadoc/index.html?org/apache/kafka/clients/consumer/KafkaConsumer.html

<think>嗯,用户这次想了解在CDH平台上使用kafka-consumer-offset-checker工具检查消费者偏移量的方法。从对话历史看,用户应该是在CDH集群中管理Kafka服务时遇到了消费者延迟问题,之前我已经提供了多种监控积压的方法,但用户特别点名要了解这个特定工具。 用户引用的两个站内参考很有价值:引用[1]展示了CDH中Kafka命令行工具的标准路径和基础用法,引用[2]则提示了复制因子配置不匹配的常见错误。这让我意识到需要重点说明版本兼容性问题——毕竟在较新的CDH版本中这个工具已被弃用。 考虑到用户可能是运维人员,需要具体操作指引,我决定分三部分回应:首先是工具路径定位,强调CDH的特殊目录结构;然后是具体命令语法,包括必填参数和常见错误处理;最后补充替代方案,因为在新版本中必须迁移到kafka-consumer-groups命令。 特别要注意的是引用[2]提到的复制因子错误,这在执行检查命令时经常出现,需要单独说明解决方案。另外用户环境可能有Kerberos认证,这个难点也要提前预警。 最后生成的延伸问题都围绕实际运维场景:第一个是版本过渡问题,第二个针对监控集成,第三个则关联到之前讨论过的消费者延迟诊断。这样既能延续当前话题,又能串联起用户可能需要的知识链。</think>在 CDH 平台的 Kafka 中使用 `kafka-consumer-offset-checker` 工具检查消费者偏移量,需注意以下关键步骤和版本适配问题: --- ### 一、工具路径与基础命令 1. **定位工具路径** CDH 的 Kafka 命令行工具位于: ```bash /opt/cloudera/parcels/KAFKA/bin/kafka-consumer-offset-checker ``` 2. **基础命令格式** ```bash ./kafka-consumer-offset-checker \ --zookeeper bigdata001:2181 \ # Zookeeper地址 --group your_consumer_group \ # 消费者组名 --topic your_topic # 目标主题(可选) ``` --- ### 二、关键输出解读 执行后输出示例: ``` GROUP TOPIC PARTITION CURRENT-OFFSET LOG-END-OFFSET LAG OWNER test_group zyl_test 0 15200 15200 0 consumer-1 test_group zyl_test 1 14800 15000 200 consumer-2 ``` - **CURRENT-OFFSET**:消费者当前提交的位移 - **LOG-END-OFFSET**:分区最新消息位移 - **LAG**:积压消息数 = `LOG-END-OFFSET - CURRENT-OFFSET` --- ### 三、版本适配与注意事项 1. **CDH 版本限制** - 仅适用于 **CDH 5.x / Kafka 0.9.x 及更早版本** - CDH 6.x (Kafka 2.x+) 已弃用此工具,需改用 `kafka-consumer-groups`: ```bash /opt/cloudera/parcels/KAFKA/bin/kafka-consumer-groups \ --bootstrap-server bigdata001:9092 \ --group your_group \ --describe ``` 2. **常见错误处理** - **复制因子不匹配错误**(引用[2]问题): ```log Number of alive brokers does not meet the required replication factor ``` **解决方案**: 修改 `__consumer_offsets` 主题的复制因子(需先停止 Kafka 服务): ```bash ./kafka-topics --zookeeper bigdata001:2181 \ --topic __consumer_offsets \ --alter --config min.insync.replicas=2 # 调整为可用Broker数 ``` 3. **Kerberos 认证环境** 若集群启用 Kerberos,需先获取凭证: ```bash kinit -kt kafka.keytab kafka/bigdata001@YOUR.DOMAIN ``` --- ### 四、新版本替代方案(CDH 6.x+) 使用 `kafka-consumer-groups` 替代: ```bash # 查看所有消费者组 ./kafka-consumer-groups --bootstrap-server bigdata001:9092 --list # 查看特定组详情 ./kafka-consumer-groups --bootstrap-server bigdata001:9092 \ --group your_group \ --describe --members --verbose ``` 输出包含: - **分区级偏移量**(PARTITION, CURRENT-OFFSET, LOG-END-OFFSET, LAG) - **消费者成员分配情况**(MEMBER-ID, HOST) - **当前状态**(STABLE, REBALANCING) --- ### 五、操作验证流程 1. 创建测试主题(引用[1]方法): ```bash ./kafka-topics --create --zookeeper bigdata001:2181 \ --replication-factor 3 --partitions 3 --topic lag_test ``` 2. 启动控制台消费者: ```bash ./kafka-console-consumer --bootstrap-server bigdata001:9092 \ --topic lag_test --group lag_test_group ``` 3. **检查偏移量**: ```bash # CDH 5.x ./kafka-consumer-offset-checker --zookeeper bigdata001:2181 --group lag_test_group # CDH 6.x ./kafka-consumer-groups --bootstrap-server bigdata001:9092 --group lag_test_group --describe ``` --- > **关键提示**: > - 老工具 `kafka-consumer-offset-checker` 依赖 Zookeeper,新工具 `kafka-consumer-groups` 直连 Broker,更符合架构演进趋势[^1][^2] > - 生产环境建议通过 Cloudera Manager 配置自动化监控(参见前文方案),避免手动检查 --- **
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值