上一篇提到,由於訊息佇列負載機制,會往pullRequestQueue佇列放入一個個的PullRequest。
這些PullRequest會有一個專門的執行緒,把它取出來並封裝成服務端的一個Request,傳送給broker。
在傳送服務端之前,需要知道broker的地址在哪,需要從什麼偏移量開始拉取(偏移量叢集模式存broker,廣播模式存本地),一次性拉多少資料。
broker收到請求後,就會從commitlog中,根據偏移量把所需要的訊息給取出來,由於broker的主從同步,這邊返回訊息的時候,也會告知下一次拉取是從主broker拉取還是slave的broker拉取資料。
從commit拉取訊息的時候,會有這幾個情況(下面忽略offsetCheckInSlave判斷):
- 當前訊息佇列並沒有訊息,則下次拉取訊息的時候,如果這個broker是主節點,還是這個偏移量。如果這個broker是從節點,則下次直接從0開始。
- 當前訊息佇列有訊息,但是我們拉取的偏移量比佇列裡最小的偏移量還小,比如我們需要拉取100的資料,但是訊息佇列的最小偏移量是500。則下次拉取訊息的時候,如果這個broker是主節點,還是這個偏移量。如果這個broker是從節點,則下次直接從500開始。
- 如果我們我們拉取的偏移量剛好等於訊息佇列裡最大的偏移量,所以我們也沒有資料可以消費了,那下次拉取的時候,還是100這個偏移量。
- 如果我們我們拉取的偏移量大於訊息佇列裡最大的偏移量,所以我們也沒有資料可以消費了,那下次拉取的時候,這裡還要判斷訊息佇列裡最小的偏移量是否等於0。
- 正常情況下,我們需要的訊息是在訊息佇列裡最小的偏移量和最大的偏移量之間,那就直接把資料從commitlog中取出來並返回。
消費端接收broker響應後,就會根據上面各個情況的偏移量進行更新,並且把訊息存入PullRequest的processQueue中。
並且再把PullRequest放入pullRequestQueue佇列中,等待下次拉取。
processQueue的訊息如果來不及消費,會一直的堆積,所以PullRequest在拉取訊息的時候,會先判斷processQueue裡的訊息數量是否已經超過1000,如果超過了,則當前不拉取,並放入pullRequestQueue佇列中,50ms後才可以繼續拉取。
此外還會判斷processQueue中訊息的大小、processQueue中佇列最大偏移量與最小偏離量的間距,如果超過了閾值,也會放入pullRequestQueue佇列中,50ms後才可以繼續拉取。