Apache Kafka是分布式發布-訂閱消息系統。它最初由LinkedIn公司開發,之后成為Apache項目的一部分。Kafka是一種快速、可擴展的、設計內在就是分布式的,分區的和可復制的提交日志服務。
kafka對消息保存時根據Topic進行歸類,發送消息者成為Producer,消息接受者成為Consumer,此外kafka集群有多個kafka實例組成,每個實例(server)成為broker。無論是kafka集群,還是producer和consumer都依賴於zookeeper來保證系統可用性集群保存一些meta信息。

一個Kafka集群通常包括多個代理。為了均衡負載,將話題分成多個分區,每個代理存儲一或多個分區。多個生產者和消費者能夠同時生產和獲取消息。

一個Topic可以認為是一類消息,每個topic將被分成多個partition(區),每個partition在存儲層面是append log文件。任何發布到此partition的消息都會被直接追加到log文件的尾部,每條消息在文件中的位置稱為offset(偏移量),offset為一個long型數字,它是唯一標記一條消息。它唯一的標記一條消息。kafka並沒有提供其他額外的索引機制來存儲offset,因為在kafka中幾乎不允許對消息進行“隨機讀寫”。
kafka和JMS(Java Message Service)實現(activeMQ)不同的是:即使消息被消費,消息仍然不會被立即刪除.日志文件將會根據broker中的配置要求,保留一定的時間之后刪除;比如log文件保留2天,那么兩天后,文件會被清除,無論其中的消息是否被消費.kafka通過這種簡單的手段,來釋放磁盤空間,以及減少消息消費之后對文件內容改動的磁盤IO開支.
對於consumer而言,它需要保存消費消息的offset,對於offset的保存和使用,有consumer來控制;當consumer正常消費消息時,offset將會"線性"的向前驅動,即消息將依次順序被消費.事實上consumer可以使用任意順序消費消息,它只需要將offset重置為任意值..(offset將會保存在zookeeper中,參見下文)
kafka集群幾乎不需要維護任何consumer和producer狀態信息,這些信息有zookeeper保存;因此producer和consumer的
客戶端實現非常輕量級,它們可以隨意離開,而不會對集群造成額外的影響.
partitions的
設計目的有多個.最根本原因是kafka基於文件存儲.通過分區,可以將日志內容分散到多個server上,來避免文件尺寸達到單機磁盤的上限,每個partiton都會被當前server(kafka實例)保存;可以將一個topic切分多任意多個partitions,來消息保存/消費的效率.此外越多的partitions意味着可以容納更多的consumer,有效提升並發消費的能力.
Distribution
一個Topic的多個partitions,被分布在kafka集群中的多個server上;每個server(kafka實例)負責partitions中消息的讀寫操作;此外kafka還可以配置partitions需要備份的個數(replicas),每個partition將會被備份到多台機器上,以提高可用性.
基於replicated方案,那么就意味着需要對多個備份進行調度;每個partition都有一個
server為"leader";leader負責所有的讀寫操作,如果leader失效,那么將會有其他follower來接管(成為新的leader);follower只是單調的和leader跟進,同步消息即可..由此可見作為leader的server承載了全部的請求壓力,因此從集群的整體考慮,有多少個partitions就意味着有多少個"leader",kafka會將"leader"均衡的分散在每個實例上,來確保整體的性能穩定.
Producers
Producer將消息發布到指定的Topic中,同時Producer也能決定將此消息歸屬於哪個partition;比如基於"round-robin"方式或者通過其他的一些算法等.
Consumers
本質上kafka只支持Topic.每個consumer屬於一個consumer group;反過來說,每個group中可以有多個consumer.發送到Topic的消息,只會被訂閱此Topic的每個group中的一個consumer消費.
如果所有的consumer都具有相同的group,這種情況和queue模式很像;消息將會在consumers之間負載均衡.
如果所有的consumer都具有不同的group,那這就是"發布-訂閱";消息將會廣播給所有的消費者.
在kafka中,一個partition中的消息只會被group中的一個consumer消費;每個group中consumer消息消費互相獨立;我們可以認為一個group是一個"訂閱"者,一個Topic中的每個partions,只會被一個"訂閱者"中的一個consumer消費,不過一個consumer可以消費多個partitions中的消息.kafka只能保證一個partition中的消息被某個consumer消費時,消息是順序的.事實上,從Topic角度來說,消息仍不是有序的.
kafka的
設計原理決定,對於一個topic,同一個group中不能有多於partitions個數的consumer同時消費,否則將意味着某些consumer將無法得到消息.
Guarantees
1) 發送到partitions中的消息將會按照它接收的順序追加到日志中
2) 對於消費者而言,它們消費消息的順序和日志中消息順序一致.
3) 如果Topic的"replicationfactor"為N,那么允許N-1個kafka實例失效.
ZooKeeper與Kafka
有多個服務器的分布式系統,每台服務器都負責保存數據,在數據上執行操作。這樣的潛在例子包括分布式搜索引擎、分布式構建系統或者已知的系統如Apache Hadoop。所有這些分布式系統的一個常見問題是,你如何在任一時間點確定哪些服務器活着並且在工作中。最重要的是,當面對這些分布式計算的難題,例如網絡失敗、帶寬限制、可變延遲連接、安全問題以及任何網絡環境,甚至跨多個數據中心時可能發生的錯誤時,你如何可靠地做這些事。這些正是Apache ZooKeeper所關注的問題,它是一個快速、高可用、容錯、分布式的協調服務。你可以使用ZooKeeper構建可靠的、分布式的數據結構,用於群組成員、領導人選舉、協同工作流和配置服務,以及廣義的分布式數據結構如鎖、隊列、屏障(Barrier)和鎖存器(Latch)。許多知名且成功的項目依賴於ZooKeeper,其中包括HBase、Hadoop 2.0、Solr Cloud、Neo4J、Apache Blur(Incubating)和Accumulo。
ZooKeeper是一個分布式的、分層級的文件系統,能促進客戶端間的松耦合,並提供最終一致的,類似於傳統文件系統中文件和目錄的Znode視圖。它提供了基本的操作,例如創建、刪除和檢查Znode是否存在。它提供了事件驅動模型,客戶端能觀察特定Znode的變化,例如現有Znode增加了一個新的子節點。ZooKeeper運行多個ZooKeeper服務器,稱為Ensemble,以獲得高可用性。每個服務器都持有分布式文件系統的內存復本,為客戶端的讀取請求提供服務。

典型的ZooKeeper ensemble,一台服務器作為Leader,其它作為Follower。當Ensemble啟動時,先選出Leader,然后所有Follower復制Leader的狀態。所有寫請求都通過Leader路由,變更會廣播給所有Follower。變更廣播被稱為原子廣播。
Kafka中ZooKeeper的用途:正如ZooKeeper用於分布式系統的協調和促進,Kafka使用ZooKeeper也是基於相同的原因。ZooKeeper用於管理、協調Kafka代理。每個Kafka代理都通過ZooKeeper協調其它Kafka代理。當Kafka系統中新增了代理或者某個代理故障失效時,ZooKeeper服務將通知生產者和消費者。生產者和消費者據此開始與其它代理協調工作。Kafka整體系統架構所示。
