在kafka的世界中有不少概念和術語是須要咱們提早理解而且熟練掌握的,下面來盤點一下。mysql
以前咱們提到過,kafka屬於分佈式的消息引擎系統,主要功能是提供一套完善的消息發佈與訂閱方案。在kafka中,發佈訂閱的對象是主題(topic),能夠爲每一個業務、每一個應用、甚至是每一類數據都建立專屬的主題。sql
向主題發佈消息的客戶端應用程序成爲生產者(producer),生產者一般持續不斷地向一個或多個主題發送消息,而訂閱這些主題獲取消息的客戶端應用程序就被稱之爲消費者(consumer)。和生產者相似,消費者也能同時訂閱多個主題。咱們把生產者和消費者統稱爲客戶端(clients)。你能夠同時運行多個生產者和消費者實例,這些實例不斷地向kafka集羣中的多個主題生產和消費消息。數據庫
有客戶端天然也就有服務端。kafka的服務器端由被稱爲broker的服務進程構成,即一個kafka集羣由多個broker組成,broker負責接收和處理客戶端發來的請求,以及對消息進行持久化。雖然多個broker進程可以運行在同一臺機器上,但更常見的作法是將不一樣的broker分散運行在不一樣的機器上。這樣即使集羣中的某一臺機器宕機,運行在其之上的broker進程掛掉了,其餘機器上的broker也依舊能對外提供服務。這其實就是kafka提供高可用的手段之一。服務器
在實現高可用的另外一個手段就是備份機制(replication)。備份的思想很簡單,就是把相同的數據拷貝到多臺機器上,而這些相同的數據拷貝就叫作副本(replica)。副本的數量是能夠配置的,這些副本保存着相同的數據,但卻有不一樣的角色和做用。kafka定義了兩種副本,領導者副本(leader replica)和追隨者副本(follower replica)。前者對外提供服務,這裏的對外指的是與客戶端進行交互;然後者只是被動地追隨領導者副本而已,不與外界進行交互。固然了,不少其餘系統中追隨者副本是能夠對外提供服務的,好比mysql,從庫是能夠處理讀操做的,也就是所謂的"主寫從讀",可是在kafka中追隨者副本不會對外提供服務,至於爲何咱們做爲思考題解答。對了,關於領導者--追隨者,以前實際上是叫作主(master)--從(slave),可是不建議使用了,由於slave有奴隸的意思,政治上有點不合適,因此目前大部分的系統都改爲leader-follower了。架構
副本的工做機制很簡單:生產者向主題寫的消息老是往領導者那裏,消費者向主題獲取消息也都是來自於領導者。也就是不管是讀仍是寫,針對的都是領導者副本,至於追隨者副本,它只作一件事情,那就是向領導者副本發送請求,請求領導者副本把最新生產的消息發送給它,這樣便可以保持和領導者的同步。app
雖然有了副本機制能夠保證數據的持久化或者數據不丟失,但沒有解決伸縮性的問題。伸縮性即所謂的scalability,是分佈式系統中很是重要且必須謹慎對待的問題。什麼事伸縮性呢?咱們拿副原本說,雖然如今有了領導者副本和追隨者副本,但假若領導者副本積累了太多的數據以致於單臺broker都沒法容納了,此時應該怎麼辦?有個很天然的想法就是,可否把數據分割成多分保存在不一樣的broker上?沒錯,kafka就是這麼設計的。負載均衡
這種機制就是所謂的分區(partition)。若是瞭解其餘的分佈式系統,那麼可能據說過度片、分區域等提法,好比MongoDB和ElasticSearch中的sharding、Hbase中的region,其實它們都是相同的原理,只是partition是最標準的名稱。分佈式
kafka中的分區機制指定的是將每一個主題劃分爲多個分區,每一個分區都是一組有序的消息日誌。生產者生產的每一條消息只會被髮到一個分區中,也就說若是向有兩個分區的主題發送一條消息,那麼這條消息要麼在第一個分區中,要麼在第二條分區中。而kafka的分區編號是從0開始的,若是某個topic有100個分區,那麼它們的分區編號就是從0到99。性能
到這裏可能會有疑問,那就是剛纔提到的副本如何與這裏的分區聯繫在一塊兒呢?實際上,副本是在分區這個層級定義的。每一個分區下能夠配置若干個副本,其中只能有1個領導者副本和N-1個追隨者副本。生產者向分區寫入消息,每條消息在分區中的位置由一個叫位移(offset)的數據來表徵。分區位移老是從0開始,假設一個生產者向一個空分區寫入了10條消息,那麼這10條消息的位移依次是0、一、二、...、9。spa
至此咱們能完整地串聯起kafka的三層消息架構
第一層是主題層,每一個主題能夠配置M個分區,每一個分區又能夠配置N個副本
第二層是分區層,每一個分區的N個副本中只能有一個副原本充當領導者角色,對外提供服務;其餘的N-1個副本只是追隨者副本,用來提供數據冗餘之用。
第三層是消息層,分區中包含若干條消息,每條消息的位移從0開始,依次遞增。
最後客戶端程序只能與分區的領導者副本進行交互
那麼kafka是如何持久化數據的呢?總的來講,kafka使用消息日誌(log)來保存數據,一個日誌就是磁盤上一個只能追加寫(append-only)消息的物理文件。由於只能追加寫入,故避免了緩慢的隨機I/O操做,改成性能較好的順序I/O操做,這也是實現kafka高吞吐量特性的一個重要手段。不過若是不停地向一個日誌寫入消息,最終也會耗盡全部的磁盤空間,所以kafka必然要按期地刪除消息以回收磁盤。怎麼刪除?簡單來講就是經過日誌段(log segment)機制。在kafka底層,一個日誌又進一步細分紅多個日誌段,消息被追加寫到當前最新的日誌段中,當寫滿了一個日誌段後,kafka會自動切分出一個新的日誌段,並將老的日誌段封存起來。kafka在後臺還有定時任務會按期地檢查老的日誌段是否可以被刪除,從而實現回收磁盤的目的。
這裏再重點說一下消費者,以前說過有兩種消息模型,即點對點模型(peer to peer, p2p)和分佈訂閱模型。這裏面的點對點指的是同一條消息只能被下游的一個消費者消費,其餘消費者不能染指。在kafka中實現這種p2p模型的方法就是引入了消費者組(consumer group)。所謂的消費者組,指的是多個消費者實例共同組成一個組來消費一個主題。這個主題中的每一個分區都只會被消費者組裏面的一個消費者實例消費,其餘消費者實例不能消費它。爲何要引入消費者組呢?主要是爲了提高消費者端的吞吐量,多個消費者實例同時消費,加速了整個消費端的吞吐量(TPS)。關於消費者組的機制,後面會詳細介紹,如今只須要知道消費者組就是多個消費者組成一個組來消費主題裏面的消息、而且消息只會被組裏面的一個消費者消費便可。此外,這裏的消費者實例能夠是運行消費者應用的進程,也能夠是一個線程,它們都稱爲一個消費者實例(consumer instance)。
消費者組裏面的消費者不只瓜分訂閱主題的數據,並且更酷的是它們還能彼此協助。假設組內某個實例掛掉了,kafka可以自動檢測,而後把這個Failed實例以前負責的分區轉移給其餘活着的消費者。這個過程就是大名鼎鼎的"重平衡(rebalance)"。嗯,其實便是大名鼎鼎,也是臭名昭著,由於由重平衡引起的消費者問題比比皆是。事實上,目前不少重平衡的bug,整個社區都無力解決。
每一個消費者在消費消息的過程當中,必然須要有個字段記錄它當前消費到了分區的哪一個位置上,這個字段就是消費者位移(consumer offset)。注意,咱們以前說一個主題能夠有多個分區、每一個分區也是用位移來表示消息的位置。可是這兩個位移徹底不是一個概念,分區位移表示的是分區內的消息位置,它是不變的,一旦消息被成功寫入一個分區上,那麼它的位置就是固定了的。而消費者位移則不一樣,它多是隨時變化的,畢竟它是消費者消費進度的指示器嘛。另外每一個消費者都有着本身的消費者位移,所以必定要區分這兩類位移的區別。一個是分區位移,另外一個是消費者位移。
小結:
生產者,producer
:向主題發佈新消息的應用程序消費者,consumer
:從主題訂閱新消息的應用程序消息,record
:kafka是消息引擎,這裏的消息就是指kafka處理的主要對象主題,topic
:主題是承載消息的邏輯容器,在實際使用中多用來區分具體的業務,即不一樣的業務對應不一樣的主題。分區,partition
:一個有序不變的消息序列,每一個主題下能夠有多個分區。分區編號從0開始,分佈在不一樣的broker上面,實現發佈於訂閱的負載均衡。生產者將消息發送到主題下的某個分區中,以分區偏移(offset)來標識一條消息在一個分區當中的位置(惟一性)分區位移,offset
:表示分區中每條消息的位置信息,是一個單調遞增且不變的值副本,replica
:kafka中同一條數據可以被拷貝到多個地方以提供數據冗餘,這即是所謂的副本。副本還分爲領導者副本和追隨者副本,各自有各自的功能職責。讀寫都是針對領導者副原本的,追隨者副本只是用來和領導者副本進行數據同步、保證數據冗餘、實現高可用。消費者位移,consumer offset
:表示消費者消費進度,每一個消費者都有本身的消費者位移消費者組,consumer group
:多個消費者實例共同組成的一個組,同時消費多個分區以實現高吞吐。重平衡,rebalance
:消費者組內某個消費者實例掛掉以後,其它消費者實例自動從新分配訂閱主題分區的過程。重平衡是kafka消費者端實現高可用的重要手段
思考:爲何kafka不像mysql那樣支持主寫從讀呢?
由於kafka的主題已經被分爲多個分區,分佈在不一樣的broker上,而不一樣的broker又分佈在不一樣的機器上,所以從某種角度來講,kafka已經實現了負載均衡的效果。不像mysql,壓力都在主上面,因此纔要從讀;另外,kafka保存的數據和數據庫的數據有着實質性的差異,kafka保存的數據是流數據,具備消費的概念,並且須要消費者位移。因此若是支持從讀,那麼消費端控制offset會更復雜,並且領導者副本同步到追隨者副本須要時間的,會形成數據不一致的問題;另外對於生產者來講,kafka是能夠經過配置來控制是否等待follower對消息確認的,若是支持從讀的話,那麼也須要全部的follower都確認了才能夠回覆生產者,形成性能降低,並且follower出現了問題也很差處理。