简介
kafka producer是kafka集群的发送消息的客户端,主要就是向某个topic的某个分区发送一条消息。partitioner决定向哪个分区发送消息。用户指定key,默认的分区器会根据key的哈希值来选择分区,如果没有指定key就以轮询的方式选择分区。也可以自定义分区策略。
旧版本:0.9.0.0版本以前,入口类:kafka.producer.Producer,同步机制,等待响应,吞吐性很差
新版本:0.9.0.0版本以后,入口类:o.a.k.clients.producer.KafkaProducer,异步机制,并提供了回调机制(callback)处理返回结果
本文使用的是新版本的kafka producer
版本
kafka server: 0.10.0.1-1
kakfa client: org.apache.kafka:kafka-clients:2.4.0
spring-kafka: org.springframework.kafka:spring-kafka:2.3.3.RELEASE
kafka版本匹配是非常坑的一个东西,后面的版本官方慢慢的做了调整。具体的kafka使用中详细的版本匹配可参考:
https://blog.csdn.net/qq_35754073/article/details/104106557
背景
项目需要把一些数据发送到kafka,然后由Kafka去做多数据中心的数据同步。本文主要是大并发的往kafka发送数据,需求是10000qps。完成了开发后在做qps测试的时候发生了很多问题,性能远远不能满足需求,针对这样的场景然后进行研究测试,最终得出一个比较好的配置,也在调优的时候对kafka producer有了一些更深的了解,再此分享也是自己进一步总结学习的过程。
使用
本文实在spring boot项目中使用的场景,所以对spring-kafka配置是进行了自动装配,所以在使用的时候只需要在application.yml对kafka producer进行必要的配置,然后写一个使用kafka producer发送message的工具类或者方法即可。所以优化的压力就大部分集中到了kafka的配置上。
先上代码:
spring:
kafka:
bootstrap-servers: localhost:9010
template:
default-topic: topic01
producer:
acks: 0
retries: 0
batch-size: 1638
buffer-memory: 33554432
compression-type: snappy
timeout.ms: 500
key-serializer: org.apache.kafka.common.serialization.StringSerializer
value-serializer: org.apache.kafka.common.serialization.StringSerializer
properties:
linger.ms: 50
request.timeout.ms: 500
max.block.ms: 500
metadata.fetch.timeout.ms: 500
max.in.flight.requests.per.connection: 20
问题
1.较小的延迟
2.保证发送结果的成功,失败需要处理
3.改变发送消息的timeout时间,防止堵塞引起的response时间太长(timeout时间默认是60s)
配置详解
- bootstrap.servers:kafka的服务器地址,可以配多个中间用‘,’分隔
- default-topic: 指定默认发送的topic,当在代码中不指定topic的时候就会默认使用这个topic
- acks:参数指定了要有多少个分区副本接收消息,生产者才认为消息是写入成功的。此参数对消息丢失的影响较大,下面是acks的配置选项,其中性能是依次下降,相反安全性则依次上升。
- acks = 0:表示生产者也不知道自己产生的消息是否被服务器接收了(只管发送,不管结果)。
- acks = 1:集群的 Leader 接收到消息,就会给生产者返回一条消息,告诉它写入成功。如果发送途中造成了网络异常或者 Leader 还没选举出来等其他情况导致消息写入失败,生产者会受到错误消息,这时候生产者往往会再次重发数据
- acks = all:只有当所有参与复制的节点都收到消息时,生产者才会接收到一个来自服务器的消息。
- retries: 发送失败后重试的次数,这个比较好理解,就是发送失败后客户端重新发送给后段的次数。默认情况下,生产者在每次重试之间等待 100ms,这个等待参数可以通过
retry.backoff.ms
进行修改。 - batch-size:按批发送时同一批次的内存大小。当有多个消息需要被发送到同一个分区时,生产者会把它们放在同一个批次里。该参数指定了一个批次可以使用的内存大小,按照字节数计算。当批次被填满,批次里的所有消息会被发送出去。不过生产者井不一定都会等到批次被填满才发送,任意条数的消息都可能被发送。
- buffer-memory:生产者内存缓冲区的大小,生产者用它缓冲要发送到服务器的消息。如果应用程序发送消息的速度超过发送到服务器的速度,会导致生产者空间不足。这个时候,send() 方法调用要么被阻塞,要么抛出异常,具体取于
block.on.buffer.null
参数的设置。 - compression-type:表示生产者启用何种压缩算法,默认情况下,消息发送时不会被压缩。该参数可以设置为 snappy、gzip 和 lz4,它指定了消息发送给 broker 之前使用哪一种压缩算法进行压缩。
- timeout.ms:broker 等待同步副本返回消息确认的时间,与 asks 的配置相匹配----如果在指定时间内没有收到同步副本的确认,那么 broker 就会返回一个错误。
- ingger.ms:是sender线程在检查batch是否ready时候,判断有没有过期的参数,默认大小是0ms。也就是说批量发送时满足batch.size和ling.ms之一,producer便开始发送消息。
- request.timeout.ms: 指定了生产者在发送数据时等待服务器返回的响应时间。
- metadata.fetch.timeout.ms: 指定了生产者在获取元数据(比如目标分区的首领是谁)时等待服务器返回响应的时间。如果等待时间超时,生产者要么重试发送数据,要么返回一个错误。
-
max.in.flight.requests.per.connection:指定生产者在收到服务器响应之前可以发送多少消息,它的值越高,就会占用越多的内存,不过也会提高吞吐量。把它设为1 可以保证消息是按照发送的顺序写入服务器。
红色参数表示对kafka性能影响比较大的参数,设置的时候需根据具体的需求设置合理的值。