前言
本文主要介绍客户端连接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的例子+原理后面再单独去介绍