上篇講到訊息從broker拉取後,會把訊息存入PullRequest的processQueue中。此時就會有其他執行緒,對這些訊息進行消費。
其他執行緒包括順序消費和併發消費。
併發消費
併發消費中,用於消費訊息的執行緒叫做ConsumeRequest,每一個ConsumeRequest預設消費32條訊息,如果需要消費的訊息超過32條,就會建立多個ConsumeRequest。這些ConsumeRequest就會放入執行緒池中等待執行。
ConsumeRequest執行緒執行的時候,會呼叫監聽器,拿到訊息消費的結果,併發消費的結果有兩種,RECONSUME_LATER和CONSUME_SUCCESS。
RECONSUME_LATER說明需要重新消費,但廣播模式下只列印警告級別的日誌,叢集模式下,重新封裝訊息成ConsumeRequest,再放入執行緒池,5s後再進行消費。
同時,也需要跟broker說,這個訊息消費失敗了。broker建立重試主題,並設定訊息重試次數,當訊息拉取超過重試次數後,就會進入DLQ佇列中。
有哪些訊息需要重新消費?比如這次訊息有10個,ackIndex是2,那下標為3到9的訊息,都要重新消費。如果這個結果是CONSUME_LATER,ackIndex就會被設定為-1,那就是所有的訊息,都要重新消費。
NSUME_SUCCESS說明消費成功,根據ackIndex計算一下成功和失敗的資訊。
對於RECONSUME_LATER或NSUME_SUCCESS的訊息處理完後,就要把訊息從ProcessQueue中移除,並更新OffsetStore裡的訊息消費進度。
OffsetStore裡的訊息消費進度會由一個定時任務,每5s會提交給broker,然後broker再更新偏移量。所以即便訊息消費成功了,但是還沒提交給broker的時候,當機了,那下次還是從之前的偏移量開始讀取資料,導致訊息重複消費。
順序消費
順序消費中,也是封裝一個ConsumeRequest,這個ConsumeRequest和併發消費的ConsumeRequest不同,他並沒有訊息列表,所以訊息直接從ProcessQueue拿。
執行緒消費的時候,首先會獲取一個鎖。這個鎖的粒度是訊息佇列,也就是說,一個訊息消費佇列,只能有一個執行緒進行消費。
獲取鎖後,就從ProcessQueue把訊息拿出來。
如果ProcessQueue有訊息,那還需要拿到ProcessQueue的ConsumeLock。
然後進行訊息消費,並通過監聽器拿到消費結果的狀態,並釋放鎖。
如果結果是SUCCESS,則更新ProcessQueue中的訊息消費資訊。
如果結果是SUSPEND_CURRENT_QUEUE_A_MOMENT,則會檢查訊息的重試次數。
如果這個重試次數超過允許的最大重試次數,就會把這個訊息傳送給broker,且存放在死信佇列中。
如果沒有超過,則會繼續重新消費,並累加消費次數。
最後,再更新OffsetStore裡的訊息消費進度。
OffsetStore的處理,和併發消費一樣。
執行緒拿到messageQueueLock鎖後,並不會一直持有這個鎖,預設消費60s,就會釋放這個鎖。