詳細剖析kafka分布式消息系統

1.背景

最近因為工作需要,調研了追求高吞吐的輕量級消息系統Kafka,打算替換掉線上運行的ActiveMQ,主要是因為明年的預算日流量有十億,而ActiveMQ的分布式實現的很奇怪,所以希望找一個適合分布式的消息系統。

以下是內容是調研過程中總結的一些知識和經驗,歡迎拍磚。

2.基礎知識

2.1.什么是消息隊列

首先,我們來看看什么是消息隊列,維基百科里的解釋翻譯過來如下:

隊列提供了一種異步通信協議,這意味著消息的發送者和接收者不需要同時與消息保持聯系,發送者發送的消息會存儲在隊列中,直到接收者拿到它。

一般我們把消息的發送者稱為生產者,消息的接收者稱為消費者;注意定義中的那兩個字“異步”,通常生產者的生產速度和消費者的消費速度是不相等的;如果兩個程序始終保持同步溝通,那勢必會有一方存在空等時間;如果兩個程序一持續運行的話,消費者的平均速度一定要大于生產者,不然隊列囤積會越來越多;當然,如果消費者沒有時效性需求的話,也可以把消息囤積在隊列中,集中消費。

說到這里,我們再來談談隊列的分類,一般我們根據生產者和消費者的不同,可以把隊列分為三類:

第一類是在一個應用程序內部(進程之間或者線程之間),相信大家學多線程時都寫過“生產者消費者”程序,生產者負責生產,將生產的結果放到緩沖區(如共享數組),消費者從緩沖區取出消費,在這里,這個緩沖區就可以稱為“消息隊列”。

第二類其實也算在第一類的特例,就像我們喜歡把操作系統和應用程序區別對待來看,操作系統要處理無數繁雜的事物,各進程、線程之間的數據交換少不了消息隊列的支持。

第三類是更為通用意義上的“消息隊列”,這類隊列主要作用于不同應用,特別是跨機器、平臺,這令數據的交換更加廣泛,一般一款獨立的隊列產品除了實現消息的傳遞外,還提供了相應的可靠性、事務、分布式等特性,將生產者、消費者從中解耦。常見的消費隊列產品根據開源與否又可分為兩類:

專有軟件:IBM WebSphere MQ,MSMQ…

開源軟件:ActiveMQ、RabbitMQ、Kafka…

2.2.JMS與AMQP

好了,對于上述第三類“消息隊列”,要在不同的機器中提供消息隊列的功能,那勢必要有統一的規范,這時候SUN就跳出來了,作為跨平臺的JAVA勢必也要支持跨平臺的消息傳遞,基于此,SUN提供了一套消息標準:Java Message Service,縮寫JMS,但是這套規范定義的是API層面的標準,在JAVA體系中可以很方便的交換,但對于其他平臺就需要,可能需要消息隊列產品本身支持多協議(如OpenWire、STMOP)。

而AMQP定義的比JMS更加底層,從名字就能看出來(Advanced Message Queuing Protocol),它定義的是Wire-level的協議,天然具有跨平臺、跨語言的特性,基于此實現的消息隊列可以與任何支持該協議的平臺交互。

一種是JAVA層面的API,一種是Wire-level協議,這是JMS和AMQP最本質的區別;同時兩種標準還有兩個比較明顯的差異:

一是消息傳遞模型;JMS比較簡單,支持兩種最通用的Peer-2-Peer、publisher/subscriber;通俗點就是點對點和廣播模式;而AMQP定義的更為復雜,其定義了一種exchange&binding機制,由此支持五種模型:direct exchange、fanout exchange、topic exchange、headers exchange、system exchange,本質上與P2P、PUB/SUB一樣,但是更加細致些。

二是支持的消息類型,JMS支持多種消息模型:TextMessage、MapMessage、BytesMessage、StreamMessage、ObjectMessage、Message等;而AMQP只有byte數組。

2.3.ActiveMQ

ActiveMQ是基于JMS實現的Provider(可以理解為隊列),它支持多種協議,如OpenWire,Stomp,AMQP等,基于此,支持多平臺;支持事務,支持分發策略、還有上面的多種消息模型。這里我們不細談ActiveMQ的各特性,我們著重來看ActiveMQ的分布式模型。

ActiveMQ支持分布式,它支持Master-Slave提供高可用,也支持Broker-Cluster提供負載均衡,但是它的負載基于一種Forwarding Bridge機制。

在這種機制下,任意時刻一條消只會被一個broker持有,producer發送的消息,可能會經過多個broker轉發最終才會到達consumer,可以想象,當broker越來越多時,幾乎每次消費都要經過轉發,效率會明顯下降;并且在這種復雜邏輯下,任一broker的加入和移除都顯得十分復雜;這兩點是我不建議使用ActiveMQ分布式集群的根本原因。

Java架構進階群:554355695

3.Kafka

好,我們最后來談今天的主角Kafka,這個奇特的名字我始終沒有找到典故,也許是開發者暗戀女孩(基友)的名字吧^_^,Kafka由linkin開發,最初的目的是為了應對linkin龐大的活動流數據(登錄、瀏覽、點擊、分享、喜歡等),這部分數據容量龐大,但是可靠性要求不高,故而通過犧牲一部分可靠性(這并不是說我們的數據會按百分比丟,我們后面再談)來提升吞吐量;它砍掉了很多復雜的特性,如事務、分發策略、多種消息模型等;通過自身獨特的設計將消息持久化到磁盤上,以此同時支持在線和離線消費;并且其天生為分布式而設計,壓根就沒有單機模式(或者說單機模式是分布式的特例),能夠很好的擴展。實際應用中,Kafka可以用來做消息隊列、流式處理(一般結合storm)、日志聚合等。

3.1.架構

Java架構進階群:554355695

我們先宏觀的看看Kafka的架構,Producer集群通過zookeeper(實際中寫的是broker list)獲取所寫topic對應的partition列表,然后順序發送消息(支持自己實現分發策略),broker集群負責消息的存儲和傳遞,支持Master Slaver模型,可分布式擴展;Consumer集群從zookeeper上獲取topic所在的partition列表,然后消費,一個partition只能被一個consumer消費。Name Server集群(一般是zookeeper)提供名稱服務等協調信息。至于什么是topic,什么是partition,我們接下來看。

3.2.Topic

Topic是生產者生產、消費者消費的隊列標識。一個Topic由一個或多個partition組成,每個partition可以單獨存在一個broker上,消費者可以往任一partition發送消息,以此實現生產的分布式,任一partition都可以被且只被一個消費者消息,以此實現消費的分布式;因此partition的設計提供了分布式的基礎。

Java架構進階群:554355695

同時,從上圖我們也能發現這種設計還有一個優點,因為每個partition內的消息是有序的,而一個partition只能被一個消費者消費,因此Kafka能提供partition層面的消息有序,而傳統的隊列在多個consumer的情況下是完全無法保證有序的。

3.3.消息傳遞模型

傳統的消息隊列最少提供兩種消息模型,一種P2P,一種PUB/SUB,而Kafka并沒有這么做,巧妙的,它提供了一個消費者組的概念,一個消息可以被多個消費者組消費,但是只能被一個消費者組里的一個消費者消費,這樣當只有一個消費者組時就等同與P2P模型,當存在多個消費者組時就是PUB/SUB模型。

Java架構進階群:554355695

3.4.消息持久化

很多系統、組件為了提升效率一般恨不得把所有數據都扔到內存里,然后定期flush到磁盤上;可實際上,現代操作系統也是這樣,所有的現代操作系統都樂于將空閑內存轉作磁盤緩存(頁面緩存),想不用都難;對于這樣的系統,他的數據在內存中保存了一份,同時也在OS的頁面緩存中保存了一份,這樣不但多了一個步驟還讓內存的使用率下降了一半;因此,Kafka決定直接使用頁面緩存;但是隨機寫入的效率很慢,為了維護彼此的關系順序還需要額外的操作和存儲,而線性的寫入可以避免這些,實際上,線性寫入(linear write)的速度大約是300MB/秒,但隨即寫入卻只有50k/秒,其中的差別接近10000倍。這樣,Kafka以頁面緩存為中間的設計在保證效率的同時還提供了消息的持久化,每個消費者自己維護當前讀取數據的offser(也可委托給zookeeper),以此可同時支持在線和離線的消費。

3.5.Push vs. Pull

對于消息的消費,ActiveMQ使用PUSH模型,而Kafka使用PULL模型,兩者各有利弊,對于PUSH,broker很難控制數據發送給不同消費者的速度,而PULL可以由消費者自己控制,但是PULL模型可能造成消費者在沒有消息的情況下盲等,這種情況下可以通過long polling機制緩解,而對于幾乎每時每刻都有消息傳遞的流式系統,這種影響可以忽略。

3.6.可靠性

剛剛說Kafka犧牲了一些可靠性來提升吞吐量,很多同學可能擔心消息的丟失,那么我們現在來看看各種情況下的可靠性。

Java架構進階群:554355695

對于如上的模型,我們分開來看,

先來看消息投遞可靠性,一個消息如何算投遞成功,Kafka提供了三種模式,第一種是啥都不管,發送出去就當作成功,這種情況當然不能保證消息成功投遞到broker;第二種是對于Master Slave模型,只有當Master和所有Slave都接收到消息時,才算投遞成功,這種模型提供了最高的投遞可靠性,但是損傷了性能;第三種模型,即只要Master確認收到消息就算投遞成功;實際使用時,根據應用特性選擇,絕大多數情況下都會中和可靠性和性能選擇第三種模型。

我們再來看消息在broker上的可靠性,因為消息會持久化到磁盤上,所以如果正常stop一個broker,其上的數據不會丟失;但是如果不正常stop,可能會使存在頁面緩存來不及寫入磁盤的消息丟失,這可以通過配置flush頁面緩存的周期、閾值緩解,但是同樣會頻繁的寫磁盤會影響性能,又是一個選擇題,根據實際情況配置。

接著,我們再看消息消費的可靠性,Kafka提供的是“At least once”模型,因為消息的讀取進度由offset提供,offset可以由消費者自己維護也可以維護在zookeeper里,但是當消息消費后consumer掛掉,offset沒有即時寫回,就有可能發生重復讀的情況,這種情況同樣可以通過調整commit offset周期、閾值緩解,甚至消費者自己把消費和commit offset做成一個事務解決,但是如果你的應用不在乎重復消費,那就干脆不要解決,以換取最大的性能。

最后,我們再來看zookeeper的可靠性,很明顯,他要掛了,一切都完了,地球就毀滅了,人類就滅絕了,星級穿越也挽救不了了……所以增強可靠性的方式就是把zookeeper也部署成集群。

3.7.性能

好了,說了那么多,我們實際來測試下Kafka在各種情況下的性能,為了對比我也測了下單機模式下ActiveMQ的性能,不過由于懶,沒有搭建ActiveMQ集群進行測試,但是基于其惡心的Forwarding Bridge模型,我也持悲觀態度。

首先,測試環境如下:

Kafka:3 broker;8核/32G;默認配置

ActiveMQ:1 broker;8核/32G;默認配置

Producer: 一臺機器通過多線程模擬多producer;8核/32G;默認配置,異步發送

Consumer: 一臺機器通過多線程模擬多consumer;8核/32G;默認配置

除了特殊說明,生產和消費同時進行。

然后,我使用如下字符表示各種測試條件:

1T-1P3C-1P1C-1KW-1K

1T:1個toipc

1P3C:1個partition 3個replication

1P1C:1個producer 1個consumer

1KW:1千萬條消息

1K:每個消息1K

我先對ActiveMQ在單機多Producer、多consumer的情況下的測試,結果比我想象中的好,官方的給出的一個數據是1-2K的數據,每秒10-20K個,這樣算下來大概30-40MB/S,而測試的結果在多線程的情況下會更好些。

Java架構進階群:554355695

然后我又對Kafka進行了相應的測試,用一個partition模擬單機模式,結果和預想的一樣,在單機模型下,兩者差異不大;而官方給的數據說生產者能達到50MB/S,消費者能達到100MB/S,生產者符合官方數據,而消費者我始終沒有壓到那么高的速度。

Java架構進階群:554355695

接下來的對于Kafka集群,我想同樣數量的消息會不會因為topic數目的增多而影響,測試結果如下,表明topic越多,速度會有所下降,也符合預期。

Java架構進階群:554355695

然后為了測試partition對性能的影響,進行了如下測試,可以看到partition數量越多,總的生產和消費速度越快;但是意外的是Only produce情況下生產效率沒有明顯提升反而略慢,這里懷疑和page cache有關,沒有深入研究。

Java架構進階群:554355695

綜上,我們可以看到Kafka的性能和吞吐是可以擴展的。

3.8.風險點

對于我們來說,Kafka主要有兩個風險點,第一,要深入使用必須要熟讀源碼,而kafka源碼是用scala寫的,我們并沒有相應的技術儲備,需要學習;第二,kafka技術較新,目前的版本是0.8.1.1,看起來還不太成熟。

4.KG應用

這一塊是在公司內部系統的應用,不適合對外,所以這里刪去。

5.參考資料

Kafka-DOC:http://kafka.apache.org/documentation.html

ActiveMQ-DOC:http://activemq.apache.org

Understading the differences between AMQP & JMS:http://www.wmrichards.com/amqp.pdf

WIKI-MQ:http://en.wikipedia.org/wiki/Message_queue

WIKI-JMS:http://en.wikipedia.org/wiki/Java_Message_Service

WIKI-AMQP:http://en.wikipedia.org/wiki/Advanced_Message_Queuing_Protocol

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,835評論 6 534
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,676評論 3 419
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,730評論 0 380
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,118評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,873評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,266評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,330評論 3 443
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,482評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,036評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,846評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,025評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,575評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,279評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,684評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,953評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,751評論 3 394
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,016評論 2 375

推薦閱讀更多精彩內容

  • 姓名:周小蓬 16019110037 轉載自:http://blog.csdn.net/YChenFeng/art...
    aeytifiw閱讀 34,737評論 13 425
  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,789評論 18 139
  • kafka的定義:是一個分布式消息系統,由LinkedIn使用Scala編寫,用作LinkedIn的活動流(Act...
    時待吾閱讀 5,347評論 1 15
  • 背景介紹 Kafka簡介 Kafka是一種分布式的,基于發布/訂閱的消息系統。主要設計目標如下: 以時間復雜度為O...
    高廣超閱讀 12,863評論 8 167
  • 本文轉載自http://dataunion.org/?p=9307 背景介紹Kafka簡介Kafka是一種分布式的...
    Bottle丶Fish閱讀 5,490評論 0 34