Spring Cloud Stream消費Kafka消息出錯時消費3次問題探究

背景

系統採用Spring Cloud Stream框架集成Kafka來實現異步消息。

問題

客戶端消費某個topic消息出錯時,會連續輸出這個消息內容3次,同時沒有提交offset。當有大量消息出錯時,topic出現消息積壓。

分析

首先,我們知道實現異步消息的系統架構一般包含3個部分:生產者Producer、消息中間件Broker、消費者Consumer。其中,

  1. 消息中間件Broker,是指二進制安裝包安裝的單機Kafka或利用zookeeper組成的Kafka集羣或者阿里雲Kafka集羣。

  2. 生產者Produer和消費者Consumer,是指基於kafka-clients包,實現我們業務邏輯的消息生產者及消費者。

而spring-cloud-stream,是一個高度可擴展的基於事件驅動的框架,在系統中屬於更高層級。系統層級:業務代碼 -> spring-cloud-stream -> spring-integration -> spring-messaging -> spring-kafka -> kafka-clients -> kafka broker。

其次,我們需要了解幾個關鍵點:

  1. Kafka Broker支持Consumer提交offset,僅此而已。offset自動提交及手動提交,是由Kafka Consumer實現的。

  2. 不要誤以爲offset自動提交,是指Kafka Broker在Consumer拉取消息後自己自動提交offset。

  3. kafka-clients的自動提交offset與spring-cloud-stream的自動提交offset不是一回事兒。

    • kafka-clients通過設置KafkaConsumer的enable.auto.commit=true來實現自動提交offset。

    • spring-cloud-stream有spring.cloud.stream.kafka.bindings.channelName.consumer.autoCommitOffset配置項,默認true;但spring-kafka有自己定義的一套AckMode(org.springframework.kafka.listener.AbstractMessageListenerContainer.AckMode定義),設置autoCommitOffset=true,spring-kafka會負責提交offset,不會利用kafka-clients的KafkaConsumer的自動提交機制(即KafkaConsumer屬性enable.auto.commit=false)。

那麼,解答上面的問題:1、爲什麼會連續消費3次?2、爲什麼之後不再消費,消息出現積壓?

1、沒有消費3次。客戶端只從Broker拉取了1次,spring-kafka使用RetryingAcknowledgingMessageListenerAdapter處理消息,在出現異常時,重新觸發我們業務邏輯再處理2次(spring-retry的RetryTemplate負責重試),一共3次。3次日誌是我們處理邏輯輸出的。

2、大量消息拉取後處理失敗,沒有向Broker提交offset,肯定會導致消息出現積壓。KafkaConsumer有存儲上次消費的offset,每次拉取都會把這個offset傳遞給Broker,從這個offset之後拉取消息,拉取不到,所以不再消費。重啓KafkaConsumer可以重新拉取消費。

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