kafka 消费者消费不到数据_kafka的消费者

本文介绍了Kafka消费者在消费数据时涉及的概念,包括偏移量offset的存储和消费者组的工作原理。在新版本中,偏移量默认存储在consumer_offsets主题中。Coordinator负责消费者组的分区分配,通过选举机制确定并管理消费者的分区消费方案。文章还讨论了三种分区分配策略:range、round-robin和sticky,并提供了代码示例。
摘要由CSDN通过智能技术生成

11038f207e48f691a53f755b9f2e0a9d.png

前言

本文会设计到代码,本文最后会写如何消费数据。用到的kafka的版本为1.1.0.那么在写代码之前先来认识一些关于消费者的一些概念的东西

偏移量offset

首先在老版本中,kafka把偏移量写入到的是zookeeper 中,但是zookeeper并不是一个负责高并发读写的这么一个工具,所以从设计上存在缺陷,于是,后来kafka在新版本中,默认就设置了一个consumer_offsets话题,并有默认的分区为50个,当有偏移量需要写入的时候,就使写入到这个topic中,在提交的时候,key是以group.id+topic+分区号,如果你的kafka部署了一个很大的集群,那么可以应付高并发。

Coordinator

我们知道在consumer消费者中会有消费者组,也就是consumer group,那么消费者组的里面的消费者是不可以消费同一份数据的,比如一个消费者组中有两个消费者,其中一个消费者消费了msg-A ,那么另外一个消费者就不能再次消费这个数据msg-A.

当然了在实际中的情况是,每个consumer消费是一个分区,比如有3个分区,这个时候我们启动一个consumer group中有三个consumer最合适的,这样子,每个consumer都可以消费一个分区的数据。

那么如果分区多了,比如这个时候有10个分区,他又是如何分配的呢?是由睡来分配的呢?

这个时候coordinator就出场了,他主要就是管理将分区分配给consumer group中的每个分区的。

以下是这个分配的过程。

首先假设我们有三台broker,这个时候就会选举出一台broker作为coordinator,选举过程是根据group ID 计算出来一个hash值,计算出来以后就是一个数字,然后用这个数字对_consumer_offset的分区数(默认是50)取模,比如2,拿到2以后就到集群中去看partition为2的这个分区的leaderpartition在哪一台服务器上面,那么那一台服务器就是coordinator服务器。

选举出coordinator之后就开始指定分区消费方案,这里要要注意,不是coordinator来制定。

当上面选举出coordinator之后,这个时候,coordinator服务器会把这个消费者组中的所有消费者向coordinator向注册leader,然后选举出一个leader,这个消费者成为leader之后就开始制定分区的消费方案,然后将这个消费方案发给coordinator,coordinator会将这个分区方案发给这个消费者组中的每个消费者。

分区方案划分策略:

1.range策略

range策略就是按照partiton的序号范围

p0~3 consumer1

p4~7 consumer2

p8~11 consumer3

默认就是这个策略;这个策略就是,以序号范围分配给每个消费者。

2.round-robin策略

consumer1:0,3,6,9

consumer2:1,4,7,10

consumer3:2,5,8,11

这个就是滚动分配,比如第一个分区就是0,然后这个时候1分区就给第二个消费者,以此进行,直到所有的分区分配完毕。

3.sticky策略

这个策略很简单,就是前两个策略的集合,刚开始的时候,以段来分配,然后如果其中某个消费者挂了之后,那么以前他所管理的分区就以滚动分区的方式分配给其他存活的消费者。

代码

好,有了上面的基础知识,让我们开始写代码吧!

同样写代码之前需要先引入maven依赖

<dependency>
        <groupId>org.apache.kafka</groupId>
        <artifactId>kafka-clients</artifactId>
        <version>1.1.0</version>
      </dependency>

具体代码:

package com.cn.niochat.kafka;

import com.alibaba.fastjson.JSONObject;
import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.clients.consumer.KafkaConsumer;

import java.util.Arrays;
import java.util.Properties;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


public class KafkaConsumeMsg {
    private static ExecutorService threadPool = Executors.newFixedThreadPool(20);

    public static void main(String[] args) throws Exception {
        KafkaConsumer<String, String> consumer = createConsumer();
        consumer.subscribe(Arrays.asList("order-topic"));
        try {
            while(true) {
                ConsumerRecords<String, String> records = consumer.poll(Integer.MAX_VALUE);
                for(ConsumerRecord<String, String> record : records) {
                    JSONObject order = JSONObject.parseObject(record.value());
                    threadPool.submit(new CreditManageTask(order));
                }
            }
        } catch(Exception e) {
            e.printStackTrace();
            consumer.close();
        }
    }

    private static KafkaConsumer<String, String> createConsumer() {
        Properties props = new Properties();
        props.put("bootstrap.servers", "hadoop03:9092,hadoop04:9092,hadoop05:9092");
        props.put("group.id", "test-group");
        props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
        props.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
        props.put("heartbeat.interval.ms", 1000); // 这个尽量时间可以短一点
        props.put("session.timeout.ms", 10 * 1000); // 如果说kafka broker在10秒内感知不到一个consumer心跳
        props.put("max.poll.interval.ms", 30 * 1000); // 如果30秒才去执行下一次poll
        // 就会认为那个consumer挂了,此时会触发rebalance
        // 如果说某个consumer挂了,kafka broker感知到了,会触发一个rebalance的操作,就是分配他的分区
        // 给其他的cosumer来消费,其他的consumer如果要感知到rebalance重新分配分区,就需要通过心跳来感知
        // 心跳的间隔一般不要太长,1000,500
        props.put("fetch.max.bytes", 10485760);
        props.put("max.poll.records", 500); // 如果说你的消费的吞吐量特别大,此时可以适当提高一些
        props.put("connection.max.idle.ms", -1); // 不要去回收那个socket连接
        // 开启自动提交,他只会每隔一段时间去提交一次offset
        // 如果你每次要重启一下consumer的话,他一定会把一些数据重新消费一遍
        props.put("enable.auto.commit", "true");
        // 每次自动提交offset的一个时间间隔
        props.put("auto.commit.ineterval.ms", "1000");
        // 每次重启都是从最早的offset开始读取,不是接着上一次
        props.put("auto.offset.reset", "earliest");


        KafkaConsumer<String, String> consumer = new KafkaConsumer<String, String>(props);
        return consumer;
    }

    static class CreditManageTask implements Runnable {
        private JSONObject order;
        public CreditManageTask(JSONObject order) {
            this.order = order;
        }

        @Override
        public void run() {
            System.out.println("对订单进行积分的维护......" + order.toJSONString());
            // 就可以做一系列的数据库的增删改查的事务操作
        }

    }
}

总结

以上就是全部内容了,点击关注不迷路哦!

您好!对于 Kafka 消费者拉取不到数据的问题,可以有几种可能的原因和解决方法。以下是一些常见的排查步骤: 1. 确认主题和分区:首先,确保您的消费者订阅了正确的主题和分区。您可以通过检查消费者的代码或配置文件来确认这一点。 2. 检查消费者组:如果您的消费者属于一个消费者组,确保消费者组中有足够的消费者来处理分区中的消息。如果消费者组中的消费者数少于分区数,部分分区可能无法消费。 3. 检查消费者偏移量:Kafka 使用偏移量(offset)来跟踪消费者在分区中读取的位置。如果消费者的偏移量发生错误,可能会导致无法拉取到数据。您可以尝试重置消费者的偏移量,或者根据需要进行手动提交。 4. 检查消息生产者:确保消息生产者正常发送消息到 Kafka 集群,并且消息被正确地发布到相关主题和分区。 5. 检查网络连接:确保消费者能够与 Kafka 集群建立正常的网络连接。您可以尝试使用 Kafka 工具,如 kafka-console-consumer 或 kafka-console-producer 进行测试。 6. 检查消费者配置:检查消费者的相关配置,如 Kafka 集群的地址、端口、安全认证等,确保它们与实际情况一致。 7. 查看日志:查看消费者的日志文件,以了解任何错误或警告信息。日志文件通常位于消费者的工作目录中。 如果您能提供更多细节或错误信息,我可以给出更具体的指导。希望这些步骤对您有所帮助!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值