在上一章中SpringBoot整合RabbitMQ,已经详细介绍了消息队列的做用,这一种咱们直接来学习SpringBoot如何整合kafka发送消息。java
kafka简介
kafka是用Scala和Java语言开发的,高吞吐量的分布式消息中间件。高吞吐量使它在大数据领域具备自然的优点,被普遍用来记录日志。git
kafka架构分析
注1:图中的红色箭头表示消息的流动过程,蓝色表示分区备份,绿色表示kafka集群注册到zookeeper。github
注2:在kafka0.9版本以前,消费者消费消息的位置记录在zookeeper中,在0.9版本以后,消费消息的位置记录在kafka的一个topic上。redis
kafka名词简介:spring
- Producer:消息生产者
- Consumer:消息消费者
- Consumer Group(CG):消费者组,一个topic能够有多个CG,每一个Partition只会把消息发送给GG中的一个Consumer
- Broker:一台kafka服务器就是一个broker,一个broker有多个topic
- Topic:消息主题,消息分类,可看做队列
- Partition:分区,为了实现扩展,一个大的topic可能分布到多个broker上,一个topic能够分为多个partition,partition中的每条消息都会被分配一个有序的id(offset),每一个partiton中的消息是有序的。
- Offset:kafka的存储文件都是按照offset.kafka来命名的,方便查找,第一个offset为0000000000.kafka。
- Leader:分区具备被备份,主分区
- Follower:从分区
1. 生产者分区策略
- 指定分区。
- 没有指定分区但有key值,将key的hash值与当前topic的分区个数进行取余获得分区。
- 若是既没有指定分区又没有指定key,第一次调用时随机生成一个整数(之后调用每次在这个整数上自增),将这个随机数与该topic的分区数取余获得分区。
2. 消息可靠性问题
采用ack确认机制来保证消息的可靠性。数据库
kafka在发送消息后会同步到其余分区副本,等全部副本都接收到消息后,kafka才会发送ack进行确认。采用这种模式的劣势就是当其中一个副本宕机后,则消息生产者就不会收到kafka的ack。apache
kafka采用ISR来解决这个问题。bootstrap
ISR:Leader维护的一个和leader保持同步的follower集合。缓存
当ISR中的folower完成数据同步以后,leader就会向follower发送ack,若是follower长时间未向leader同步数据,则该follower就会被踢出ISR,该时间阀值的设置参数为replica.lag.time.max.ms
,默认时间为10s,leader发生故障后,就会从ISR中选举新的leader。服务器
注:本文所讲的kafka版本为0.11,在0.9版本之前成为ISR还有一个条件,就是同步消息的条数。
ack参数配置
0:生产者不等待broker的ack。
1:leader分区接收到消息向生产者发送ack。
-1(all):ISR中的leader和follower同步成功后,向生产者发送ack。
3. 消息一致性问题
假如leader中有10条消息,向两个follower同步数据,follower A同步了8条,follower B同步了9条。这时候leader宕机了,follower A和follower B中的消息是不一致的,剩下两个follower就会从新选举出一个leader。
-
LEO(log end offset):每一个副本的最后一个offset
-
HW(high watermark):全部副本中最小的offset
为了保证数据的一致性,全部的follower会将各自的log文件高出HW的部分截掉,而后再重新的leader中同步数据。
4. 消息重复性问题
在kafka0.11版本中引入了一个新特性:幂等性。启用幂等性后,ack默认为-1。将生产者中的enable.idompotence
设置为true,即启用了幂等性。
开启幂等性的Producer在初始化的时候会被分配一个PID,发往同一Partition的消息会附带Sequence Number。Broker端会对<PID,Partition,SeqNumber>作缓存,当具备相同主键的消息提交时,Broker只会缓存一条。可是每次重启PID就会发生变化,所以只能保证一次会话同一分区的消息不重复。
5. 消费者组分区分配策略
kafka有两种分配策略,一种是RoundRobin,另外一种是Range
RoundRobin是按照消费者组以轮询的方式去给消费者分配分区的方式,前提条件是消费者组中的消费者须要订阅同一个topic。
Range是kafka默认的分配策略,它是经过当前的topic按照必定范围来分配的,假若有3个分区,消费者组有两个消费者,则消费者A去消费1和2分区,消费者B去消费3分区。
6. 消费者offset维护
Kafka 0.9 版本以前,consumer默认将offset保存在zookeeper中,0.9 版本开始,offset保存在kafka的一个内置topic中,该topic为_consumer_offsets
。
7. 生产者事务
为了实现跨分区会话的事务,须要引入一个全局惟一的Tracscation ID,并将Producer 得到的PID与之绑定。这样当Producer重启后就能够经过正在进行的Transaction ID得到原来的PID。
为了管理Transcation ID,kafka引入了一个新的组件Transcation Coordinator。Producer就是经过和Transcation Coordinator交互得到Transction ID对应的任务状态。
Spring Boot 整合kafka
1. 引入kafka依赖
<dependency> <groupId>org.springframework.kafka</groupId> <artifactId>spring-kafka</artifactId> </dependency>
2. 配置kafka服务信息
spring: kafka: # kafka服务地址 bootstrap-servers: 47.104.155.182:9092 producer: # 生产者消息key序列化方式 key-serializer: org.apache.kafka.common.serialization.StringSerializer # 生产者消息value序列化方式 value-serializer: org.apache.kafka.common.serialization.StringSerializer consumer: # 消费者组 group-id: test-consumer-group # 消费者消息value反序列化方式 key-deserializer: org.apache.kafka.common.serialization.StringDeserializer # 消费者消息value反序列化方式 value-deserializer: org.apache.kafka.common.serialization.StringDeserializer
3. 消费者
@Component @Slf4j @KafkaListener(topics = {"first-topic"},groupId = "test-consumer-group") public class Consumer { @KafkaHandler public void receive(String message){ log.info("我是消费者,我接收到的消息是:"+message); } }
4. 生产者
@RestController public class Producer { @Autowired private KafkaTemplate kafkaTemplate; @GetMapping("send") public void send(){ String message = "你好,我是Java旅途"; // 第一个参数 topic // 第二个参数 消息 kafkaTemplate.send("first-topic",message); } }
本文示例代码已上传至github,点个star
支持一下!
Spring Boot系列教程目录
spring-boot-route(一)Controller接收参数的几种方式
spring-boot-route(二)读取配置文件的几种方式
spring-boot-route(五)整合Swagger生成接口文档
spring-boot-route(六)整合JApiDocs生成接口文档
spring-boot-route(七)整合jdbcTemplate操做数据库
spring-boot-route(八)整合mybatis操做数据库
spring-boot-route(九)整合JPA操做数据库
spring-boot-route(十一)数据库配置信息加密
spring-boot-route(十二)整合redis作为缓存
spring-boot-route(十三)整合RabbitMQ
spring-boot-route(十五)整合RocketMQ
spring-boot-route(十六)使用logback生产日志文件
spring-boot-route(十七)使用aop记录操做日志
spring-boot-route(十八)spring-boot-adtuator监控应用
spring-boot-route(十九)spring-boot-admin监控服务
spring-boot-route(二十)Spring Task实现简单定时任务
spring-boot-route(二十一)quartz实现动态定时任务
spring-boot-route(二十二)实现邮件发送功能
这个系列的文章都是工做中频繁用到的知识,学完这个系列,应付平常开发绰绰有余。若是还想了解其余内容,扫面下方二维码告诉我,我会进一步完善这个系列的文章!