Spring Boot 自定义kafka 消费者配置 ContainerFactory最佳实践
Spring Boot 自定义kafka 消费者配置 ContainerFactory最佳实践
本篇博文主要提供一个在 SpringBoot 中自定义 kafka配置的实践,想象这样一个场景:你的系统需要监听多个不同集群的消息,在不同的集群中topic冲突了,所以你需要分别定义kafka消息配置。
此篇文章会在SpringBoot 提供的默认模板上提供扩展,不会因为你自定义了消费者配置,而导致原生SpringBoot的Kakfa模板配置失效。
引入 MAVEN 依赖
版本需要你自己指定
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>xxx</version>
</dependency>
<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka</artifactId>
<version>xxx</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.kafka/kafka-clients -->
<dependency>
<groupId>org.apache.kafka</groupId>
<artifactId>kafka-clients</artifactId>
<version>xxx</version>
</dependency>
引入Java配置类
/**
* 手动自定义 kafka 消费者 ContainerFactory 配置demo
*/
@Configuration
@EnableConfigurationProperties(KafkaProperties.class)
public class KafkaConsumerConfig {
@Autowired
private KafkaProperties properties;
@Value("${监听服务地址}")
private List<String> myServers;
@Bean("myKafkaContainerFactory")
@ConditionalOnBean(ConcurrentKafkaListenerContainerFactoryConfigurer.class)
public ConcurrentKafkaListenerContainerFactory<?, ?> kafkaListenerContainerFactory(
ConcurrentKafkaListenerContainerFactoryConfigurer configurer) {
ConcurrentKafkaListenerContainerFactory<Object, Object> factory = new ConcurrentKafkaListenerContainerFactory<>();
configurer.configure(factory, consumerFactory());
return factory;
}
//获得创建消费者工厂
public ConsumerFactory<Object, Object> consumerFactory() {
KafkaProperties myKafkaProperties = JSON.parseObject(JSON.toJSONString(this.properties), KafkaProperties.class);
//对模板 properties 进行定制化
//....
//例如:定制servers
myKafkaProperties.setBootstrapServers(myServers);
return new DefaultKafkaConsumerFactory<>(myKafkaProperties.buildConsumerProperties());
}
}
yml模板
#kafka配置,更多配置请参考:KafkaProperties
spring.kafka:
#公共参数,其他的timeout.ms, request.timeout.ms, metadata.fetch.timeout.ms保持默认值
properties:
#这个参数指定producer在发送批量消息前等待的时间,当设置此参数后,即便没有达到批量消息的指定大小(batch-size),到达时间后生产者也会发送批量消息到broker。默认情况下,生产者的发送消息线程只要空闲了就会发送消息,即便只有一条消息。设置这个参数后,发送线程会等待一定的时间,这样可以批量发送消息增加吞吐量,但同时也会增加延迟。
linger.ms: 50 #默认值:0毫秒,当消息发送比较频繁时,增加一些延迟可增加吞吐量和性能。
#这个参数指定producer在一个TCP connection可同时发送多少条消息到broker并且等待broker响应,设置此参数较高的值可以提高吞吐量,但同时也会增加内存消耗。另外,如果设置过高反而会降低吞吐量,因为批量消息效率降低。设置为1,可以保证发送到broker的顺序和调用send方法顺序一致,即便出现失败重试的情况也是如此。
#注意:当前消息符合at-least-once,自kafka1.0.0以后,为保证消息有序以及exactly once,这个配置可适当调大为5。
max.in.flight.requests.per.connection: 1 #默认值:5,设置为1即表示producer在connection上发送一条消息,至少要等到这条消息被broker确认收到才继续发送下一条,因此是有序的。
#生产者的配置,可参考org.apache.kafka.clients.producer.ProducerConfig
producer:
#这个参数可以是任意字符串,它是broker用来识别消息是来自哪个客户端的。在broker进行打印日志、衡量指标或者配额限制时会用到。
clientId: ${spring.application.name} #方便kafkaserver打印日志定位请求来源
bootstrap-servers: 127.0.0.1:8080 #kafka服务器地址,多个以逗号隔开
#acks=0:生产者把消息发送到broker即认为成功,不等待broker的处理结果。这种方式的吞吐最高,但也是最容易丢失消息的。
#acks=1:生产者会在该分区的leader写入消息并返回成功后,认为消息发送成功。如果群首写入消息失败,生产者会收到错误响应并进行重试。这种方式能够一定程度避免消息丢失,但如果leader宕机时该消息没有复制到其他副本,那么该消息还是会丢失。另外,如果我们使用同步方式来发送,延迟会比前一种方式大大增加(至少增加一个网络往返时间);如果使用异步方式,应用感知不到延迟,吞吐量则会受异步正在发送中的数量限制。
#acks=all:生产者会等待所有副本成功写入该消息,这种方式是最安全的,能够保证消息不丢失,但是延迟也是最大的。
#如果是发送日志之类的,允许部分丢失,可指定acks=0,如果想不丢失消息,可配置为all,但需密切关注性能和吞吐量。
acks: all #默认值:1
#当生产者发送消息收到一个可恢复异常时,会进行重试,这个参数指定了重试的次数。在实际情况中,这个参数需要结合retry.backoff.ms(重试等待间隔)来使用,建议总的重试时间比集群重新选举leader的时间长,这样可以避免生产者过早结束重试导致失败。
#另外需注意,当开启重试时,若未设置max.in.flight.requests.per.connection=1,则可能出现发往同一个分区的两批消息的顺序出错,比如,第一批发送失败了,第二批成功了,然后第一批重试成功了,此时两者的顺序就颠倒了。
retries: 2 #发送失败时重试多少次,0=禁用重试(默认值)
#默认情况下消息是不压缩的,此参数可指定采用何种算法压缩消息,可取值:none,snappy,gzip,lz4。snappy压缩算法由Google研发,这种算法在性能和压缩比取得比较好的平衡;相比之下,gzip消耗更多的CPU资源,但是压缩效果也是最好的。通过使用压缩,我们可以节省网络带宽和Kafka存储成本。
compressionType: "none" #如果不开启压缩,可设置为none(默认值),比较大的消息可开启。
#当多条消息发送到一个分区时,Producer会进行批量发送,这个参数指定了批量消息大小的上限(以字节为单位)。当批量消息达到这个大小时,Producer会一起发送到broker;但即使没有达到这个大小,生产者也会有定时机制来发送消息,避免消息延迟过大。
batch-size: 16384 #默认16K,值越小延迟越低,但是吞吐量和性能会降低。0=禁用批量发送
#这个参数设置Producer暂存待发送消息的缓冲区内存的大小,如果应用调用send方法的速度大于Producer发送的速度,那么调用会阻塞一定(max.block.ms)时间后抛出异常。
buffer-memory: 33554432 #缓冲区默认大小32M
#消费者的配置,可参考:org.apache.kafka.clients.consumer.ConsumerConfig
consumer:
#这个参数可以为任意值,用来指明消息从哪个客户端发出,一般会在打印日志、衡量指标、分配配额时使用。
#暂不用提供clientId,2.x版本可放出来,1.x有多个topic且concurrency>1会出现JMX注册时异常
#clientId: ${spring.application.name} #方便kafkaserver打印日志定位请求来源
# 签中kafka集群
bootstrap-servers: 127.0.0.1:8080 #kafka服务器地址,多个以逗号隔开
#这个参数指定了当消费者第一次读取分区或者无offset时拉取那个位置的消息,可以取值为latest(从最新的消息开始消费),earliest(从最老的消息开始消费),none(如果无offset就抛出异常)
autoOffsetReset: latest #默认值:latest
#这个参数指定了消费者是否自动提交消费位移,默认为true。如果需要减少重复消费或者数据丢失,你可以设置为false,然后手动提交。如果为true,你可能需要关注自动提交的时间间隔,该间隔由auto.commit.interval.ms设置。
enable-auto-commit: false
#周期性自动提交的间隔,单位毫秒
auto-commit-interval: 2000 #默认值:5000
#这个参数允许消费者指定从broker读取消息时最小的Payload的字节数。当消费者从broker读取消息时,如果数据字节数小于这个阈值,broker会等待直到有足够的数据,然后才返回给消费者。对于写入量不高的主题来说,这个参数可以减少broker和消费者的压力,因为减少了往返的时间。而对于有大量消费者的主题来说,则可以明显减轻broker压力。
fetchMinSize: 1 #默认值: 1
#上面的fetch.min.bytes参数指定了消费者读取的最小数据量,而这个参数则指定了消费者读取时最长等待时间,从而避免长时间阻塞。这个参数默认为500ms。
fetchMaxWait: 500 #默认值:500毫秒
#这个参数控制一个poll()调用返回的记录数,即consumer每次批量拉多少条数据。
maxPollRecords: 500 #默认值:500
listener:
#创建多少个consumer,值必须小于等于Kafk Topic的分区数。
ack-mode: MANUAL_IMMEDIATE
concurrency: 1 #推荐设置为topic的分区数
配置释义
点开 KafkaProperties 这个类,可以看到这个是SpringBoot 自动配置kafka的配置类,引入这个实例,就相当于你拿到了SpringBoot kafka配置模板的参数,就是上述贴的配置,然后再此基础上重新定义你需要改变的配置,这里主要讲消费者配置。
代码中举了个重写监听servers的例子:
//例如:定制servers
myKafkaProperties.setBootstrapServers(myServers);
@KafkaListener 使用 containerFactory
@Slf4j
@Component
public class ConsumerDemo {
//声明consumerID为demo,监听topicName为topic.quick.demo的Topic
//这个消费者的 containerFactory 是SpringBoot 提供的 kafkaListenerContainerFactory 这个bean
@KafkaListener(id = "demo", topics = "topic.quick.demo")
public void listen(String msgData) {
log.info("demo receive : " + msgData);
}
@KafkaListener(topics = "k010", containerFactory = "myKafkaContainerFactory")
public void listen(String msgData, Acknowledgment ack) {
log.info("demo receive : " + msgData);
//手动提交
//enable.auto.commit参数设置成false。那么就是Spring来替为我们做人工提交,从而简化了人工提交的方式。
//所以kafka和springboot结合中的enable.auto.commit为false为spring的人工提交模式。
//enable.auto.commit为true是采用kafka的默认提交模式。
ack.acknowledge();
}
}
如果在@KafkaListener属性中没有指定 containerFactory 那么Spring Boot 会默认注入 name 为“kafkaListenerContainerFactory” 的 containerFactory。具体源码可跟踪:KafkaListenerAnnotationBeanPostProcessor中的常量:
public static final String DEFAULT_KAFKA_LISTENER_CONTAINER_FACTORY_BEAN_NAME = "kafkaListenerContainerFactory";
Spring Boot 自定义kafka 消费者配置 ContainerFactory最佳实践的更多相关文章
- Spring Boot 2.X(四):Spring Boot 自定义 Web MVC 配置
0.准备 Spring Boot 不仅提供了相当简单使用的自动配置功能,而且开放了非常自由灵活的配置类.Spring MVC 为我们提供了 WebMvcConfigurationSupport 类和一 ...
- Spring Boot自定义Redis缓存配置,保存value格式JSON字符串
Spring Boot自定义Redis缓存,保存格式JSON字符串 部分内容转自 https://blog.csdn.net/caojidasabi/article/details/83059642 ...
- Spring Boot工程结构推荐程结构(最佳实践)
工程结构(最佳实践) Spring Boot框架本身并没有对工程结构有特别的要求,但是按照最佳实践的工程结构可以帮助我们减少可能会遇见的坑,尤其是Spring包扫描机制的存在,如果您使用最佳实践的工程 ...
- Spring Boot自定义配置与加载
Spring Boot自定义配置与加载 application.properties主要用来配置数据库连接.日志相关配置等.除了这些配置内容之外,还可以自定义一些配置项,如: my.config.ms ...
- 玩转Spring Boot 自定义配置、导入XML配置与外部化配置
玩转Spring Boot 自定义配置.导入XML配置与外部化配置 在这里我会全面介绍在Spring Boot里面如何自定义配置,更改Spring Boot默认的配置,以及介绍各配置的优先 ...
- 峰哥说技术:06-手撸Spring Boot自定义启动器,解密Spring Boot自动化配置原理
Spring Boot深度课程系列 峰哥说技术—2020庚子年重磅推出.战胜病毒.我们在行动 06 峰哥说技术:手撸Spring Boot自定义启动器,解密Spring Boot自动化配置原理 Sp ...
- Spring boot 集成Kafka
搭建Kafka集群,参考: https://www.cnblogs.com/jonban/p/kafka.html 源码示例如下: 1.新建 Maven 项目 kafka 2.pom.xml < ...
- Spring Boot 探索系列 - 自动化配置篇
26. Logging Prev Part IV. Spring Boot features Next 26. Logging Spring Boot uses Commons Logging f ...
- Spring Boot之实现自动配置
GITHUB地址:https://github.com/zhangboqing/springboot-learning 一.Spring Boot自动配置原理 自动配置功能是由@SpringBootA ...
随机推荐
- HDU - 1503 最长公共子序列记录路径
题意:先给两个水果的名字然后得出一个最短的序列包含这两个词. 思路:我一开始的思路是先求出最长公共子序列,然后做一些处理将其他的部分输出来:两种水果的字符串和最长公共子序列的字符串这三个字符串做对比, ...
- SpringBoot 集成ehcache
1, 项目实在springboot 集成mybatis 的基础上的: https://www.cnblogs.com/pickKnow/p/11189729.html 2,pom 如下,有的不需要加, ...
- Java刷题知识点总结
1,方法的重写(override)两同两小一大原则: 方法名相同,参数类型相同 子类返回类型小于等于父类方法返回类型, 子类抛出异常小于等于父类方法抛出异常, 子类访问权限大于等于父类方法访问权限. ...
- 使用golang理解mysql的两阶段提交
使用golang理解mysql的两阶段提交 文章源于一个问题:如果我们现在有两个mysql实例,在我们要尽量简单地完成分布式事务,怎么处理? 场景重现 比如我们现在有两个数据库,mysql3306和m ...
- 字典树基础进阶全掌握(Trie树、01字典树、后缀自动机、AC自动机)
字典树 概述 字典树,又称单词查找树,Trie树,是一种树形结构,是一种哈希树的变种.典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计.它 ...
- C 旅店
时间限制 : - MS 空间限制 : - KB 评测说明 : 1s,256m 问题描述 一条笔直的公路旁有N家旅店,从左往右编号1到N,其中第i家旅店的位置坐标为Xi.旅人何老板总在赶路.他白天 ...
- 消息队列 NSQ 源码学习笔记 (一)
nsqlookupd 用于Topic, Channel, Node 三类信息的一致性分发 概要 nsqlookup 知识点总结 功能定位 为node 节点和客户端节点提供一致的topic, chann ...
- codeforces 1038a(找最长的前k个字母出现相同次数的字符串)
codeforces 1038a You are given a string s of length n, which consists only of the first k letters of ...
- 使用Gitee搭建个人图床
使用Gitee搭建个人图床 一.前言 搭建个人的图床可以更加方便地管理个人图片,虽然Github也可以实现个人图床的搭建,但是,Github毕竟是外网,访问速度慢且不稳定.因此采用Gitee来搭建图床 ...
- Docker学习之搭建nginx环境
前言 很久没写随笔了,今天我们来学习一下如何在docker搭建nginx环境吧! 一:下载镜像,使用docker pull拉取最新的nginx镜像 命令:docker pull nginx 查看镜像: ...