Kafka producer

kafka源码分析之producer kafka源码分析之kafka producer发送数据源码分析 阅读详情

Kafka producer

producer概览

Kafka producer客户端负责向Kafka写入数据的应用程序。Kafka提供了多个语言版本的producer客户端。Kafka封装了一套二进制通信协议,对于producer而言,用户可以直接使用任意语言按照该协议的格式进行编程,实现消息的发送。

producer之间是相互独立的,producer首要功能就是向某个topic的某个分区发送消息,由分区器确定往topic的哪个分区发送消息,Kafka producer提供了一个默认的分区器,每条待发送消息指定key,默认分区器将根据key的哈希值选择目标分区如果没有指定key,默认分区器将使用轮询方式确认目标分区使消息能均匀分布在所有分区上。在确定目标分区后,需要确定这个分区的leader,即该分区leader副本所在的broker。producer有多种选择来实现消息发送,例如不等待任何副本的响应便返回成功,或只等待leader副本响应写入操作之后再返回成功
在这里插入图片描述
producer使用用户主线程即运行运行producer的线程将待发送消息封装进ProducerRecord类实例,并将其序列化后发送到partitioner,再由其确定目标分区后一同发送到位于producer程序中的一块内存缓冲区中,producer的另一个工作线程(I/O发送线程,即Sender线程)将实时从缓冲区中提取准备就绪的消息封装进一个批次,统一发送给对应的broker

构造producer

producer程序实例

以下代码为发送消息实例

    package com.aim.kafka.client.producer;

    import org.apache.kafka.clients.producer.KafkaProducer;
    import org.apache.kafka.clients.producer.Producer;
    import org.apache.kafka.clients.producer.ProducerRecord;
    import java.util.Properties;
    public class Sender {

        public void sendMessage(){
            //创建属性对象
            Properties properties = new Properties();
            //设置broker的地址,可以支持多个,这样当某些broker挂掉还可以使用其它broker。必须指定
            properties.put("bootstrap.servers", "172.23.16.83:9092");
            //发送到broker端的任何消息格式都必须是字节数组,因此需要进行序列化,指定key的序列化器,除使用默认提供的
            //序列化器,也可以通过实现Serializer接口,创建自定义序列化器
            properties.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
            //指定value部分的序列化器
            properties.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
            //指定Producer确认请求发送完成之前需要搜集到的反馈信息数量,0将不等待任何服务器的反馈直接认为发送成功
            //将等待leader节点写入本地日志,则认为发送成功,不关心follower节点同步情况,leader节点挂掉,但follwer节点又
            //没来得及同步,将导致消息丢失;all或-1 leader节点将等待所有副本确认之后在确认这条消息发送成功
            properties.put("acks", "-1");
            //设置发送消息重试次数
            properties.put("retries", 3);
            //批次大小
            properties.put("batch.size", 323840);
            //延迟时间
            properties.put("linger.ms", 10);
            //缓冲大小
            properties.put("buffer.memory", 33554432);
            //最大阻塞时间
            properties.put("max.block.ms", 3000);
            //构建生产者
            Producer producer = new KafkaProducer(properties);
            //发送消息
            producer.send(new ProducerRecord("my-topic", Integer.toBinaryString(1), Integer.toString(1)));
            //关闭生产者
            producer.close();
        }
    }

构造KafkaProducer对象:

  • 除直接通过属性对象初始化创建外也可指定keySerializer、valueSerializer创建
    Serializer<String> keySerializer = new StringSerializer();
    Serializer<String> valueSerializer = new StringSerializer();
    //构建生产者
    Producer producer2 = new KafkaProducer(properties, keySerializer, valueSerializer);

构造ProducerRecord对象

  • Java版本Producer使用ProducerRecord来表示每条消息,ProducerRecord提供了多个重载构造函数初始化,可以指定消息topic、分区、时间戳、key、value、headers等内容

发送消息

  • Producer发送消息的主方法是send方法,send方法有两个重载的方法,但Producer底层完全实现了异步化发送,并通过Future同时实现了同步发送和异步+回调两种方式

异步发送

    //构建生产者
    Producer producer2 = new KafkaProducer(properties, keySerializer, valueSerializer);
    producer2.send(new ProducerRecord("my-topic", "2"), (metadata, exception) -> {
        if(exception == null) {
            //消息发送成功
        } else {
            //执行错误处理逻辑
        }
    });

同步发送

    //构建生产者
    Producer producer = new KafkaProducer(properties);
    //发送消息,调用Future.get()将无限等待结果返回,get方法要么返回发送结果要么抛出异常。没有错误get将返回
    //RecordMetadata实例,包括消息发送的topic、分区及消息对应分区的位移信息
    try {
        producer.send(new ProducerRecord("my-topic",
                Integer.toBinaryString(1), Integer.toString(1))).get();
    } catch (Exception e) {
        e.printStackTrace();
    }

Kafka发送消息错误类型有两种

  • 可重试错误
  • 不可重试错误
可重试错误

可重试错误都继承自org.apache.kafka.common.errors.RetriableException,当设置重试次数后,在重试次数内自行恢复并不会抛出异常,但超过重试次数则会抛出异常如下

  • LeaderNotAvailableException:分区leader副本不可用,这种现象通常是leader换届选举期间,因此通常是瞬时异常,重试可自行恢复
  • NotControllerException: controller当前不可用,通常表明controller在经历新一轮的选举,可重试自动恢复
  • NetworkException: 网络瞬时故障导致的异常
不可重试错误

不可重试错误,Kafka无法处理的问题,如下

  • RecordToolLargeException:发送消息尺寸过大,超过规定大小上线
  • SerializationException:序列化失败
  • KafkaException:其他类型异常

关闭producer

  • 完成发送之后需要关闭producer,调用无参数close方法,producer会等待处理完之前的发送请求后再关闭;
    带超时参数close方法,会等待producer timeout超时然后强制退出

producer主要参数

producer参数详情查看

acks:指定producer发送响应前,leader broker必须确保已成功写入该消息的副本数。producer发送消息到kafka集群时,这条消息会被发送到指定topic分区leader所在的broker,producer等待从该leader broker返回消息的写入结果(具有超时时间的等待)以确定消息是否被成功提交,这一切完成后producer就可以继续发送新消息。leader broker何时发送写入结果返还给producer直接影响到消息的持久性及producer端的吞吐量

  • acks = 0:producer将不会等待leader broker返回处理结果,此时producer发送完消息后立即发送下一条消息。由于不接收发送结果,因此producer.send的回调也完全失去了作用,用户无法通过回调机制感知任何发送过程中的失败,所以这种设置并不能保证消息一定被成功发送,但吞吐量最高
  • acks = all 或者 -1:表示发送消息时,leader broker不仅将消息写入本地日志,同时还会等待ISR中其他副本成功写入它们各自的本地日志后,才发送响应结果给producer,这样可以达到最高消息持久性,但producer的吞吐量也是最低
  • acks = 1:producer发送消息后leader broker仅将消息写入本地日志,便发送响应结果给producer,不等待副本写入该消息。这是一种折中方案

buffer.memory:指定producer用于缓存消息的缓冲区大小,默认是33554432字节即32M,由于采用异步消息发送设计架构,producer启动时会首先创建一块内存缓冲区用于保存待发消息,然后由一个专属线程负责从缓冲区读取消息执行发送,这部分空间大小由buffer.memory指定,若producer向缓冲区写消息速度大于专属I/O线程发送消息速度,将造成缓冲区空间不断增大,此时producer会停止手头工作等待I/O线程追上来,若一段时间过后还是无法追上,producer将抛出异常

compression.type:设置producer端是否压缩消息,默认none,即不压缩消息。压缩消息可以降低网络I/O传输开销,提升整体吞吐量,但也会增加producer端机器但CPU开销。如果broker端的压缩参数设置的与producer不同,broker端写入消息时也会额外使用CPU资源进行解压缩-重压缩操作

retries:设置消息发送重试次数,排除瞬时故障导致的消息发送失败。但重试可能导致消息重复发送;可能导致消息乱序,producer会将多个消息发送请求缓存内存中,由于某种原因导致重试,可能造成消息流乱序,可以通过max.in.flight.request.per.connection
参数设置为1,确保producer某一时刻只能发送一个请求。retry.backoff.ms可以指定两次重试消息发送之间的间隔

batch.size:producer会将发往同一分区的多条消息封装进一个batch,当batch满时,producer将发送batch中所有消息,但并不总是等待batch满了才发送。batch.size设置的过小将导致吞吐量过低,设置的过大将给内存带来压力,无论能否填满,producer都会为batch分配固定大小的内存,同时消息延迟也会更大些。默认大小为16384,即16KB,这是比较保守的值可以适当增大该值

linger.ms:延迟发送时间,默认为0,即不关心batch是否填满,立即发送。设置该参数大于0,将等待设置时间,在该段时间发送的消息将放到一个批次发送,当在该段时间内,batch满了将立即发送,当在该时间段batch还没满也将立即发送

max.request.size:控制producer端能发送的最大消息大小,默认的1048576字节太小,通常无法满足企业级消息的大小要求

request.timeout.ms:producer发送请求给broker后,broker需要在规定时间内将处理结果返回给producer,默认30秒,如果在规定时间内仍然没有返回处理结果,producer就认为请求超时,并在回调函数中显示抛出TimeoutException异常,

消息分区机制

producer程序实例

Kafka producer发送消息很重要的一步就是要确定将消息发送到指定的topic的哪个分区中。producer提供了分区策略及对应分区器(partitioner),默认partitioner会尽力确保具有相同key的消息发送到相同分区上。若没有指定key,将以轮询的方式来确保topic的所有分区上消息是均匀分布的

自定义分区机制

对于有key的消息,producer自带的partitioner会根据murmur2算法计算消息key的哈希值,然后对总分区数求模得到消息要发送的目标分区号。用户也可以自定义分区策略

自定义分区策略:

  • 在producer中创建一个实现org.apache.kafka.clients.producer.Partitioner接口的类,主要分区逻辑在Partitioner.partition中实现
  • 用于构造KafkaProducer的Properties对象中设置partitioner.class参数

实现步骤:

1.实现partitioner接口。假设我们的消息中有一些消息使用于审计功能,这类消息的key会被固定地分配一个字符串"audit",我们让这类消息发送到topic的最后一个分区上,便于后续统一处理,对于相同topic下的其他消息则采用随机发送的策略发送到
其他分区上,此自定义分区策略的实现如下

    package com.aim.kafka.client.partitioner;
    import org.apache.commons.lang3.StringUtils;
    import org.apache.kafka.clients.producer.Partitioner;
    import org.apache.kafka.common.Cluster;
    import org.apache.kafka.common.PartitionInfo;

    import java.util.List;
    import java.util.Map;
    import java.util.Random;

    public class AuditPartitioner implements Partitioner {

        private Random random;

        /**
         * 实现必要资源的初始化工作
         *
         * @param configs
         */
        @Override
        public void configure(Map<String, ?> configs) {
            random = new Random();
        }

        /**
         * 实现自定义分区策略
         * @param topic
         * @param keyObj
         * @param keyBytes
         * @param value
         * @param valueBytes
         * @param cluster
         * @return
         */
        @Override
        public int partition(String topic, Object keyObj, byte[] keyBytes, Object value, byte[] valueBytes,
                             Cluster cluster) {
            String key = (String) keyObj;
            //获取topic对应可用分区
            List<PartitionInfo> partitionInfoList = cluster.availablePartitionsForTopic(topic);
            int partitionCount = partitionInfoList.size();
            int auditPartitionCount = partitionCount - 1;
            return StringUtils.isEmpty(key) || StringUtils.contains(key, "audit") ? auditPartitionCount
                    : random.nextInt(partitionCount - 1);
        }

        /**
         * 必要资源的清理工作
         */
        @Override
        public void close() {
        }
    }

2.指定partitioner.class

    properties.put(ProducerConfig.PARTITIONER_CLASS_CONFIG, "com.aim.kafka.client.partitioner.AuditPartitioner");
    Producer producer3 = new KafkaProducer(properties);
    producer3.send(new ProducerRecord<>("my-topic", "audit", "audit record"), (metadata, exception) -> {
        if (exception == null) {
            //消息发送成功
        } else {
            //执行错误处理逻辑
            if(exception instanceof RetriableException){
                //处理可重试瞬时异常
            } else {
                //处理不可重试异常
            }
        }
    });
    producer3.close();

消息序列化

默认序列化

kafka在网络中以字节的方式发送,支持用户给broker发送各种类型的消息,序列化器负责在producer发送消息前将消息转换成字节数组;解序列化器则将consumer接收到的字节数组转换成相应的对象,默认提供的序列化器如下

  • ByteArraySerializer: 什么都不做
  • ByteBufferSerializer: 序列化ByteBuffer
  • BytesSerializer: 序列化Kafka自定义Bytes类
  • DoubleSerializer: 序列化Double类型
  • IntegerSerializer: 序列化Integer类型
  • LongSerializer: 序列化Long类型
  • StringSerializer: 序列化String类型

producer已经初步建立序列化机制来序列化简单的消息类型,对于复杂的类型则需要自定义serializer。producer的序列化机制使用只需构造producer时指定key.serializer和value.serializer即可

    //发送到broker端的任何消息格式都必须是字节数组,因此需要进行序列化,指定key的序列化器,除使用默认提供的
    //序列化器,也可以通过实现Serializer接口,创建自定义序列化器
    properties.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
    //指定value部分的序列化器
    properties.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");

自定义序列化

Kafka支持用户自定义消息序列化,需要完成3件事情:

  • 定义数据对象格式
  • 创建自定义序列化类,实现org.apache.kafka.common.serialization.Serialize,在serialize方法中实现序列化逻辑
  • 在用于构造KafkaProducer的Properties对象中设置key.serializer或value.serializer

实例:

1.创建Java POJO对象

    package com.aim.kafka.client.serializer;

    public class User {
    private String firstName;

    private String lastName;

    private int age;

    private String address;

    public User(){
    }

    public User(String firstName, String lastName, int age, String address){
        this.firstName = firstName;
        this.lastName = lastName;
        this.age = age;
        this.address = address;
    }

    @Override
    public String toString() {
        return "User{" +
                "firstName='" + firstName + '\'' +
                ", lastName='" + lastName + '\'' +
                ", age=" + age +
                ", address='" + address + '\'' +
                '}';
    }
    }

2.实现serializer接口

    package com.aim.kafka.client.serializer;

    import com.fasterxml.jackson.databind.ObjectMapper;
    import org.apache.kafka.common.serialization.Serializer;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;

    import java.util.Map;

    public class UserSerializer implements Serializer {

        private static final Logger logger = LoggerFactory.getLogger(UserSerializer.class);

        @Autowired
        private ObjectMapper objectMapper;

        /**
         * 初始化
         * @param configs
         * @param isKey
         */
        @Override
        public void configure(Map configs, boolean isKey) {
            objectMapper = new ObjectMapper();
        }

        /**
         * 序列化
         * @param topic
         * @param data
         * @return
         */
        @Override
        public byte[] serialize(String topic, Object data) {
            byte[] ret = null;
            try {
                ret = objectMapper.writeValueAsString(data).getBytes("utf-8");
            } catch (Exception e) {
                logger.info("failed to serialize the object:{}", data, e);
            }
            return ret;
        }

        /**
         * 释放资源
         */
        @Override
        public void close() {

        }
    }

3.指定使用序列化器

    properties.put("value.serializer", "com.aim.kafka.client.serializer.UserSerializer");
        Producer producer4 = new KafkaProducer(properties);
        producer4.send(new ProducerRecord<>("my-topic", "audit", new User()), (metadata, exception) -> {
            if (exception == null) {
                //消息发送成功
            } else {
                //执行错误处理逻辑
                if(exception instanceof RetriableException){
                    //处理可重试瞬时异常
                } else {
                    //处理不可重试异常
                }
            }
        });
        producer4.close();

producer拦截器

producer端interceptor拦截器使得用户在消息发送前以及producer回调逻辑前有机会对消息做一些定制化需求,并且支持指定多个interceptor按顺序作用于同一条消息形成拦截链,interceptor的实现接口是org.apache.kafka.clients.producer.ProducerInterceptor,其方法如下:

  • onSend(ProducerRecord): 该方法封装进KafkaProducer.send方法中,运行在用户主线程中,producer确保消息被序列化以计算分区前调用该方法,用户可以在该方法中对消息做任何操作,但最好不要修改消息所属topic和分区,否则会影响目标分区计算
  • onAcknowledgement(RecordMetadata, Exception): 该方法会在消息被应答之前或消息发送失败时调用,并且通常都是在producer回调逻辑触发之前,onAcknowledgement运行在producer的I/O线程中,因此不要在该方法中放入很重的逻辑,否则会拖慢producer的消息发送效率
  • close: 关闭interceptor,主要执行一些资源清理工作

实例

下例是一个简单的双interceptor组成的拦截器,第一个interceptor在消息发送前将时间戳信息加到消息value的最前部;第二个interceptor在消息发送后更新成功发送消息数或失败发送消息数

1.第一个interceptor TimeStampPrependerInterceptor

    package com.aim.kafka.client.interceptor;

    import org.apache.kafka.clients.producer.ProducerInterceptor;
    import org.apache.kafka.clients.producer.ProducerRecord;
    import org.apache.kafka.clients.producer.RecordMetadata;

    import java.util.Map;

    public class TimeStampPrependerInterceptor implements ProducerInterceptor<String, String> {
        @Override
        public ProducerRecord<String, String> onSend(ProducerRecord<String, String> record) {
            return new ProducerRecord<>(record.topic(), record.partition(), record.timestamp(),
                    record.key(), System.currentTimeMillis() + "," + record.value().toString());
        }

        @Override
        public void onAcknowledgement(RecordMetadata metadata, Exception exception) {

        }

        @Override
        public void close() {

        }

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

        }
    }

2.第二个interceptor CounterInterceptor

    package com.aim.kafka.client.interceptor;

    import org.apache.kafka.clients.producer.ProducerInterceptor;
    import org.apache.kafka.clients.producer.ProducerRecord;
    import org.apache.kafka.clients.producer.RecordMetadata;

    import java.util.Map;
    import java.util.concurrent.atomic.AtomicInteger;

    public class CounterInterceptor implements ProducerInterceptor<String, String> {

        private AtomicInteger errorCounter = new AtomicInteger(0);
        private AtomicInteger successCounter = new AtomicInteger(0);

        @Override
        public ProducerRecord<String, String> onSend(ProducerRecord<String, String> record) {
            return record;
        }

        @Override
        public void onAcknowledgement(RecordMetadata metadata, Exception exception) {
            if(exception == null){
                successCounter.getAndIncrement();
            } else {
                errorCounter.getAndIncrement();
            }
        }

        @Override
        public void close() {
            //保存结果
            System.out.println("Successful sent:" + successCounter);
            System.out.println("Failed sent:" + errorCounter);
        }

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

        }
    }

3.在producer中指定interceptor::

    List<String> interceptors = new ArrayList<>();
        properties.put("value.serializer", "com.aim.kafka.client.serializer.UserSerializer");
        interceptors.add("com.aim.kafka.client.interceptor.TimeStampPrependerInterceptor");
        interceptors.add("com.aim.kafka.client.interceptor.CounterInterceptor");
        properties.put(ProducerConfig.INTERCEPTOR_CLASSES_CONFIG, interceptors);
        Producer producer5 = new KafkaProducer(properties);
        producer5.send(new ProducerRecord<>("my-topic", "audit", "bbbb"), (metadata,
                                                                           exception) -> {
            if (exception == null) {
                //消息发送成功
            } else {
                //执行错误处理逻辑
                if (exception instanceof RetriableException) {
                    //处理可重试瞬时异常
                } else {
                    //处理不可重试异常
                }
            }
        });
        producer5.close();

无消息丢失配置

Producer发送消息采用异步方式,仅仅把消息放入缓冲区,由一个专属I/O线程负责从缓冲区提取消息并封装进消息batch中,然后发送出去,如果I/O线程发送之前producer崩溃则缓冲区中数据全部丢失。

producer消息乱序,假设producer端发送两条消息,第一条消息因为网络抖动发送失败进入重试机制,第二条消息发送成功,当第一条消息重试发送成功后,可能第一条消息反而位于第二条消息之后

异步发送无消息丢失配置

    block.on.buffer.full = true
    acks = all or -1
    retries = Integer.MAX_VALUE
    max.in.flight.request.per.connection = 1
    使用带回调机制的send发送消息,KafkaProducer.send(record, callback)
    Callback逻辑中显式立即关闭producer,使用close(0)
    unclean.leader.election.enable = false
    replication.factor = 3
    min.insync.replicas = 2
    replication.factor > min.insync.replicas
    enable.auto.commit = false

producer端配置

block.on.buffer.full = true

  • Kafka 0.9.0.0标记为"deprecated",并使用max.block.ms参数替换,该参数设置当producer内存缓冲区被填满时producer处于阻塞状态并停止接收新消息而不是抛出异常。0.10.0.0之后版本可以直接设置max.block.ms

acks = all:

  • 必须所有follower都响应了发送消息才认为消息发送成功

retries = Integer.MAX_VALUE:

  • producer需要开启无限重试,producer只会重试可恢复异常,对于不可恢复异常并不会重试

max.in.flight.requests.per.connection = 1

  • 该参数设置为1主要防止topic同分区下的消息乱序问题,此消息限制producer在单个broker连接上能够发送的未响应请求的数量,因此设置为1,producer在某个broker发送响应之前无法在往该broker发送PRODUCER请求

使用带回调机制的send

  • 不要使用KafkaProducer单参数的send方法,使用该方法方法,kafka仅仅将消费发送出去,但并不关心消息是否发送成功,肯能导致消息丢失,需要调用带回调的方法发送消息

Callback逻辑中显式立即关闭producer

  • 在Callback失败处理逻辑中显示调用KafkaProducer.close(0),防止消息乱序,不使用close(0)默认情况下producer允许将未完成的消息发送出去,可能造成消息乱序

broker端配置

unclean.leader.election.enable = false:

  • 关闭unclean leader选举,不允许非ISR中的副本被选举成leader,从而避免broker端因日志水位阶段而造成消息丢失

replication.factor >= 3

  • 需要多个副本保存分区消息,设置3主要是参考hadoop及业界通用的三备份原则

min.insync.replicas > 1

  • 控制某条消息至少被写入到ISR多少个副本才算成功,设置大于1是为了让producer端发送语义的持久性。只有当producer端acks被设置成all或-1,该参数才有意义,不要使用默认值

确保replication.factor > min.insync.replicas

  • 两者若相等则只要有一个副本挂掉,分区就无法正常工作,虽然有很高的持久性,但可用性被极大降低, 推荐设置成replication.factor = min.insync.replicas + 1

消息压缩

数据压缩显著降低了磁盘占用、带宽占用,有效提升I/O密集型应用的性能,但压缩会引入CPU资源的占用。Producer端能将一批消息压缩成一条消息发送,broker端将这条压缩消息写入本地日志,当consumer端获取这条压缩消息时,会自定解压。但遇到需要进行消息格式转换等情况时broker端需要对消息进行解压缩然后重新压缩

支持的压缩算法

当前Kafka支持3中压缩算法:GZIP、Snappy、LZ4、zstd,通过compression.type开启消息压缩

    //设置压缩算法,默认不压缩
	properties.put(ProducerConfig.COMPRESSION_TYPE_CONFIG, "zstd");

算法性能比较与调优

KafkaProducer.send方法逻辑主要耗时在消息压缩,因此调优压缩算法至关重要。Kafka中压缩算法的性能,zstd>>LZ4>>Snappy>>GZIP,是否启用压缩的依据是I/O资源消耗与CPU资源消耗的对比。如果生产环境I/O资源非常紧张,producer程序消耗了大量网络带宽或broker端的磁盘占用率非常高,而producer端CPU资源非常富裕,可以考虑为producer端开启消息压缩

多线程处理

实际环境中使用一个用户主线程通常无法满足所需吞吐量目标,因此需要构建多个线程或多个进程来同时给Kafka集群发送消息

  • 多线程单KafkaProducer实例:全局构建一个KafkaProducer实例,多线程共享使用,由于KafkaProducer是线程安全,所以这种使用方式是线程安全,
  • 多线程多KafkaProducer实例:在每个producer主线程中都构建一个KafkaProducer实例,并且保证此实例在该线程中封闭

单KafkaProducer实例,所有线程共享一个KafkaProducer实例,实现简单,性能好,但所有线程共享一个内存缓冲区,可能需要较多内存,一旦producer某个线程崩溃导致KafkaProducer实例被破坏,则所有用户线程都无法工作

多KafkaProducer实例,每个线程维护专属的KafkaProducer实例,每个用户线程专属KafkaProducer实例,缓冲区空间及一组对应的配置参数,可以进行细粒度的调优,单个KafkaProducer崩溃不会影响其他producer线程工作。需要较大的内存分配开销

对于分区不多的Kafka集群而言,推荐第一种方法。对于拥有超多分区的集群而言,采用第二中方法具有较高的可控性

Kafka 之生产者(Producer) Kafka生产者是一个应用程序,它负责向 Kafka 主题发送消息。这些消息可以用于多种目的,如记录用户活动、收集物联网设备数据、保存日志消息或缓存即将写入数据库的数据。 阅读详情

相关推荐

图解Kafka Producer中的消息缓存模型

图解Kafka Producer中的消息缓存模型

石臻说AI(szzdzhp001) 【原名 石臻臻的杂货铺】 1万+

KafkaProducer详解

1.Producer简介 Kafka Producer 就是负责向Kafka 服务端,写入数据的程序。 Kafka 支持多种Producer库,主流的编程语言都覆盖到了。但是除了Java其他的语言都是由非Apach Kafka社区的人进行维护的。有其他语言的客户端需求,可以去这个网址去下载相应的信息。 kafakclients链接 2.构造Producer 2.1简单构造 1.构建配置文件 首先第一步是进行用户鉴权的操作(如果Kafka集群需要的话) 然后需要配置的三个主要参数 broker的地址 k

weixin_39034379的博客 1万+

【Kafka】kafka命令 kafka-console-producer

文章目录1.概述2.输入单挑数据3.批量导入数据3.无key型消息4.有key型消息 1.概述 消费者:【Kafka】kafka命令kafka-console-consumer.sh kafka-console-producer 命令的常用参数如下 参数值类型说明有效值--bootstrap-serverString要连接的服务器必需(除非指定--broker-list)形如:host1:prot1,host2:prot2--topicString(必需)接收消息的主题名称--broker-listStr

九师兄 2383

Kafka基础介绍之Producer

简介 我们知道要想使用Kafka,其实最开始就是要创建一个Producer来往其中写消息,可以称之为消息源头吧,没有Producer来写,也就谈不上后面的consumer读了。 写消息粗听起来很简单,但是我们仔细思考一下这里就有很多问题需要确认。比如你的应用可以接受某些消息没有成功写进去吗?或者能够接受有重复的消息被写入吗?亦或是你的应用对写入的速度和延时有要求吗? 各种应用显然对我上面提到的问题有不同的答案,比如说一个log系统,丢一条或者少一条数据并不重要,延时一个几十秒甚至几分钟也不是什么大的问

m0_64354070的博客 3349

《探秘 BME680温度湿度气压气体传感器模块:环境感知的卓越之选》:此文为AI自动生成

BME680 是一款由博世公司推出的集成环境传感器模块,在环境监测和物联网等领域中发挥着重要作用。它能够同时测量温度、湿度、气压和气体浓度等多个环境参数,为各种应用提供准确可靠的环境数据。该模块采用小巧的封装形式,便于集成到各种设备中,无论是智能家居、可穿戴设备还是工业监测系统,都能轻松适配。例如,在智能家居系统中,BME680 模块可以监测室内环境参数,如温度、湿度、气压和空气质量等。通过与智能家居控制器或智能手机应用程序的连接,用户可以实时了解室内环境状况,并根据需要进行调整。

zheng_ruiguo的专栏 1874

IAR9.30以上版本安装、注册、新建工程和配置过程详细介绍

IAR 一般是指一款嵌入式软件的集成开发环境,类似于 MDK-Keil 这款软件。IAR 对于不同的内核处理器,是对应不同的 IAR 软件的,IAR 到目前为止支持大部分的MCU,比如8051系列、ARM架构系列、MSP430系列、AVR系列等等这些常用的芯片架构。对于 ARM 架构的芯片,有对应的 IAR Embedded Workbench for ARM 软件平台,因为我主要是使用 ARM 架构芯片,下面安装、注册和使用都是基于这个版本进行介绍的。

luobeihai的博客 6万+

【Kafka】生产者Producer详解

详细讲解kafka的生产者

qq_43745578的博客 3122

紫光同创FPGA中ADF网表文件的黑匣子封装与PDS环境实战指南

本文详细介绍了在紫光同创FPGA开发环境中使用ADF网表文件进行黑匣子封装的实战指南。通过PDS环境配置、加密ADF生成、黑匣子集成及验证调试等步骤,帮助开发者实现核心IP保护,同时保持设计性能。特别适用于需要模块级代码保护的企业级FPGA开发场景。

weixin_33725239的博客 343

kafka学习笔记(三、生产者Producer使用教程——原理及最全配置参数解析)

生产者就是负责向kafka发送消息的应用程序。消息在通过send()方法发往broker的过程中,有可能需要经过和的一系列作用后才能被真正的发往broker。key用来指定消息的键,不仅是附加消息还可以用来计算分区号而可以让消息发往特定的分区。byte[]

Timmer的博客 4034

LIO-SAM编译ubuntu20.04 Noetic

一、下载二、编译&&解决报错报错如下。

Kenneth666888的博客 690

在 SAP S/4HANA 的 BP 事务里做保存前校验:BDT 事件、BUPA_FURTHER_CHECKS 与 CVI 扩展 BAdI 一次讲透

SAP BP事务保存前校验机制解析 摘要:本文系统梳理了SAP BP事务保存前的校验机制,揭示了三种关键校验点的差异与适用场景: BDT框架DCHCK事件:最靠近UI层,适合屏幕字段级校验,但API调用时可能失效 Classic BAdI BUPA_FURTHER_CHECKS:全局拦截点,可阻断整个BP保存,适合核心业务规则 CVI扩展校验:仅管控供应商/客户段落,需注意可能产生"BP已保存但段落未保存"的情况 文章通过真实案例(如黑名单校验、付款冻结等)展示了各校验点的最佳实践,并特

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 312

详解Kafka Producer

在 Kafka 中,我们把产生消息的那一方称为生产者,比如我们经常回去淘宝购物,你打开淘宝的那一刻,你的登陆信息,登陆次数都会作为消息传输到 Kafka 后台,当你浏览购物的时候,你的浏览信息,你的搜索指数,你的购物爱好都会作为一个个消息传递给 Kafka 后台,然后淘宝会根据你的爱好做智能推荐,致使你的钱包从来都禁不住诱惑,那么这些生产者产生的消息是怎么传到 Kafka 应用程序的呢?发送过程是怎么样的呢?尽管消息的产生非常简单,但是消息的发送过程还是比较复杂的,如图我们从创建一个。

weixin_62421895的博客 1192

展锐 Android 15 无听筒方案删除配置

【代码】展锐 Android 15 无听筒方案删除配置。

m0_60898338的博客 169

kafka producer的serializer

今天遇到问题,kafka的producer是的类型,却始终报错, [2015-01-14 15:10:22,837] ERROR Error serializing message for topic haidafu (kafka.producer.async.DefaultEventHandler) java.lang.ClassCastException: java.lang.String

在风中寻找 从清晨到日暮 1万+

[Dify实战] [安全合规] 用 Dify 优化安全巡检:从经验驱动到标准闭环-带绑定资源

摘要:企业信息系统安全管理中,安全合规巡检面临标准不统一、整改难追踪等痛点。本文提出基于Dify工具的智能化解决方案,通过自动化工作流实现标准检查清单生成、风险等级标注、整改建议输出及审计记录归档。方案采用结构化Prompt模板和Markdown输出格式,涵盖账号权限、数据安全等核心维度,并提供证据收集建议和闭环管理机制,帮助组织从人工经验驱动转向数据流程驱动的合规管理。配套可导入Dify的工作流文件将随后发布。

技术小甜甜:传播可落地技术,帮助个人和企业降低解决真实场景问题的成本 273

GitLab CI/CD .gitlab-ci.yml 关键词(十一):发布版本 release

本篇文章介绍使用GitLab CI/CD 发布一个版本,对外发布。并填写一些发布的信息。

知无涯 4724

【Kafka】Kafka源码解析之producer过程解读

【Kafka】Kafka源码解析之producer过程解读

芝兰生于深谷,不以无人而不芳 1596

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

Kafka幂等Producer和事务Producer

一、Kafka 消息交付可靠性 Kafka 对Producer和Consumer 需要处理的消息提供三种承诺: 最多一次(at most once):消息可能丢失,但绝不会被重发; 至少一次(at least once):消息不会丢失,但有可能被重复发送(默认此可靠性); 精确一次(at most once):消息不会丢失,也不会被重复发送。 目前,Kafka默认提供的交付可靠性保障是第二种,...

希望我的博客,能解决你工作中的问题 958

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

kafka producer

通过前面的架构简述,知道了Producer是用来产生消息记录,并将消息以异步的方式发送给指定的topic的某个partition的。另外还知道,它保证了消息的有序的发送。那么它是如何做到这些的呢?我们又该如何使用它的API来发送消息? Kafka Producer、Kafka Consumer相对于 Kafka Broker,都属于客户端。Kafka支持多种语言的客户端。下面就...

疯一样的女子 480

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

Kafka之Producer

通过https://www.cnblogs.com/tree1123/p/11243668.html 已经对consumer有了一定的了解。producer比consumer要简单一些。 一、旧版本producer 0.9.0.0版本以前,是由scala编写的旧版本producer。 入口类:kafka.producer.Producer 代码示例: Properties pro...

大数据流动 364

kafka producer总结

Kafka producer的ack的3种机制: 通过初始化producer时的producerconfig可以通过配置request.required.acks不同的值来实现。 0:这意味着生产者producer不等待来自broker同步完成的确认就继续发送下一条(批)消息。       此选项提供最低的延迟但最弱的耐久性保证,因为其没有任何确认机制。 1:这意味着producer在le

cuidongdong1234的专栏 4851

Kafka 的 Producer 如何实现幂等性

在数学中,幂等性是指一个操作执行多次与执行一次的效果相同。在分布式系统中,幂等性意味着对同一操作的多次重复执行不会产生额外的影响。对于 Kafka 的 Producer 来说,幂等性就是指发送同一条消息多次,Kafka 只会保存一份,不会出现重复消息。Kafka 的幂等性 Producer 为我们提供了一种可靠的消息发送机制,可以有效地避免消息重复发送带来的问题。通过设置合适的参数和处理异常情况,我们可以充分利用幂等性 Producer 的优势,提高系统的稳定性和可靠性。

我爱娃哈哈的专栏 1296

Kafka Producer

本文采用Kafka 0.8.2版本 OverviewProducer的作用生成数据(消息),并将其发送到Kafka集群(brokers)中。将消息发送给谁Producer在向Kafka集群发送消息时,需要指定发送到哪一个topic中。除此之外,还可以指定发送到该topic的哪一个partition中。消息的构成一条消息的成分,从逻辑上来说,由真正的消息数据(message)和元数据(metadat

肖韬的BLOG 5303

Kafka:Producer Config 配置

Producer Configs 配置 属性 描述 类型 默认值 bootstrap.servers 用于建立与kafka集群的连接,这个list仅仅影响用于初始化的hosts,发现全部的servers。格式:host1:port1,host2:port2,…,尽量不止一个,以防其中一个down了 list acks server完成producer requ

Nothing is impossible 2万+

kafka producer配置

以下是JAVA生产者的配置(2.X版本及以上): NAME DESCRIPTION TYPE DEFAULT VALID VALUES IMPORTANCE bootstrap.servers 这是一个用于建立初始连接到kafka集群的"主机/端口对"配置列表。不论这个参数配置了哪些服务器来初始化连接,客户端都是会均衡地与集群中的所有服务器建立连接。...

yuxianhui66的博客 414
上一篇: Kafka线上环境部署
下一篇: Kafka consumer
炒栗子不加糖
博客等级 码龄10年 68粉丝 123原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值