Kafka分佈式的單位是partition,同一個partition用一個write ahead log組織,因此能夠保證FIFO的順序。不一樣partition之間不能保證順序。mysql
可是絕大多數用戶均可以經過message key來定義,由於同一個key的message能夠保證只發送到同一個partition,好比說key是user id,table row id等等,因此同一個user或者同一個record的消息永遠只會發送到同一個partition上,保證了同一個user或record的順序。固然,若是你有key skewness 就有些麻煩,須要特殊處理sql
Apache Kafka官方保證了partition內部的數據有效性(追加寫、offset讀);爲了提升Topic的併發吞吐能力,能夠提升Topic的partition數,並經過設置partition的replica來保證數據高可靠;併發
可是在多個Partition時,不能保證Topic級別的數據有序性。分佈式
所以,若是大家就像死磕kafka,可是對數據有序性有嚴格要求,那我建議:大數據
因此能夠思考下是否是技術選型有問題, kafka自己適合與流式大數據量,要求高吞吐,對數據有序性要求不嚴格的場景。優化
原文連接:http://www.lpnote.com/2017/01/17/sequence-message-in-kafka/this
順序消息包括如下兩方面:線程
全局順序就目前的應用範圍來說,能夠列舉出來的也就限於binlog日誌傳輸,如mysql binlog日誌傳輸要求全局的順序,不能有任何的亂序。這種的解決辦法一般是最爲保守的方式:日誌
其實在大部分業務場景下,只須要保證消息局部有序便可,什麼是局部有序?局部有序是指在某個業務功能場景下保證消息的發送和接收順序是一致的。如:訂單場景,要求訂單的建立、付款、發貨、收貨、完成消息在同一訂單下是有序發生的,即消費者在接收消息時須要保證在接收到訂單發貨前必定收到了訂單建立和付款消息。文檔
針對這種場景的處理思路是:針對部分消息有序(message.key相同的message要保證消費順序)場景,能夠在producer往kafka插入數據時控制,同一key分發到同一partition上面。由於每一個partition是固定分配給某個消費者線程進行消費的,因此對於在同一個分區的消息來講,是嚴格有序的(在kafka 0.10.x之前的版本中,kafka因消費者重啓或者宕機可能會致使分區的從新分配消費,可能會致使亂序的發生,0.10.x版本進行了優化,減小從新分配的可能性)。
對於一個有着前後順序的消息A、B,正常狀況下應該是A先發送完成後再發送B,可是在異常狀況下,在A發送失敗的狀況下,B發送成功,而A因爲重試機制在B發送完成以後重試發送成功了。
這時對於自己順序爲AB的消息順序變成了BA
消息producer在發送消息的時候,對於同一個broker鏈接是存在多個未確認的消息在同時發送的,也就是存在上面場景說到的狀況,雖然A和B消息是順序的,可是因爲存在未知的確認關係,有可能存在A發送失敗,B發送成功,A須要重試的時候順序關係就變成了BA。簡之一句就是在發送B時A的發送狀態是未知的。
針對以上的問題,嚴格的順序消費還須要如下參數支持:max.in.flight.requests.per.connection
這個參數官方文檔的解釋是:
The maximum number of unacknowledged requests the client will send on a single connection before blocking. Note that if this setting is set to be greater than 1 and there are failed sends, there is a risk of message re-ordering due to retries (i.e., if retries are enabled).
大致意思是:
在發送阻塞前對於每一個鏈接,正在發送可是發送狀態未知的最大消息數量。若是設置大於1,那麼就有可能存在有發送失敗的狀況下,由於重試發送致使的消息亂序問題。因此咱們應該將其設置爲1,保證在後一條消息發送前,前一條的消息狀態已是可知的。