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

jopen 10年前發布 | 29K 次閱讀 消息系統 Kafka

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

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

1. kafka是什么

kafka是LinkedIn開發并開源的一個分布式MQ系統,現在是Apache的一個孵化項目。在它的主頁描述kafka為一個高吞吐量的分布式(能將消息分散到不同的節點上)MQ。在這片博文中,作者簡單提到了開發kafka而不選擇已有MQ系統的原因。兩個原因:性能和擴展性。這里做適當解釋。

基本上目前絕大多數(如果不是所有的)MQ系統都是針對企業集成應用設計的,而不是針對大規模Service應用設計的。兩者有什么區別?

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

大規模的service是指面向公眾的向非死book,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的孵化項目,還不是很成熟,雖然開發活動還是比較活躍的。

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!