Java Kafka producer send 发送数据到Kafka,可能在Kafka的topic中消费不到的原因

陌路散爱 提交于 2020-09-27 10:04:18

一般发送数据到Kafka,就是new一个producer,然后简单到send就好了,就可以在kafka里面看到数据了,可以使用命令行的消费模式,但是你在写测试代码的时候,想看看数据是否真的写到kafka服务器了的时候,就发现,额,好像数据没发送到kafka服务器上似的,代码也看似没问题哦。Java代码如下:

    private void produceOnce(String toTopic) {
        Properties conf = new Properties();
        conf.setProperty(BOOTSTRAP_SERVERS_CONFIG, "192.168.1.191:9092");
        conf.put(ACKS_CONFIG, "all");
        conf.put(KEY_SERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringSerializer");
        conf.put(VALUE_SERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringSerializer");
        KafkaProducer<String, String> producer = new KafkaProducer<>(conf);
        List<String> list = Lists.newArrayList(
                "aaaa","bbb"
        );
        for (String v : list) {
            ProducerRecord<String, String> record = new ProducerRecord<>(toTopic, "k", v);
            try {
                //producer.send(record);
                producer.send(record).get();
            } catch (Exception e) {
                System.out.println(e.toString());
            }
        }
    }

注意,在使用producer发送数据的时候,有2行,一个是send(),一个send().get()。我把send给注释了,留下了带get的方法,在junit的测试方法中,使用简单的直接send,数据可能就发不到kafka去。带上get之后,就能发到kafka去。具体原因就跟这个kafka的producer的原理有关系了。

调用send方法,并不是说这个消息就会被发送到kafka服务器,他为了效率他只是把你这个消息 record暂时给发到一个队列去,等待kafka的线程来发送。可能这个线程还没好呢,junit方法的test方法已经走完了,jvm已经结束了,那个发送数据的kafka的线程也就gg了,但是get之后,他是需要等待发送的返回结果的,所以,在测试的时候,这个方法就能保证数据发到kafak服务器去了,而不是缓存在本地的队列中。

生产端ProducerRecord经过序列化器、分区器处理后,并不是直接发往broker端,而是发送到客户端的消息缓冲池(Accumulator) 中,最后交由Sender线程发往broker端。

缓冲池最大大小由参数buffer.memory控制,默认是32M,当生产消息的速度过快导致buffer满了的时候,将阻塞max.block.ms时间,超时抛异常,所以buffer的大小可以根据实际的业务情况进行适当调整。

发送到缓冲池中消息将会被分为一个一个的batch,分批次的发送到broker 端,批次大小由参数batch.size控制,默认16KB。这就意味着正常情况下消息会攒够16KB时才会批量发送到broker端,所以一般减小batch大小有利于降低消息延时,增加batch大小有利于提升吞吐量。

但是消息并不是必须要达到一个batch尺寸才会批量发送到服务端呢,Producer端提供了另一个重要参数linger.ms,用来控制batch最大的空闲时间,超过该时间的batch也会被发送到broker端。

整个流程大概分为如下几步

      1、构建一个KafkaProducer对象,初始化一些用到的组件,比如缓存区,Sender线程等

      2、如果配置了拦截器,可用对发送的消息进行可定制化的拦截或更改

      3、对Key,value进行序列化

      4、根据传入的参数,为消息选择合适的分区,具体怎么选,后面分析

      5、将消息按照分区发送到RecordAccmulator暂存,消息按照每个分区进行汇总

      6、后台Sender线程被触发后从RecordAccmulator里面获取消息然后构建成ClientRequest,怎么构建后面分析

      7、将ClientRequest封装成NetWorkClient准备发送

      8、NetWorkClient将请求放入KafkaChannel准备发送,然后执行网络IO,最后发送到kafka server

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!