(點選上方公眾號,可快速關註)
來源:Valleylord ,
valleylord.github.io/post/201607-mq-kafka/
現代的網際網路分散式系統,只要稍微大一些,就一定逃不開3類中介軟體:遠端呼叫(RPC)框架、訊息佇列、資料庫訪問中介軟體。Kafka 是訊息佇列中介軟體的代表產品,用 Scala 語言實現,本文采用的是 Kafka_2.11 0.10.0.0 版本進行實驗。
基本概念
首先,Kafka 中有一些基本的概念需要熟悉 1 2。
-
Topic,指訊息的類別,每個訊息都必須有;
-
Producer,指訊息的產生者,或者,訊息的寫端;
-
Consumer,指訊息的消費者,或者,訊息的讀端;
-
Producer Group,指產生者組,組內的生產者產生同一類訊息;
-
Consumer Group,指消費者組,組內的消費者消費同一類訊息;
-
Broker,指訊息伺服器,Producer 產生的訊息都是寫到這裡,Consumer 讀訊息也是從這裡讀;
-
Zookeeper,是 Kafka 的註冊中心,Broker 和 Consumer 之間的協調器,包含狀態資訊、配置資訊和一些 Topic 的資訊;
-
Partition,指訊息的水平分割槽,一個 Topic 可以有多個分割槽;
-
Replica,指訊息的副本,為了提高可用性,將訊息副本儲存在其他 Broker 上。
特別說明,Broker 是指單個訊息服務行程,一般情況下,Kafka 是叢集執行的,Broker 只是叢集中的一個服務行程,而非代指整個 Kafka 服務,可以簡單將 Broker 理解成伺服器(Server)。Kafka 引入的術語都比較常見,從字面上理解相對直觀。Kafka 的大致結構圖是這樣:
Kafka 是 Pull 樣式的訊息佇列,即 Consumer 連到訊息佇列服務上,主動請求新訊息,如果要做到實時性,需要採用長輪詢,Kafka 在0.8的時候已經支援長輪詢樣式。上圖中 Consumer 的連線箭頭方向可能會讓讀者誤以為是 Push 樣式,特此註明。更多關於 Kafka 設計的文章可以參考官方檔案,或者一些比較好的部落格文章 3。
關於順序和分割槽
Kafka 是一個力求保持訊息順序性的訊息佇列,但不是完全保證,其保證的是 Partition 級別的順序性,如下圖:
此圖是 Topic 的分割槽 log 的示意圖,可見,每個分割槽上的 log 都是一個有序的佇列,所以,Kafka 是分割槽級別有序的。如果,某個 Topic 只有一個分割槽,那麼這個 Topic 下的訊息就都是有序的。
分割槽是為了提升訊息處理的吞吐率而產生的,將一個 Topic 中的訊息分成幾份,分別給不同的 Broker 處理。如下圖:
此圖中有2個 Broker,Server 1 和 Server 2,每個 Broker 上有2個分割槽,總共4個分割槽,P0 ~ P3;有2個 Consumer Group,Consumer Group A 有2個 Consumer,Consumer Group B 有4個 Consumer。Kafka 的實現是,在穩定的情況下,維持固定的連線,每個 Consumer 穩定的消費其中某幾個分割槽的訊息,以上圖舉例,Consumer Group A 中的 C1 穩定消費 P0、P3,C2 穩定消費 P1、P2。這樣的連線分配可能會導致訊息消費的不均勻分佈,但好處是比較容易保證順序性。
維持完全的順序性在分散式系統看來幾乎是無意義的。因為,如果需要維持順序性,那麼就只能有一條執行緒阻塞的處理順序訊息,即,Producer -> MQ -> Consumer 必須執行緒上一一對應。這與分散式系統的初衷是相違背的。但是區域性的有序性,是可以維持的。比如,有30000條訊息,每3條之間有關聯,1->2->3,4->5->6,……,但是全域性範圍來看,並不需要保證 1->4->7,可以 7->4->1 的順序來執行,這樣可以達到最大並行度10000,而這通常是現實中我們面對的情況。通常應用中,將有先後關係的訊息傳送到相同的分割槽上,即可解決大部分問題。
關於副本
副本是高可用 Kafka 叢集的實現方式。假設叢集中有3個 Broker,那麼可以指定3個副本,這3個副本是對等的,對於某個 Topic 的分割槽來說,其中一個是 Leader,即主節點,另外2個副本是 Follower,即從節點,每個副本在一個 Broker 上。當 Leader 收到訊息的時候,會將訊息寫一份到副本中,通常情況,只有 Leader 處於工作狀態。在 Leader 發生故障宕機的時候,Follwer 會取代 Leader 繼續傳送訊息,而不會發生訊息丟失。Kafka 的副本是以分割槽為單位的,也就是說,即使是同一個 Topic,其不同分割槽的 Leader 節點也不同。甚至,Kafka 傾向於用不同的 Broker 來做分割槽的 Leader,因為這樣能做到更好的負載均衡。
在副本間的訊息同步,實際上是複製訊息的 log,複製可以是同步複製,也可以是非同步複製。同步複製是說,當 Leader 收到訊息後,將訊息寫入從副本,只有在收到從副本寫入成功的確認後才傳回成功給 Producer;非同步複製是說,Leader 將訊息寫入從副本,但是不等待從副本的成功確認,直接傳回成功給 Producer。同步複製效率較低,但是訊息不會丟;非同步複製效率高,但是在 Broker 宕機的時候,可能會出現訊息丟失。
關於丟訊息和重覆收到訊息
任何一個 MQ 都需要處理丟訊息和重覆收到訊息的,正常情況下,Kafka 可以保證:1. 不丟訊息;2. 不重覆發訊息;3. 訊息讀且只讀一次。當然這都是正常情況,極端情況,如 Broker 宕機,斷電,這類情況下,Kafka 只能保證 1 或者 2,無法保證 3。
在有副本的情況下,Kafka 是可以保證訊息不丟的,其前提是設定了同步複製,這也是 Kafka 的預設設定,但是可能出現重覆傳送訊息,這個交給上層應用解決;在生產者中使用非同步提交,可以保證不重覆傳送訊息,但是有丟訊息的可能,如果應用可以容忍,也可以接受。如果需要實現讀且只讀一次,就比較麻煩,需要更底層的 API 4。
參考文章
-
http://kafka.apache.org/documentation.html
-
http://www.jianshu.com/p/453c6e7ff81c
-
http://www.infoq.com/cn/author/%E9%83%AD%E4%BF%8A#文章
-
http://developer.51cto.com/art/201501/464491.htm
-
https://segmentfault.com/q/1010000004292925
-
http://www.cnblogs.com/gnivor/p/5318319.html
-
http://www.cnblogs.com/davidwang456/p/4313784.html
-
http://www.jianshu.com/p/8689901720fd
-
http://zqhxuyuan.github.io/2016/05/26/2016-05-13-Kafka-Book-Sample/
-
How to choose the number of topics/partitions in a Kafka cluster?
【關於投稿】
如果大家有原創好文投稿,請直接給公號傳送留言。
① 留言格式:
【投稿】+《 文章標題》+ 文章連結
② 示例:
【投稿】《不要自稱是程式員,我十多年的 IT 職場總結》:http://blog.jobbole.com/94148/
③ 最後請附上您的個人簡介哈~
看完本文有收穫?請轉發分享給更多人
關註「ImportNew」,提升Java技能