java客户端连接操作kafka-生产者

前言

本文主要介绍客户端连接kafka,发送消息的常用参数,常用api及扩展点

准备工作

因为我这里是使用的阿里云购买的ESC,需要讲前面的docker-compose文件中的ip地址,改成公网地址 并且防火墙以及安全组开放前面指定的端口号9092

kafka配置文件相关参数

server.properties

1. zookeeper.connect
zookeeper链接地址
2. listeners & advertised.listeners
客户端连接地址,后面针对公有云之内的机器
3. broker.id
指定 Kafka 集群中 broker 的唯一标识
4. log.dir和log.dirs
消息都是放在磁盘的,参数指定位置
5. message.max.bytes
指定 broker 所能接收消息的最大值

java客户端连接代码

public class ProducerFastStart {
    public static final String brokerList = "your:9092";
    public static final String topic = "test";
    public static void main(String[] args) {
        Properties properties = new Properties();
        properties.put("key.serializer",
                "org.apache.kafka.common.serialization.StringSerializer");
        properties.put("value.serializer",
                "org.apache.kafka.common.serialization.StringSerializer");
        properties.put("bootstrap.servers", brokerList);
        KafkaProducer<String, String> producer =
                new KafkaProducer<>(properties);
        ProducerRecord<String, String> record =
                new ProducerRecord<>(topic, "hello, Kafka!");
        try {
            producer.send(record);
        } catch (Exception e) {
            e.printStackTrace();
        }
        producer.close();
    }
}
复制代码
public class ConsumerFastStart {
    public static final String brokerList = "your:9092";
    public static final String topic = "test";
    public static final String groupId = "group.demo";
    public static void main(String[] args) {
        Properties properties = new Properties();
        properties.put("key.deserializer",
                "org.apache.kafka.common.serialization.StringDeserializer");
        properties.put("value.deserializer",
                "org.apache.kafka.common.serialization.StringDeserializer");
        properties.put("bootstrap.servers", brokerList);
        properties.put("group.id", groupId);
        KafkaConsumer<String, String> consumer = new KafkaConsumer<>(properties);
        consumer.subscribe(Collections.singletonList(topic));
        while (true) {
            ConsumerRecords<String, String> records =
                    consumer.poll(Duration.ofMillis(1000));
            for (ConsumerRecord<String, String> record : records) {
                System.out.println(record.value());
            }
        }
    }
}
复制代码

核心api及扩展点

上面是一个简单发送例子,具体代码不多做介绍,提几个关键点
1. producer.send(record)方法
a.是一个异步方法,返回的是一个future,可以利用这个future去做一些处理;
b.同时还可以指定callback,比较推荐这种;callback可以保证分区有序;不能保证topic有序

2. 序列化
a.可以使用kafka自带的序列化,比如StringSerializer Integer等等;但是生产者消费者要对应,可以使用json序列化
b.还可以自定义序列化,实现Serializer接口即可

3. 分区器
因为发送的数据,最终都要落到分区上,当我们没有指定分区时,就会由系统的分区器来帮我们计算;根据key的hash值去做处理
a.系统自带的DefaultPartitioner,根据MurmurHash2 算法处理
b.还可以自定义分区器,同样实现接口即可

4. 拦截器

以生产者拦截器为例,主要是实现ProducerInterceptor接口,并实现其中的这三个方法:

public ProducerRecord<K, V> onSend(ProducerRecord<K, V> record); 
public void onAcknowledgement(RecordMetadata metadata, Exception exception);
public void close();
复制代码

1.onSend:主要是在消息序列化以及计算分区前,可以对消息定制化
2.onAcknowledgement:这个主要是在消息被应答前(Acknowledgement),或者消息发送失败后调用;是优先于callback方法的
3.close():主要用于在关闭拦截器时执行一些资源的清理工作

使用:
实现自定义的 ProducerInterceptorPrefix 之后,并在 KafkaProducer 的配置参数 interceptor.classes中指定这个拦截器:

properties.put(ProducerConfig.INTERCEPTOR_CLASSES_CONFIG,
        ProducerInterceptorPrefix.class.getName());
复制代码

生产者其他核心参数

上面的简单例子,只设置了一些简单的参数,其他生产者的核心参数没有去介绍,使用的是默认值

1. acks:

  • acks = 1。默认值即为1。保证消息写入leader副本,否则会收到一个错误的响应;但是如果是在写入了leader副本,但是follower副本拉取之前leader宕机的话,消息就会丢失了
  • acks = 0。生产者发送消息之后不需要等待任何服务端的响应
  • acks = -1 或 acks = all。生产者在消息发送之后,要等 ISR 中的所有副本都成功写入(注意是ISR,可能不是所有的副本;所以还是可能存在消息丢失,要更可靠的话就要 min.insync.replicas等参数的联动)

据平常项目经验来看,除非是真的有很严苛的要求必须一个消息都不能丢失,否则acks=1即可,消息的可靠性一般都能满足了。(acks 设置为1,是消息可靠性和吞吐量之间的折中方案。)

2. max.request.size

这个参数用来限制生产者客户端能发送的消息的最大值,默认值为1048576B,即1MB。一般情况下,这个默认值就可以满足大多数的应用场景了。

3. retries和retry.backoff.ms

retries 参数用来配置生产者重试的次数,默认值为0;可以将这个参数调大来应对网络波动之类的;让kafka重试
重试还和另一个参数 retry.backoff.ms 有关,这个参数的默认值为100,它用来设定两次重试之间的时间间隔,避免无效的频繁重试(这个主要是要估算下故障恢复的时间)
同样的,非特殊场景,建议没必要更改设置;因为这样会破坏同一个分区kafka消息发送的顺序性,除非 搭配max.in.flight.requests.per.connection 配置为1,但是会影响吞吐量,一般没必要就不更改。

4. compression.type

这个参数用来指定消息的压缩方式,默认值为“none”,即默认情况下,消息不会被压缩

5. connections.max.idle.ms

这个参数用来指定在多久之后关闭闲置的连接,默认值是540000(ms),即9分钟

6. linger.ms

这个参数用来指定生产者发送 ProducerBatch 之前等待更多消息(ProducerRecord)加入 ProducerBatch 的时间,默认值为0。生产者客户端会在 ProducerBatch 被填满或等待时间超过 linger.ms 值时发送出去。增大这个参数的值会增加消息的延迟,但是同时能提升一定的吞吐量

7. receive.buffer.bytes

这个参数用来设置 Socket 接收消息缓冲区(SO_RECBUF)的大小,默认值为32768(B),即32KB。如果设置为-1,则使用操作系统的默认值

8. send.buffer.bytes

这个参数用来设置 Socket 发送消息缓冲区(SO_SNDBUF)的大小,默认值为131072(B),即128KB

9. request.timeout.ms 这个参数用来配置 Producer 等待请求响应的最长时间,默认值为30000(ms)

后话

生产者的原理,以及springboot中使用kafka的例子+原理后面再单独去介绍

Guess you like

Origin juejin.im/post/7068588181821587464