深入分析Kafka生产者和消费者

本文深入探讨了Kafka的生产者和消费者。在生产者方面,讲解了消息发送流程、发送方式、属性配置、序列化器和分区器等;在消费者部分,涵盖了消费者属性、基础概念如消费者群组、分区再均衡、提交和偏移量策略等。通过理解这些概念,可以帮助优化Kafka的使用和提高消息处理效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Kafka生产者

消息发送的流程

在这里插入图片描述
生产者每发送一条消息都需要先创建一个ProducerRecord对象,并且需要指定目标主题、消息内容,当然还可以指定消息键和分区。之后就会调用send()方法发送该对象,由于生产者需要与Kafka Broker建立网络传输,必然需要先通过序列化器对消息的键和值对象序列化成字节数组,才能进行传输。
之后,分区器就会接收到数据,然后先确认ProducerRecord对象中是否指定了分区,如果指定分区那么就直接把指定的分区返回,如果未指定分区,分区器就会根据消息键进行选择分区。确认分区后,那么消息才能确认发送到哪个主题的哪个分区上。接下来,消息又会被添加到批次里,同一个批次的消息总是发送到同一个主题和分区上,最后生产者端会有一个独立线程负责将批次发送到相应的Broker上。
Broker接收到消息后会进行响应,消息写入成功,会返回生产者端一个RecordMetaData对象,这个对象记录了消息在哪个主题的分区上,同时还记录了消息在分区中的偏移量。消息如果写入失败,则会返回一个错误,而生产者会根据配置的重试次数进行重试,当超过重试次数还是失败,就会将错误信息返回给生产者端。

发送方式

发送并忘记

producer.send(record);//忽略返回值

同步发送

//接收返回值
Future<RecordMetadata> future = producer.send(record);
//调用get方法进行阻塞,获取结果
RecordMetadata recordMetadata = future.get();

异步发送

//发送时,指定Callback回调
producer.send(record, new Callback() {
   
   public void onCompletion(RecordMetadata metadata,Exception exception) {
   
         if(null!=exception){
   
           //异常处理
         }
         if(null!=metadata){
   
              System.out.println("message offset:"+metadata.offset()+" "
                                +"message partition:"+metadata.partition());
         }
   }
);

生产者属性配置

创建KafkaProducer时都需要为其指定属性,属性的配置可以参考org.apache.kafka.clients.producer 包下的 ProducerConfig 类,大部分属性都配置了合理的默认值,如果对内存使用、性能和可靠性方面有要求可以相应调整一些属性,下面介绍一些常用的配置属性:

  1. acks: 确认机制,控制生产者发送消息时,必须有指定多少个分区副本接收到信息后,生产者才能认为消息写入成功,可选配置如下:
    acks=0:生产者在成功写入消息之前是不会等待任何的来自服务器的响应。如果在此期间出现了异常,造成Broker没能收到消息,而此时生产者又得不到反馈,消息也就丢失了。但是因为生产者不需要去等待服务器的响应,吞吐量相对更高;
    acks=1:只要集群中分区的首领节点接收到消息,生产者就会收到来自服务器的成功响应。如果消息无法到达首领节点,生产者会收到一个错误响应,为了避免数据丢失,生产者会重发消息。不过,如果一个没有收到消息的节点成为新首领,消息还是会丢失。缺省使用这个配置;
    acks=all:只有当集群中所有的分区副本都接收到消息后,生产者才会受到一个来自服务器的成功响应。
  2. batch.size: 对于发往同一个分区的消息,生产者发送过程中会先将消息记录在一个批次中。该参数的作用就是控制一个批次占用的内存大小。一个批次内存被填满后,会一次性将批次里的所有消息发送给Broker,但生产者并一定会等到批次被填满后才进行发送,即使是一条消息也有可能被发送。该参数的大小是按照字节数计算的,缺省为16384(16k),批次内存满了新的消息就写不进去了。
  3. linger.ms: 该参数用于配合batch.size使用,作用是控制生产者在发送批次前等待更多消息加入批次的时间。当然如果batch.size指定的批次内存已经填满,就不会进行等待而是直接发送,反之发送的消息字节数远比batch.size小,那么就能够在linger.ms指定的时间内获得更多的消息,从而减少请求次数,提升消息的吞吐量。
  4. max.request.size: 该参数用来控制生产者发送请求最大大小,缺省为1M。如果请求只有一条消息,则约束消息大小不能超过1M,如果请求是一个批次,则约束批次中所有消息的总大小不能超过1M。需要注意这个参数与Kafka的server.properties配置文件中指定的message.max.bytes参数有关,如果生产者发送的消息超过 message.max.bytes 设置的大小,就会被 Kafka Broker拒绝。
  5. buffer.memory: 控制生产者内存缓冲区的大小。
  6. retries: 控制生产者在消息发送失败后,可以进行重试的次数,默认情况下每次重试过程都会等待100ms再进行重试,重试等待时间可以通过retry.backoff.ms 参数来调整。
  7. request.timeout.ms: 控制生产者发送消息后等待请求响应的最大时间,超过这个时间没有收到响应,那么生产者端就会重试,超过重试次数将会抛出异常,缺省为30s。
  8. max.in.flight.requests.per.connection: 控制生产者在接收到服务器响应之前可以发送多少个消息,如果需要保证消息在一个分区上的严格顺序,这个值应该设为 1,不过这样会严重影响生产者的吞吐量。
  9. compression.type: 该参数控制生产者进行压缩数据的压缩类型,可选值包括:[none,gzip,snappy],缺省是none。压缩数据适用于消息批次处理,处理的批次消息越多,压缩性能就越好。snappy 占用 cpu 少,提供较好的性能和可观的压缩比,更关注性能和网络带宽建议使用这个。而如果网络带宽紧张,可以用gzip,虽然会占用较多的 cpu,但提供更高的压缩比。

序列化器

创建KafkaProducer对象时,必须指定键和值的序列化器,一些业务场景可能需要自定义序列化器,那么只需要实现org.apache.kafka.common.serialization.Serializer 接口,重写serialize()方法定义序列化逻辑即可。但自定义序列化器可能更多会去结合特定业务场景使用,所以容易导致程序的脆弱性,如果需求做了调整相应的序列化器实现也可能需要调整。因此使用序列化器更推荐使用自带格式描述以及语言无关的序列化框架,比如Kafka 官方推荐的 Apache Avro。
Avro在文件的读写是依据schema而进行的,而schema是通过一个JSON文件进行描述数据的,可以把这个schema 内嵌在数据文件中。这样,不管数据格式如何变动,消费者都知道如何处理数据。但是内嵌的消息,自带格式,会导致消息的大小不必要的增大,消耗了资源。我们可以使用 schema 注册表机制,将所有写入的数据用到的 schema 保存在注册表中,然后在消息中引用 schema 的标识符,而读取的数据的消费者程序使用这个标识符从注册表中拉取 schema 来反序列化记录。

分区器

生产者在发送消息时需要创建ProducerRecord对象,ProducerRecord对象可以指定一个消息键。指定了消息键,那么分区器就会将拥有相同键的消息指定给同一个主题的同一个分区。如果没有指定消息键,那么会通过默认分区器,使用轮询算法将消息均衡发布到主题下的各个分区。默认分区器会对消息键进行散列,然后根据散列值将消息映射到特定的分区上,这样同一个消息键总是能够被映射到同一个分区,但是只有不改变主题分区数量的情况下,键和分区之间的映射才能保持不变,一旦增加了新的分区,就无法保证了,所以如果要使用键来映射分区,那就要在创建主题的时候把分区规划好,不要增加新分区。

自定义分区器

一些业务场景中数据可能会有侧重,比如按地区进行划分数据时,不同地区的消息量是不同的,那么这种情况下就可以根据消息值中的一些标识,去针对消息值进行做分区,会更适合对应的业务场景。自定义一个分区器只需要去实现org.apache.kafka.clients.producer.Partitioner该接口,重写partition()方法完成相应的分区逻辑。

Kafka消费者

消费者属性配置

消费者需要创建KafkaConsumer,创建该对象时也需要指定消费者相关属性,可以参考org.apache.kafka.clients.consumer 包下 ConsumerConfig 类,大部分属性都配置了合理的默认值,如果需要关注内存使用、性能和可靠性方面可以相应调整一些属性,下面介绍一些常用的配置属性:

  1. auto.offset.reset: 控制消费者读取一个没有偏移量的分区或者偏移量无效的情况下,消费者应该如何处理。可选值包括:[latest、earliest],缺省为latest,表示从最新的记录开始读取。而earliest则表示消费者从起始位置开始读取分区的记录。
  2. enable .auto.commit: 表示消费者是否自动提交偏移量,缺省为true。这个参数很关键,通常情况都需要设置为false,自行控制何时提交偏
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值