一.Kafka的基本概念
關鍵字: 分散式釋出訂閱訊息系統;分散式的,分割槽的訊息服務
Kafka是一種高吞吐量的分散式釋出訂閱訊息系統,使用Scala編寫。
對於熟悉JMS(Java Message Service)規範的同學來說,訊息系統已經不是什麼新概念了(例如ActiveMQ,RabbitMQ等)。
Kafka擁有作為一個訊息系統應該具備的功能,但是確有著獨特的設計。可以這樣來說,Kafka借鑑了JMS規範的思想,但是確並沒有完全遵循JMS規範。
kafka是一個分散式的,分割槽的訊息(官方稱之為commit log)服務。它提供一個訊息系統應該具備的功能,但是確有著獨特的設計。
二.基礎的訊息(Message)相關術語
1.Topic
Kafka按照Topic分類來維護訊息
2.Producer
我們將釋出(publish)訊息到Topic的程式稱之為生產者(producer)
3.Consumer
我們將訂閱(subscribe)Topic並且處理Topic中訊息的程式稱之為消費者(consumer)
4.Broker
Kafka以叢集的方式執行,叢集中的每一臺伺服器稱之為一個代理(broker)。
因此,從一個較高的層面上來看,producers通過網路傳送訊息到Kafka叢集,然後consumers來進行消費,如下圖
服務端(brokers)和客戶端(producer、consumer)之間通訊通過TCP協議來完成。我們為Kafka提供了一個Java客戶端,但是也可以使用其他語言編寫的客戶端。
5.Topic和Log
我們首先深入理解Kafka提出一個高層次的抽象概念-Topic。
可以理解Topic是一個類別的名稱,所有的message傳送到Topic下面。對於每一個Topic,kafka叢集按照如下方式維護一個分割槽(Partition,可以就理解為一個佇列Queue)日誌檔案:
6.partition
partition是一個有序的message序列,這些message按順序新增到一個叫做commit log的檔案中。每個partition中的訊息都有一個唯一的編號,稱之為offset,用來唯一標示某個分割槽中的message。
提示:每個partition,都對應一個commit-log。一個partition中的message的offset都是唯一的,但是不同的partition中的message的offset可能是相同的。
6.1 對log進行分割槽的目的
對log進行分割槽(partitioned),有以下目的。首先,當log檔案大小超過系統檔案系統的限制時,可以自動拆分。每個partition對應的log都受到所在機器的檔案系統大小的限制,但是一個Topic中是可以有很多分割槽的,因此可以處理任意數量的資料。另一個方面,是為了提高並行度。
7.offset
7.1 consumer有自己的offset
每個consumer是基於自己在commit log中的消費進度(offset)來進行工作的。在kafka中,offset由consumer來維護:一般情況下我們按照順序逐條消費commit log中的訊息,當然我可以通過指定offset來重複消費某些訊息,或者跳過某些訊息。
這意味kafka中的consumer對叢集的影響是非常小的,新增一個或者減少一個consumer,對於叢集或者其他consumer來說,都是沒有影響的,因此每個consumer維護各自的offset。
8.Distribution
log的partitions分佈在kafka叢集中不同的broker上,每個broker可以請求備份其他broker上partition上的資料。kafka叢集支援配置一個partition備份的數量。
針對每個partition,都有一個broker起到“leader”的作用,0個多個其他的broker作為“follwers”的作用。leader處理所有的針對這個partition的讀寫請求,而followers被動複製leader的結果。如果這個leader失效了,其中的一個follower將會自動的變成新的leader。每個broker都是自己所管理的partition的leader,同時又是其他broker所管理partitions的followers,kafka通過這種方式來達到負載均衡。
9.Producers
生產者將訊息傳送到topic中去,同時負責選擇將message傳送到topic的哪一個partition中。通過round-robin做簡單的負載均衡。也可以根據訊息中的某一個關鍵字來進行區分。通常第二種方式使用的更多。
10.Consumers
consumer例項可以執行在不同的程式上,也可以在不同的物理機器上。
如果所有的consumer都位於同一個consumer group 下,這就類似於傳統的queue模式,並在眾多的consumer instance之間進行負載均衡。
10.1 consumer group概念
Kafka基於這2種模式提供了一種consumer的抽象概念:consumer group。
每個consumer都要標記自己屬於哪一個consumer group。
如果所有的consumer都有著自己唯一的consumer group,這就類似於傳統的publish-subscribe模型。
10.2 佇列(queuing)模式
在queuing模式中,多個consumer從伺服器中讀取資料,訊息只會到達一個consumer。
10.3 釋出訂閱(publish-subscribe)模式
在 publish-subscribe模型中,訊息會被廣播給所有的consumer。
通常一個topic會有幾個consumer group,每個consumer group都是一個邏輯上的訂閱者(logical subscriber)。每個consumer group由多個consumer instance組成,從而達到可擴充套件和容災的功能。這並沒有什麼特殊的地方,僅僅是將publish-subscribe模型中的執行在單個程式上的consumers中的consumer替換成一個consumer group。如下圖所示
說明:由2個broker組成的kafka叢集,總共有4個Parition(P0-P3)。這個叢集由2個Consumer Group, A有2個 consumer instances ,而B有四個
三.Kafka的消費順序
Kafka比傳統的訊息系統有著更強的順序保證。
在傳統的情況下,伺服器按照順序保留訊息到佇列,如果有多個consumer來消費佇列中的訊息,伺服器 會接受訊息的順序向外提供訊息。但是,儘管伺服器是按照順序提供訊息,但是訊息傳遞到每一個consumer是非同步的,這可能會導致先消費的consumer獲取到訊息時間可能比後消費的consumer獲取到訊息的時間長,導致不能保證順序性。這表明,當進行並行的消費的時候,訊息在多個 consumer之間可能會失去順序性。
訊息系統通常會採取一種“exclusive consumer”的概念,來確保同一時間內只有一個consumer能夠從佇列中進行消費,但是這實際上意味著在訊息處理的過程中是不支援並行的。
Kafka partition保證區域性順序
Kafka比傳統方式做得更好:通過Topic中並行度的概念,即partition,Kafka可以同時提供順序性保證和多個consumer同時消費時的負載均衡。
實現的原理是通過將一個topic中的partition分配給一個consumer group中的不同consumer instance。通過這種方式,我們可以保證一個partition在同一個時刻只有一個consumer instance在訊息,從而保證順序。雖然一個topic中有多個partition,但是一個consumer group中同時也有多個consumer instance,通過合理的分配依然能夠保證負載均衡。需要注意的是,一個consumer group中的consumer instance的數量不能比一個Topic中的partition的數量多。
Kafka只在partition的範圍內保證訊息消費的區域性順序性,不能在同一個topic中的多個partition中保證總的消費順序性。通常來說,這已經可以滿足大部分應用的需求。但是,如果的確有在總體上保證消費的順序的需求的話,那麼我們可以通過將topic的partition數量設定為1,將consumer group中的consumer instance數量也設定為1.