天天看點

【Kafka】如何保證消息有序性1. 消息有序性2. 發送端消息有序性3. 接收端消息有序性參考

文章目錄

  • 1. 消息有序性
  • 2. 發送端消息有序性
    • 2.1 Kafka如何保證單partition有序?
    • 2.2 client消息發送原理
  • 3. 接收端消息有序性
  • 參考

1. 消息有序性

我們需要從2個方面看待消息有序性

  • 第一,發送端能否保證發送到伺服器的消息是有序的
  • 第二,接收端能否有序的消費伺服器中的資料

發送端一般通過同步發送實作,即一次僅發送一條,等傳回成功後,再發送下一條,接收端一般僅通過一個消費者參與消費實作

2. 發送端消息有序性

2.1 Kafka如何保證單partition有序?

Kafka分布式的機關是partition,同一個partition用一個write ahead log組織,是以可以保證FIFO的順序。不同partition之間不能保證順序。但是絕大多數使用者都可以通過message key來定義,因為同一個key的message可以保證隻發送到同一個partition,比如說key是user id,table row id等等,是以同一個user或者同一個record的消息永遠隻會發送到同一個partition上,保證了同一個user或record的順序。

也就說通過隊列,保證partition上的資料元素是有序的。通過設定相同的路由,讓多個資料被路由到同一個partition即可。

2.2 client消息發送原理

下面,我們要如何保證資料從client發送到伺服器上的partition是有序的?

先閱讀 深入圖解Kafka producer 發送過程
  • 消息發送對于使用者線程有同步和異步之分

    同步能保證逐條發送消息,并保證是有序的

    異步通常也是有序的,因為tcp長連接配接方式 按序讀取InFlightRequests隊列并發送至伺服器上,tcp保證是有序的。但是如果開啟了重試機制,可能會導緻亂序。

  • 背景的發送線程隻有異步方式

異步場景下開啟重試政策時:

max.in.flight.requests.per.connection=5 預設值,控制發送視窗的大小,即連續發送次數

如果把 retries 設為非零整數,同時把 max.in.flight.requests.per.connection 設為比 1 大的數,那麼,如果第一個批次消息寫入失敗,而第二個批次寫入成功,broker 會重試寫入第一個批次。如果此時第一個批次也寫入成功,那麼兩個批次的順序就反過來了。

如果發送端配置了重試機制,kafka不會等之前那條消息完全發送成功才去發送下一條消息,這樣可能會出現,發送了1,2,3條消息,第一條逾時了,後面兩條發送成功,再重試發送第1條消息,這時消息在broker端的順序就是2,3,1了

一般來說,如果某些場景要求消息是有序的,那麼消息是否寫入成功也是很關鍵的,是以不建議把retries設為 0。可以把 max.in.flight.requests.per.connection 設為 1,這樣在生産者嘗試發送第一批消息時,就不會有其他的消息發送給broker。不過這樣會嚴重影響生産者的吞吐量,是以隻有在對消息的順序有嚴格要求的情況下才能這麼做。

3. 接收端消息有序性

kafka保證全鍊路消息順序消費,需要從發送端開始,将所有有序消息發送到同一個分區,然後用一個消費者去消費,但是這種性能比較低,可以在消費者端接收到消息後将需要保證順序消費的幾條消費發到記憶體隊列(可以搞多個),一個記憶體隊列開啟一個線程順序處理消息。

僅有一個消費者通路一個分區,可以保證有序,但是效率低。當有多個消費者時,通過新增業務隊列,讓所有資料都發到業務隊列中,排序後再進行業務處理。

參考

Kafka的10道基礎面試題

11. kafka重試機制解讀