kafka之五 生产者详解

a 夏天 提交于 2020-01-02 21:32:46

生产者详解

在这里插入图片描述

发送类型

  • 同步发送

     //通过send()发送完消息后返回一个Future对象,然后调用Future对象的get方法等待kafka响应
     //如果kafka正常响应,返回一个RecordMetadate对象,该对象存储消息的偏移量
     //如果kafka发生错误,无法正常响应,就会抛出异常,我们便可以进行异常处理
     producer.send(recore).get();
    
  • 异步发送

        producer.send(record,new Callback(){
       public void onCompletion(RecordMetadate metadata,Exception exception){
           if(exception == null){
            System.out.println(metadata.partition()+":"+ metadata.offset());
           }
       }
    })
    

序列化器

  • 消息要到网络上进行传输,必须进行序列化,而序列化器的作用就在此
  • kafka提供了默认的字符串序列化器(org.apache.kafka.common.serialization.StringSerializer),
    还有整型(IntegerSerializer)和字节数组(BytesSerializer)序列化器.
    这些序列化器都实现了接口(org.apache.kafka.common.serialization.Serializer),基本能满足大部分需求
  • 也能自定义序列化器.实现Serializer接口即可

分区器

  • 本身kafka有自己的分区策略,如果未指定,就会使用默认的分区策略
  • kafka根据传递小时的key来进行分区的分配,就会hash(key)%numPartitions.如果key相同的话
    ,那么就会分配到统一分区
 public int partition(String topic, Object key, byte[] keyBytes, Object value, byte[] valueBytes, Cluster cluster) {
        List<PartitionInfo> partitions = cluster.partitionsForTopic(topic);
        int numPartitions = partitions.size();
        if (keyBytes == null) {
            int nextValue = nextValue(topic);
            List<PartitionInfo> availablePartitions = cluster.availablePartitionsForTopic(topic);
            if (availablePartitions.size() > 0) {
                int part = Utils.toPositive(nextValue) % availablePartitions.size();
                return availablePartitions.get(part).partition();
            } else {
                // no partitions are available, give a non-available partition
                return Utils.toPositive(nextValue) % numPartitions;
            }
        } else {
            // hash the keyBytes to choose a partition
            return Utils.toPositive(Utils.murmur2(keyBytes)) % numPartitions;
        }
    }
  • 自定义分区:实现Partitioner接口,然后重写partition方法,在里面写自己分区的逻辑即可
public class DefaultPartition implements Partitioner {
    
    
    @Override
    public int partition(String topic, Object key, byte[] keyBytes, Object value, byte[] valueBytes, Cluster cluster) {
        List<PartitionInfo> partitions = cluster.partitionsForTopic(topic);
        int numPartitions = partitions.size();
        return Utils.toPositive(Utils.murmur2(keyBytes)) % numPartitions;
    }

    @Override
    public void close() {

    }

    @Override
    public void configure(Map<String, ?> configs) {

    }
     
}

拦截器

  • Producer拦截器是一个新的功能,他和consumer端interceptor在kafka0.10版本被引入
    主要用于是吸纳clients端的定制化控制逻辑
  • 生产者拦截器可以用于消息发送前做一些准备工作
  • 使用场景
    • 按照某个规则过滤掉不符合要求的消息
    • 修改消息的内容
    • 统计类需求
public class ProducerInterceptorPrefix implements ProducerInterceptor<String,String> {


    @Override
    public ProducerRecord<String, String> onSend(ProducerRecord<String, String> record) {
        // 再这里做消息的处理
        return null;
    }
    @Override
    public void onAcknowledgement(RecordMetadata metadata, Exception exception) {
    }
    @Override
    public void close() {
    }
    @Override
    public void configure(Map<String, ?> configs) {
    }
}

发送原理在这里插入图片描述

  • 消息发送的过程中,涉及到两个线程协同工作,主线程首先将业务数据封装成ProducerRecord对象,
    之后调用send()方法将消息放入RecordAccumulator(消息收集器,也是主线程和Sender线程直接的缓冲区)
    暂存.Sender线程负责将消息信息构成请求,并最终执行网络io的线程,它冲RecordAccumulator取出消息并批量发送出去,
    KafkaProducer是线程安全的,多线程共享使用同一个KafkaProducer对象

其他生产者参数

  • acks
    • acks指定必须有多少个分区副本接收消息,生产者才认为消息写入成功,用户检测数据丢失的可能性
    • acks=0:生产者在成功写入消息之前不会等待任何来自服务器的响应。无法监控数据是否发送成功,但可以以网络能够支持的最大速度发送消息,达到很高的吞吐量。
    • acks=1:只要集群的首领节点收到消息,生产者就会收到来自服务器的成功响应。
    • acks=all:只有所有参与复制的节点全部收到消息时,生产者才会收到来自服务器的成功响应。这种模式是最安全的,
    • 如果acks参数配置是整数类型,而不是字符串的话,就会抛出异常
      在这里插入图片描述
  • retries
    • 生产者从服务器收到的错误有可能是临时性的错误的次数,如果达到了这个次数,生产者会放弃
      重试并返回错误.默认生产者在每次重试之间等待100ms,可以通过retry.backoff.ms参数来修改这个时间间隔
  • batch.size
    • 该参数指定了一个批次可以使用的内存大小,按照字节数计算(而不是消息个数)。不能设置太多,会占内存,也不能设置调小,会频繁发送消息
  • max.request.size
    • 发送的请求大小,broker也有对可接受最大值有自己的限制(message.max.size),两边配置最好一致
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!