分佈式消息隊列(Message Queue)系統:kafka

分佈式系統很重要的一個設計原則是鬆耦合,即儘可能減小子系統間的依賴。這樣各個子系統能夠相互獨立的進行演進,維護,重用等。Message Queue (MQ)是一種很好的解耦手段。要了解MQ在系統整合中的做用,能夠看Enterprise Integration Patterns (EIP)這本書或對應的網站。簡單說就是發佈者只管把消息發佈到MQ中而無論誰會來取,一樣消息使用者只管只管從MQ取消息而不論是誰發佈的。這樣發佈者和使用者都不用知道對方的存在。html

MQ產品也有不少,開源的也很多。常見的有activeMQ,openMQ,RabbitMQ等。之前也用過MQ系統,而最近在思考SaaS系統中如何使用MQ。因此在網上看看目前有什麼樣的MQ系統具備比較好的擴展性,能夠支持大規模的數據流的,就發現了kafka。java

1. kafka是什麼

kafka是LinkedIn開發並開源的一個分佈式MQ系統,如今是Apache的一個孵化項目。在它的主頁描述kafka爲一個高吞吐量的分佈式(能將消息分散到不一樣的節點上)MQ。在這片博文中,做者簡單提到了開發kafka而不選擇已有MQ系統的緣由。兩個緣由:性能和擴展性。這裏作適當解釋。apache

基本上目前絕大多數(若是不是全部的)MQ系統都是針對企業集成應用設計的,而不是針對大規模Service應用設計的。二者有什麼區別?服務器

企業集成的基本特色是把企業中現存的本不相干的各類應用進行集成。例如:一個企業可能想把財務系統和倉管系統進行集成,減小部門間結算和流通的成本和時間,並能更好的支持上層決策。但這兩個系統是由不一樣的廠家作的,不能修改。另外企業集成是一個持續漸進的過程,需求變化很是頻繁。這對MQ系統的要求是要很是靈活,可定製性要求高。因此常見的MQ系統一般均可以經過復炸的xml配置或插件開發進行定製以適應不一樣企業的業務流程的須要。他們大多數都能經過配置不一樣程度的支持EIP中定義一些模式。但設計目標並無很重視擴展性和性能,由於一般企業級應用的數據流和規模都不會很是大。即便有的比較大,使用高配置的服務器或作一個簡單幾個節點的集羣就能夠知足了。網絡

大規模的service是指面向公衆的向facebook,google,linkedin和taobao這樣級別或有可能成長到這個級別的應用。相對企業集成來說,這些應用的業務流程相對比較穩定。子系統間集成的業務複雜度也相對較低,由於子系統一般也是通過精心選擇和設計的並能作必定的調整。因此對MQ系統的可定製性及定製的複雜性要求並不高。但因爲數據量會很是巨大,不是幾臺Server能知足的,可能須要幾十甚至幾百臺,且對性能要求較高以下降成本,因此MQ系統須要有很好的擴展性。負載均衡

kafka正是一個知足SaaS要求的MQ系統,它經過下降MQ系統的複雜度來提升性能和擴展性。異步

2. kafka的設計

kafka的設計文檔詳細說明了它的設計思路。這裏簡單列舉並討論一下。分佈式

基本概念

kafka的工做方式和其餘MQ基本相同,只是在一些名詞命名上有些不一樣。爲了更好的討論,這裏對這些名詞作簡單解釋。經過這些解釋應該能夠大體瞭解kafka MQ的工做方式。性能

  • Producer (P):就是網kafka發消息的客戶端
  • Consumer (C):從kafka取消息的客戶端
  • Topic (T):能夠理解爲一個隊列
  • Consumer Group (CG):這是kafka用來實現一個topic消息的廣播(發給全部的consumer)和單播(發給任意一個consumer)的手段。一個topic能夠有多個CG。topic的消息會複製(不是真的複製,是概念上的)到全部的CG,但每一個CG只會把消息發給該CG中的一個consumer。若是須要實現廣播,只要每一個consumer有一個獨立的CG就能夠了。要實現單播只要全部的consumer在同一個CG。用CG還能夠將consumer進行自由的分組而不須要屢次發送消息到不一樣的topic。
  • Broker (B):一臺kafka服務器就是一個broker。一個集羣由多個broker組成。一個broker能夠容納多個topic。
  • Partition(P):爲了實現擴展性,一個很是大的topic能夠分佈到多個broker(即服務器)上。kafka只保證按一個partition中的順序將消息發給consumer,不保證一個topic的總體(多個partition間)的順序。

可靠性(一致性)

MQ要實現從producer到consumer之間的可靠的消息傳送和分發。傳統的MQ系統一般都是經過broker和consumer間的確認(ack)機制實現的,並在broker保存消息分發的狀態。即便這樣一致性也是很難保證的(參考原文)。kafka的作法是由consumer本身保存狀態,也不要任何確認。這樣雖然consumer負擔更重,但其實更靈活了。由於無論consumer上任何緣由致使須要從新處理消息,均可以再次從broker得到。測試

kafka的producer有一種異步發送的操做。這是爲提升性能提供的。producer先將消息放在內存中,就返回。這樣調用者(應用程序)就不須要等網絡傳輸結束就能夠繼續了。內存中的消息會在後臺批量的發送到broker。因爲消息會在內存呆一段時間,這段時間是有消息丟失的風險的。因此使用該操做時須要仔細評估這一點。

另外,在最新的版本中,還實現了broker間的消息複製機制,去除了broker的單點故障(SPOF)。

擴展性

kafka使用zookeeper來實現動態的集羣擴展,不須要更改客戶端(producer和consumer)的配置。broker會在zookeeper註冊並保持相關的元數據(topic,partition信息等)更新。而客戶端會在zookeeper上註冊相關的watcher。一旦zookeeper發生變化,客戶端能及時感知並做出相應調整。這樣就保證了添加或去除broker時,各broker間仍能自動實現負載均衡。

負載均衡

負載均衡能夠分爲兩個部分:producer發消息的負載均衡和consumer讀消息的負載均衡。

producer有一個到當前全部broker的鏈接池,當一個消息須要發送時,須要決定發到哪一個broker(即partition)。這是由partitioner實現的,partitioner是由應用程序實現的。應用程序能夠實現任意的分區機制。要實現均衡的負載均衡同時考慮到消息順序的問題(只有一個partition/broker上的消息能保證按順序投遞),partitioner的實現並不容易。我的認爲這一點還有待改進。

consumer讀取消息時,除了考慮當前的broker狀況外,還要考慮其餘consumer的狀況,才能決定從哪一個partition讀取消息。具體的機制還不是很清楚,須要作更深刻的研究。

性能

性能是kafka設計重點考慮的因素。使用多種方法來保證穩定的O(1)性能。

kafka使用磁盤文件保存收到的消息。它使用一種相似於WAL(write ahead log)的機制來實現對磁盤的順序讀寫,而後再定時的將消息批量寫入磁盤。消息的讀取基本也是順序的。這正符合MQ的順序讀取和追加寫特性。

另外,kafka經過批量消息傳輸來減小網絡傳輸,並使用java中的sendfile和0拷貝機制減小從讀取文件到發送消息間內存數據拷貝和內核用戶態切換的次數。

根據kafka的性能測試報告,它的性能基本達到了O(1)的複雜度。

3. 總結

從以上來看,我的以爲kafka比較適合用來作簡單的消息傳遞和分發,能支持大數據量。但若是須要實現複雜的EIP模式,則不像傳統MQ那麼容易。並且,由於只有partition內的消息才能保證傳遞順序,若是消息的順序很重要,又須要很好的擴展性,使用kafka實現可能會比較困難。因此,kafka應該比較適合處理簡單的事件和消息,例如數據(log)收集,大量事實數據的實時分析(kafka可與MapReduce集成)。

但須要注意的是,kafka如今還只是Apache的孵化項目,還不是很成熟,雖然開發活動仍是比較活躍的。

相關文章
相關標籤/搜索