Kafka(二)Producer第一篇

一,Client开发


生产逻辑需要具备以下几个 步骤:
(1)配置生产者客户端参数及创建相应的生产者实例。
(2)构建待发送的消息。
(3)发送消息。
(4)关闭生产者实例。

public class Producer {
    private static final String BROKER_LIST = "localhost:9092";
    private static final String TOPIC = "TOPIC-A";
    public static Properties initConfig() {
        Properties properties = new Properties();
        // 以下3个必须
        properties.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, BROKER_LIST);
        properties.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName());
        properties.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName());
       
        // 客户端ID
        properties.put(ProducerConfig.CLIENT_ID_CONFIG, "eris-kafka-producer");
        // 重试次数
        properties.put(ProducerConfig.RETRIES_CONFIG, 3);
        // 成功收到消息分区副本数,默认为1,即leader副本收到就返回成功。注意是字符串!
        properties.put(ProducerConfig.ACKS_CONFIG, "1");
        // 生产者客户端能发送的消息的最大值,单位为B,默认1M
        properties.put(ProducerConfig.MAX_REQUEST_SIZE_CONFIG,  1048576);
        // Producer等待请求响应的最长时间,单位ms,默认值为30000
        properties.put(ProducerConfig.REQUEST_TIMEOUT_MS_CONFIG,  30000);
        // 生产者发送ProducerBatch之前等待更多ProducerRecord加入的时间。默认为0,ProducerBatch被填满时发出
        properties.put(ProducerConfig.LINGER_MS_CONFIG,  0);
        return properties;
    }

    public static ProducerRecord<String, String> initMessage() {
        return new ProducerRecord<>(TOPIC, "hi eris");
    }

    public static void main(String[] args) {
        Properties properties = initConfig();
        KafkaProducer<String, String> kafkaProducer = new KafkaProducer<String, String>(properties);
        ProducerRecord record = initMessage();
        kafkaProducer.send(record);
        kafkaProducer.close();
    }
}

注意:KafkaProducer,它是线程安全的,我们可以在多线程的环境中复用它。
而 消费者客户端KafkaConsumer是非线程安全的。
1,发送消息的构造
消息对象是ProducerRecord,业务信息是value字段。

  • key可以让消息再二次归类,同一个key的消息会被划分到同一个分区中;
  • topic属性和value属性是必填项,其余属性是选填项;

2,主要Producer参数
ProducerConfig.BOOTSTRAP_SERVERS_CONFIG并非需要所有的broker地址,生产者会从给定的broker里查找到其他broker的信息,一般至少要2个。
3, 消息的发送
3-1,消息发送的3种模式:发后即忘、同步及异步
A,发后即忘:
kafkaProducer.send(record);
B,同步:
kafkaProducer.send(record).get();
C,异步:

  • 不推荐手动用future实现业务异步,诸多消息对应的Future对象的处理会引起逻辑的混乱。
  • 对于同一个分区,如果消息record1于record2之前先发送,那么KafkaProducer可以保证对应的callback1在callback2之前调用,也就是说 ,回调函数的调用也可以保证分区有序。

3-2,KafkaProducer中一般会发生两种类型的异常:可重试的异常和不可重试的异常。
对于可重试异常,如果配置了 retries 参数,那么只要在规定的重试次数内自行恢复了,就不会抛出异常;不可重试异常会直接抛出异常。
3-3,close方法会回收资源,并且阻塞等待之前所有的发送请求完成后再关闭 KafkaProducer,可带timeout。
3-4,消息在通过send发往broker的过程中,有可能需要经过拦截器(Interceptor)、序列化器(Serializer)和分区器(Partitioner)才能被真正地发往 broker。
4,序列化
生产者需要用序列化器(Serializer) 把对象转换成字节数组才能通过网络发送给Kafka。
如果 Kafka 客户端提供的几种序列化器都无法满足需求,则可以选择使用如Avro、JSON、Thrift、ProtoBuf和Protostuff等通用的序列化工具来实现,或者使用 自定义的序列化器来实现
5,分区器
如果ProducerRecord中指定了partition字段,那么就不需要分区器的作用。
反之若没有指定partition字段,那么就需要依赖分区器, 根据key这个字段来计算partition的值。

  • 如果key不为null,计算得到的分区会是所有分区中的任意一个;
  • 如果key为null,计算得到的分区号仅为可用分区中的任意一个;

一旦主题中增加了分区,那么就难以保证key与分区之间的映射关系了。
可以自定义分区器。
6,拦截器
自定义拦截器需要实现org.apache.kafka.clients.producer.ProducerInterceptor接口,接口中包含3个方法:

  • onSend:将消息序列化和计算分区之前调用;
  • onAcknowledgement:消息被应答(ack)之前或消息发送失败时调用,优先于用户设定的 Callback之前执行;
  • interceptor.classes配置拦截器链(逗号分隔),拦截链会按照参数配置的顺序一一执行。如果某个拦截器执行失败,下一个拦截器会接 着上一个执行成功的拦截器继续执行。

二,重要参数


1.acks
用来指定分区中必须要有多少个副本收到这条消息,之后生产者才会认为这条消息是成功写入的。

  • ack=1(默认),leader写入(落盘)即成功;
  • ack=0,发送后就认为成功,不需要等待任何服务端的响应;
  • ack=-1或者ack="all",需要ISR中的所有副本都成功写入;

2,retries
生产者重试的次数,默认值为0,即不重试。
保证消息顺序
max.in.flight.requests.per.connection
该参数指定了生产者在收到服务器响应之前可以发送多少个消息(即最多缓存的请求数)。它的值越高,就会占用越多的内存,不过也会提升吞吐量。把它设为 1 可以保证消息是按照发送的顺序写入服务器的,即使发生了重试。
如果把 retries 设为非零整数,同时把 max.in.flight.requests.per.connection 设为比 1 大的数,那么,如果第一个批次消息写入失败,而第二个批次写入成功,broker 会重试写入第一个批次。如果此时第一个批次也写入成功,那么两个批次的顺序就反过来了。
一般来说,如果某些场景要求消息是有序的,那么消息是否写入成功也是很关键的,所以不建议把 retries 设为 0。可以把 max.in.flight.requests.per.connection 设为 1,这样在生产者尝试发送第一批消息时,就不会有其他的消息发送给 broker。不过这样会严重影响生产者的吞吐量,所以只有在对消息的顺序有严格要求的情况下才能这么做。
3,linger.ms
这个参数用来指定生产者发送ProducerBatch之前等待更多ProducerRecord加入ProducerBatch的时间,默认值为0,即生产者会在 ProducerBatch 被填满时发送出去。
其他:

相关推荐
道一云黑板报3 小时前
Flink集群批作业实践:七析BI批作业执行
大数据·分布式·数据分析·flink·kubernetes
qq_5470261793 小时前
Kafka 常见问题
kafka
core5123 小时前
flink sink kafka
flink·kafka·sink
飞来又飞去4 小时前
kafka sasl和acl之间的关系
分布式·kafka
MZWeiei5 小时前
Zookeeper的监听机制
分布式·zookeeper
莹雨潇潇5 小时前
Hadoop完全分布式环境部署
大数据·hadoop·分布式
浩哲Zhe6 小时前
RabbitMQ
java·分布式·rabbitmq
明达技术7 小时前
分布式 IO 模块:赋能造纸业,革新高速纸机主传动
分布式
Allen Bright7 小时前
RabbitMQ中的Topic模式
分布式·rabbitmq
李洋-蛟龙腾飞公司9 小时前
HarmonyOS Next 应用元服务开发-分布式数据对象迁移数据权限与基础数据
分布式·华为·harmonyos