6.3.2 延迟操作与延迟缓存
客戶端的一個請求包括多個分區,服務端為每個請求都會創建一個延遲操作對象,而不是為每個分區創建一個延遲操作對象。服務端的“延遲操作緩存”管理了所有的“延遲操作對象”,緩存的鍵是每一個分區,緩存的值是分區對應的延遲操作列表。
如圖6-56所示,假設第一個延遲操作包含的分區有[Pl,P2,P3,P4,P5],第二個延遲操作包含的分區有[Pl,P3,P5,P6,P7]。在延遲緩存中,從分區的角度來看,分區Pl上有兩個延遲的操作,分區P2上只有一個延遲的操作,分區P3上有兩個延遲的操作。
下面的代碼模擬了延遲緩存(Purgatory)添加或刪除延遲操作(Operation)的方法。延遲操作有多個分區,延遲緩存保存了分區到延遲操作的映射關系。延遲緩存的watch()方法會將延遲操作對象加入到每個分區的值列表中。比如第一個延遲操作對象有[凹,凹,月,問,PS]這5個分區,那么延遲緩存中對應有5個映射關系,分別是[Pl->Operationl,P2->0perationl,P3->0perationl,P4->0perationl,PS->Operationl]。第二個延遲操作對象有[Pl,月,町,問,P7]這5個分區,延遲緩存會更新為7個元素:[Pl->List(Operationl,Operation2),P2->0perationl,P3->List(Operationl,Operation2),P4->0perationl,PS->List(Operationl,Operation2),P6->0peration2,P7->0peration2]。
每個延遲操作對象都是一個帶有超時的線程類。當延遲操作完成時,延遲緩存會調用remove()方法將延遲操作從延遲緩存中移除。比如,從延遲緩存中移除第二個延遲操作(Operation2)后,延遲緩存會從每個分區的值列表中刪除第二個延遲操作。最后延遲緩存會更新為[Pl->Operation2,P3->0peration2,PS->Operation2,P6->0peration2,P7->0peration2]。相關代碼如下:
注意:延遲緩存watch()和remove()方法的參數都是延遲操作對象,兩者分別表示監控延遲的操作,或者移除延遲操作的監控。
一個客戶端請求對應一個延遲的操作,一個延遲操作對應多個分區。在延遲緩存中,一個分區對應多個延遲操作。因為延遲操作的外部事件以分區為粒度,所以延遲緩存保存了分區到延遲操作的映射關系。延遲操作加入到延遲緩存,以分區作為緩存的鍵。外部事件也是從分區的角度,嘗試完成延遲的操作。
不同的延遲操作可能會有相同的分區,比如主題的副本數等于4,就會有3個備份副本向主副本同步數據。邢么主副本所在的服務端針對3個備份副本的拉取請求,就會存在3個延遲的拉取操作。但對于消費者而育,不同消費者的拉取請求,它們的分區一定不會相同。如圖6-57所示,分區Pl和凹的主副本在消息代理節點l上,有3個角色都和主副本有關:生產者、消費者、備份副本。
圖6-57中黑色的民條表示延遲的操作對象,服務端一共創建了6個延遲的操作對象。在延遲緩存中,只有2個鍵,分別是分區Pl和l分區P2,這2個分區在延遲緩存中對應的值如下。
- 分區Pl對應:延遲的生產、消費者l的延遲拉取、3個備份副本的延遲拉取,總共有5個延遲操作。
- 分區P2對應:延遲的生產、消費者2的延遲拉取、3個備份副本的延遲拉取,總共有5個延遲操作。
外部事件以指定的鍵嘗試完成延遲操作,圖6-58是圖6-57的簡化版本。消息代理節點l上仍然有2個分區,消費者和備份副本拉取主副本的方式保持不變,但生產者只寫消息到分區Pl。圖6-58中分區Pl相關的延遲操作用實線箭頭表示,分區P2相關的延遲操作用虛線箭頭表示。3個備份副本的延遲拉取除了拉取分區Pl,也會拉取分區凹,具體步驟如下。
(1)生產者追加消息集到分區Pl的主副本,由于ISR的備份副本還沒有發送應答,服務端創建延遲的生產。延遲緩存的內容為P1->DelayedProduce。 (2)消費者拉取分區凹的主副本消息,由于讀取的字節數不夠,服務端創建延遲的拉取(DelayedFetch1)。延遲緩存為P1->List(DelayedProduce,DelayedFetch1)。 (3)分區凹的第一個備份副本(第二個消息代理節點)發送拉取請求,拉取請求包括2個分區。由于讀取的字節數不夠,服務端創建延遲的拉取(DelayedFetch2),延遲緩存為P1->List(DelayedProduce,DelayedFetch1,DelayedFetch2),P2->DelayedFetch2o (4)分區Pl的第二個備份副本(第三個消息代理節點)發送拉取請求,拉取請求包括2個分區。由于讀取的字節數不夠,服務端創建延遲的拉取(DelayedFetch3),延遲緩存為P1->List(DelayedProduce,DelayedFetch1,DelayedFetch2,DelayedFetch3),P2->List(DelayedFetch2,DelayedFetch3)。 (5)分區凹的第三個備份副本(第四個消息代理節點)發送拉取請求,拉取請求包括2個分區。由于讀取的字節數不夠,服務端創建延遲的拉取(DelayedFetch4),延遲緩存為P1->List(DelayedProduce,DelayedFetch1,DelayedFetch2,DelayedFetch3,DelayedFetch4),P2->List(DelayedFetch2,DelayedFetch3,DelayedFetch4)。 (6)服務端處理分區Pl前2個副本的拉取請求,嘗試完成延遲的生產不能完成。服務端在處理第三個備份副本的拉取請求時,可以完成延遲的生產操作,返回分區Pl的生產結果給生產者。延遲的生產完成后,延遲緩存為:P1->List(DelayedFetch1,DelayedFetch2,DelayedFetch3,DelayedFetch4),P2->List(DelayedFetch2,DelayedFetch3,DelayedFetch4)。, (7)在步驟(6)之后,分區Pl的主副本增加了最高水位。但因為最高水位和拉取偏移藍的差距,仍然不滿足拉取請求的最少字節數,服務端嘗試完成消費者的延遲拉取也不能完成。 (8)生產者再次追加消息到分區凹,如果追加新的消息后,主副本的偏移量減去備份副本拉取請求的偏移量,滿足拉取請求的最少字節數,服務端就可以完成3個備份副本的延遲拉取。雖然備份副本的拉取請求包含2個分區,但只要讀取的總大小滿足最少字節數,服務端就可以返回拉取結果給備份副本。3個備份副本的延遲拉取完成后,延遲緩存為P1->DelayedFetch1。 (9)當增加主副本的最高水位,并且最高水位減去消費者的拉取偏移量大于最少字節數,服務端才可以完成消費者的延遲拉取,并返回拉取結果給消費者。消費者的延遲拉取也完成后,延遲緩存為空。總結下服務端處理生產請求、拉取請求過程中與延遲操作相關的幾個重要知識點。
(1)服務端在讀取或寫入本地日志后,因為生產請求要等待ISR集合的所有副本發送應答,拉取請求要等待收集足夠的消息,所以服務端會創建延遲的生產和延遲的拉取,并放入延遲緩存中。加入到延遲緩存的延遲操作,在外部事件發生時,會嘗試完成延遲的操作。 (2)一個延遲操作有多個分區,加入到延遲緩存中,鍵是每個分區,值是分區對應的延遲操作列表。外部事件發生時,服務端會以分區為粒度,嘗試完成這個分區中的所有延遲操作。如果指定分區對應的某個延遲操作可以被完成,那么延遲操作會從這個分區的延遲操作列表中移除。但這個延遲操作還有其他分區,其他分區中已經被完成的延遲操作也需要從延遲緩存中刪除。 (3)仍然以前面的示例為例,3個備份副本的延遲拉取都有2個分區Pl和凹,延遲緩存為[P1->L"ist(DelayedOperat"io『12,Delayed0perat"ion3,Delayed0perat"ion4),P2->L"ist(Delayed0perat"ion2,Delayed0perat"ion3,DelayedOperat"ion4)]。如果分區Pl的主副本新追加了一批消息,3個延遲拉取都收集到足夠的消息,延遲緩存會刪除分區Pl的所有延遲操作,只留下[P2->L"ist(Delayed0perat"ion2,Delayed0perat"ion3,DelayedOperat"ion4)]。最后,分區P2中的延遲操作也應該刪除,因為這3個延遲操作實際上都已經完成了。在具體實現上,外部事件通過指定分區嘗試完成延遲的操作,如果延遲操作可以完成,其他分區中的延遲操作并不會被立即刪除。這是因為分區作為延遲緩存的鍵,在服務端的數量會很多,如果一個個檢查所有的分區,再從延遲緩存中刪除已經完成的延遲操作,速度就會很慢。另外,如果采用這種方式,只要分區對應的延遲操作完成了一個,就要立即檢查所有分區,對服務端的性能影響比較大。以上面的示例為例,外部事件根據分區Pl嘗試完成延遲的操作,最多只會刪除分區Pl中可以完成的延遲操作,并不會刪除其他分區中已經完成的延遲操作。Kafka的延遲緩存還有一個清理器,會負責定時地清理所有分區中已經完成的延遲操作。下面再以延遲拉取和延遲生產為例,分析這兩種延遲操作的工作過程。
如圖6-59所示,3個分區的主副本在消息代理節點1,其他3個消息代理節點分別保存2個分區的備份副本。分區Pl有2條消息,分區P2有l條消息,分區P3有2條消息。3個消息代理節點向主劇本同步數據時,都不滿足最少的5字節,服務端創建3個延遲的拉取操作。
如圖6-60所示,生產者往分區Pl新追加了一條消息(深灰色方塊),服務知會嘗試完成分區Pl對應的延遲拉取。由于消息代理節點2對應的延遲拉取,它的數據仍然不足5字節,服務端不會完成延遲拉取;消息代理節點4對應的延遲拉取,它的數據滿足5字節,服務端可以完成這個延遲拉取。
如圖6-61所示,生產者繼續往分區Pl追加2條消息,消息代理節點2和消息、代理節點4繼續同步分區Pl的主副本數據,如果它們對應延遲拉取對象的數據都已經足夠了服務端就都可以完成這兩個延遲的拉取。
如圖6-62所示,從延遲緩存保存的數據來看,生產者追加消息到分區Pl,第一種場景完成了消息代理節點4對應的延遲拉取,第二種場景完成了消息代理節點2對應的延遲拉取,第三種場景則完成了消息代理節點2和消息代理節點4對應的延遲拉取。圖6-60對應了第一種場景,醫16-61對應了第三種場景。
注意:圖6-62中外部事件根據指定分區嘗試完成的延遲操作,用刪除線和淺色字體表示。其他分區中完成的延遲操作用淺色字體表示,它們并不會立即從延遲緩存中刪除,而是通過延遲緩存的清理器被定時清理掉。
延遲拉取共有兩種:備份副本和消費者的拉取。備份副本或消費者的拉取請求都可以有多個分區,但服務端完成延遲的拉取操作并不需要等待所有分區都收集夠最少字節數,它只需要所有分區加起來的大小滿足最少字節數,就可以返回拉取結果給備份副本或消費者。與拉取請求相反,生產請求如果有多個分區,服務端完成延遲的生產操作,必須等待所有分區都被ISR所有劇本同步后,才會返回生產結果給生產者。下面以服務端處理延遲生產的過程為例展開講解。
如圖6-63所示,服務端處理多個分區的生產請求,并將延遲操作加入延遲緩存。假設拉取請求的最少字節數等于l字節,這樣服務端就可以不考慮備份副本的延遲拉取,具體步驟如下。
總結
以上是生活随笔為你收集整理的6.3.2 延迟操作与延迟缓存的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 德国小红伞
- 下一篇: 怎么发现愿景和目标 | 进击