消息中間件ActiveMQ與Kafka對比之Kafka
今天讓我們來談談身份高貴,舉止優雅的消息中間件,主要還是淺談,消息中間件這塊水太深。大體上我們結合互聯網業務做一些探討,從互聯網主要關心的消息安全性,服務器的穩定性容錯性以及吞吐量三方面來講。
由于這塊產品非常多,我只挑選兩個我使用過的產品結合使用經驗做一些研究,他們是ActiveMQ和Kafka,前者完全實現了JMS的規范,后者看上去有一些“野路子”,并沒有糾結于JMS規范,劍走偏鋒的設計了另一套吞吐非常高的分布式發布-訂閱消息系統,目前非常流行。接下來我們結合三個點(消息安全性,服務器的穩定性容錯性以及吞吐量)來分別談談這兩個消息中間件。今天我們談Kafka,ActiveMQ的文章在此。
01 性能怪獸Kafka
Kafka是LinkedIn開源的分布式發布-訂閱消息系統,目前歸屬于Apache定級項目。”Apache Kafka is publish-subscribe messaging rethought as a distributed commit log.”,官網首頁的一句話高度概括其職責。Kafka并沒有遵守JMS規范,他只用文件系統來管理消息的生命周期。Kafka的設計目標是:
(1)以時間復雜度為O(1)的方式提供消息持久化能力,即使對TB級以上數據也能保證常數時間復雜度的訪問性能。
(2)高吞吐率。即使在非常廉價的商用機器上也能做到單機支持每秒100K條以上消息的傳輸。
(3)支持Kafka Server間的消息分區,及分布式消費,同時保證每個Partition內的消息順序傳輸。
(4)同時支持離線數據處理和實時數據處理。
(5)Scale out:支持在線水平擴展。
所以,不像AMQ,Kafka從設計開始極為高可用為目的,天然HA。broker支持集群,消息亦支持負載均衡,還有副本機制。同樣,Kafka也是使用Zookeeper管理集群節點信息,包括consumer的消費信息也是保存在zk中,下面我們分話題來談:
1)消息的安全性
Kafka集群中的Leader負責某一topic的某一partition的消息的讀寫,理論上consumer和producer只與該Leader 節點打交道,一個集群里的某一broker即是Leader的同時也可以擔當某一partition的follower,即Replica。Kafka分配Replica的算法如下:
(1)將所有Broker(假設共n個Broker)和待分配的Partition排序
(2)將第i個Partition分配到第(i mod n)個Broker上
(3)將第i個Partition的第j個Replica分配到第((i + j) mode n)個Broker上
同時,Kafka與Replica既非同步也不是嚴格意義上的異步。一個典型的Kafka發送-消費消息的過程如下:首先首先Producer消息發送給某Topic的某Partition的Leader,Leader先是將消息寫入本地Log,同時follower(如果落后過多將會被踢出出 Replica列表)從Leader上pull消息,并且在未寫入log的同時即向Leader發送ACK的反饋,所以對于某一條已經算作commit的消息來講,在某一時刻,其存在于Leader的log中,以及Replica的內存中。這可以算作一個危險的情況(聽起來嚇人),因為如果此時集群掛了這條消息就算丟失了,但結合producer的屬性(request.required.acks=2 當所有follower都收到消息后返回ack)可以保證在絕大多數情況下消息的安全性。當消息算作commit的時候才會暴露給consumer,并保證at-least-once的投遞原則。
2)服務的穩定容錯性
前面提到過,Kafka天然支持HA,整個leader/follower機制通過zookeeper調度,它在所有broker中選出一個 controller,所有Partition的Leader選舉都由controller決定,同時controller也負責增刪Topic以及 Replica的重新分配。如果Leader掛了,集群將在ISR(in-sync replicas)中選出新的Leader,選舉基本原則是:新的Leader必須擁有原來的Leader commit過的所有消息。假如所有的follower都掛了,Kafka會選擇第一個“活”過來的Replica(不一定是ISR中的)作為 Leader,因為如果此時等待ISR中的Replica是有風險的,假如所有的ISR都無法“活”,那此partition將會變成不可用。
3) 吞吐量
Leader節點負責某一topic(可以分成多個partition)的某一partition的消息的讀寫,任何發布到此partition的消息都會被直接追加到log文件的尾部,因為每條消息都被append到該partition中,是順序寫磁盤,因此效率非常高(經驗證,順序寫磁盤效率比隨機寫內存還要高,這是Kafka高吞吐率的一個很重要的保證),同時通過合理的partition,消息可以均勻的分布在不同的partition里面。 Kafka基于時間或者partition的大小來刪除消息,同時broker是無狀態的,consumer的消費狀態(offset)是由 consumer自己控制的(每一個consumer實例只會消費某一個或多個特定partition的數據,而某個partition的數據只會被某一個特定的consumer實例所消費),也不需要broker通過鎖機制去控制消息的消費,所以吞吐量驚人,這也是Kafka吸引人的地方。
最后說下由于zookeeper引起的腦裂(Split Brain)問題:每個consumer分別單獨通過Zookeeper判斷哪些partition down了,那么不同consumer從Zookeeper“看”到的view就可能不一樣,這就會造成錯誤的reblance嘗試。而且有可能所有的 consumer都認為rebalance已經完成了,但實際上可能并非如此。
參考資料:
http://kafka.apache.org
http://www.jasongj.com/2015/03/10/KafkaColumn1/
http://www.jasongj.com/2015/04/24/KafkaColumn2/
https://github.com/alibaba/RocketMQ
http://blog.csdn.net/damacheng/article/details/42846549
來自:http://www.liubey.org/mq-kafka/