spring-boot-route(十四)整合Kafka

在上一章中SpringBoot整合RabbitMQ,已經詳細介紹了消息隊列的作用,這一種我們直接來學習SpringBoot如何整合kafka發送消息。

kafka簡介

kafka是用Scala和Java語言開發的,高吞吐量的分佈式消息中間件。高吞吐量使它在大數據領域具有天然的優勢,被廣泛用來記錄日誌。

kafka架構分析

注1:圖中的紅色箭頭表示消息的流動過程,藍色表示分區備份,綠色表示kafka集羣註冊到zookeeper。

注2:在kafka0.9版本之前,消費者消費消息的位置記錄在zookeeper中,在0.9版本之後,消費消息的位置記錄在kafka的一個topic上。

kafka名詞簡介

  1. Producer:消息生產者
  2. Consumer:消息消費者
  3. Consumer Group(CG):消費者組,一個topic可以有多個CG,每個Partition只會把消息發送給GG中的一個Consumer
  4. Broker:一臺kafka服務器就是一個broker,一個broker有多個topic
  5. Topic:消息主題,消息分類,可看作隊列
  6. Partition:分區,爲了實現擴展,一個大的topic可能分佈到多個broker上,一個topic可以分爲多個partition,partition中的每條消息都會被分配一個有序的id(offset),每個partiton中的消息是有序的。
  7. Offset:kafka的存儲文件都是按照offset.kafka來命名的,方便查找,第一個offset爲0000000000.kafka。
  8. Leader:分區具有被備份,主分區
  9. Follower:從分區

1. 生產者分區策略

  1. 指定分區。
  2. 沒有指定分區但有key值,將key的hash值與當前topic的分區個數進行取餘得到分區。
  3. 如果既沒有指定分區又沒有指定key,第一次調用時隨機生成一個整數(以後調用每次在這個整數上自增),將這個隨機數與該topic的分區數取餘得到分區。

2. 消息可靠性問題

採用ack確認機制來保證消息的可靠性。

kafka在發送消息後會同步到其他分區副本,等所有副本都接收到消息後,kafka纔會發送ack進行確認。採用這種模式的劣勢就是當其中一個副本宕機後,則消息生產者就不會收到kafka的ack。

kafka採用ISR來解決這個問題。

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(三)實現多文件上傳

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(十一)數據庫配置信息加密

spring-boot-route(十二)整合redis做爲緩存

spring-boot-route(十三)整合RabbitMQ

spring-boot-route(十四)整合Kafka

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(二十二)實現郵件發送功能

spring-boot-route(二十三)開發微信公衆號

這個系列的文章都是工作中頻繁用到的知識,學完這個系列,應付日常開發綽綽有餘。如果還想了解其他內容,掃面下方二維碼告訴我,我會進一步完善這個系列的文章!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章