分布式系統(tǒng)很重要的一個設(shè)計原則是松耦合,即盡量減少子系統(tǒng)間的依賴,。這樣各個子系統(tǒng)可以相互獨(dú)立的進(jìn)行演進(jìn),,維護(hù),重用等,。Message Queue (MQ)是一種很好的解耦手段,。要了解MQ在系統(tǒng)整合中的作用,可以看Enterprise Integration Patterns (EIP)這本書或?qū)?yīng)的網(wǎng)站,。簡單說就是發(fā)布者只管把消息發(fā)布到MQ中而不管誰會來取,,同樣消息使用者只管只管從MQ取消息而不管是誰發(fā)布的。這樣發(fā)布者和使用者都不用知道對方的存在,。 MQ產(chǎn)品也有很多,,開源的也不少。常見的有activeMQ,,openMQ,,RabbitMQ等。以前也用過MQ系統(tǒng),,而最近在思考SaaS系統(tǒng)中如何使用MQ,。所以在網(wǎng)上看看目前有什么樣的MQ系統(tǒng)具有比較好的擴(kuò)展性,,可以支持大規(guī)模的數(shù)據(jù)流的,就發(fā)現(xiàn)了kafka,。 1. kafka是什么kafka是LinkedIn開發(fā)并開源的一個分布式MQ系統(tǒng),,現(xiàn)在是Apache的一個孵化項目。在它的主頁描述kafka為一個高吞吐量的分布式(能將消息分散到不同的節(jié)點(diǎn)上)MQ,。在這片博文中,作者簡單提到了開發(fā)kafka而不選擇已有MQ系統(tǒng)的原因,。兩個原因:性能和擴(kuò)展性,。這里做適當(dāng)解釋。 基本上目前絕大多數(shù)(如果不是所有的)MQ系統(tǒng)都是針對企業(yè)集成應(yīng)用設(shè)計的,,而不是針對大規(guī)模Service應(yīng)用設(shè)計的,。兩者有什么區(qū)別? 企業(yè)集成的基本特點(diǎn)是把企業(yè)中現(xiàn)存的本不相干的各種應(yīng)用進(jìn)行集成,。例如:一個企業(yè)可能想把財務(wù)系統(tǒng)和倉管系統(tǒng)進(jìn)行集成,,減少部門間結(jié)算和流通的成本和時間,并能更好的支持上層決策,。但這兩個系統(tǒng)是由不同的廠家做的,,不能修改。另外企業(yè)集成是一個持續(xù)漸進(jìn)的過程,,需求變化非常頻繁,。這對MQ系統(tǒng)的要求是要非常靈活,可定制性要求高,。所以常見的MQ系統(tǒng)通常都可以通過復(fù)炸的xml配置或插件開發(fā)進(jìn)行定制以適應(yīng)不同企業(yè)的業(yè)務(wù)流程的需要,。他們大多數(shù)都能通過配置不同程度的支持EIP中定義一些模式。但設(shè)計目標(biāo)并沒有很重視擴(kuò)展性和性能,,因為通常企業(yè)級應(yīng)用的數(shù)據(jù)流和規(guī)模都不會非常大,。即使有的比較大,使用高配置的服務(wù)器或做一個簡單幾個節(jié)點(diǎn)的集群就可以滿足了,。 大規(guī)模的service是指面向公眾的向facebook,,google,linkedin和taobao這樣級別或有可能成長到這個級別的應(yīng)用,。相對企業(yè)集成來講,,這些應(yīng)用的業(yè)務(wù)流程相對比較穩(wěn)定。子系統(tǒng)間集成的業(yè)務(wù)復(fù)雜度也相對較低,,因為子系統(tǒng)通常也是經(jīng)過精心選擇和設(shè)計的并能做一定的調(diào)整,。所以對MQ系統(tǒng)的可定制性及定制的復(fù)雜性要求并不高。但由于數(shù)據(jù)量會非常巨大,,不是幾臺Server能滿足的,,可能需要幾十甚至幾百臺,,且對性能要求較高以降低成本,所以MQ系統(tǒng)需要有很好的擴(kuò)展性,。 kafka正是一個滿足SaaS要求的MQ系統(tǒng),,它通過降低MQ系統(tǒng)的復(fù)雜度來提高性能和擴(kuò)展性。 2. kafka的設(shè)計kafka的設(shè)計文檔詳細(xì)說明了它的設(shè)計思路,。這里簡單列舉并討論一下,。 基本概念kafka的工作方式和其他MQ基本相同,只是在一些名詞命名上有些不同,。為了更好的討論,,這里對這些名詞做簡單解釋。通過這些解釋應(yīng)該可以大致了解kafka MQ的工作方式,。
可靠性(一致性)MQ要實現(xiàn)從producer到consumer之間的可靠的消息傳送和分發(fā)。傳統(tǒng)的MQ系統(tǒng)通常都是通過broker和consumer間的確認(rèn)(ack)機(jī)制實現(xiàn)的,,并在broker保存消息分發(fā)的狀態(tài),。即使這樣一致性也是很難保證的(參考原文)。kafka的做法是由consumer自己保存狀態(tài),,也不要任何確認(rèn),。這樣雖然consumer負(fù)擔(dān)更重,但其實更靈活了,。因為不管consumer上任何原因?qū)е滦枰匦绿幚硐?,都可以再次從broker獲得。 kafka的producer有一種異步發(fā)送的操作,。這是為提高性能提供的,。producer先將消息放在內(nèi)存中,,就返回。這樣調(diào)用者(應(yīng)用程序)就不需要等網(wǎng)絡(luò)傳輸結(jié)束就可以繼續(xù)了,。內(nèi)存中的消息會在后臺批量的發(fā)送到broker,。由于消息會在內(nèi)存呆一段時間,這段時間是有消息丟失的風(fēng)險的,。所以使用該操作時需要仔細(xì)評估這一點(diǎn),。 另外,在最新的版本中,,還實現(xiàn)了broker間的消息復(fù)制機(jī)制,,去除了broker的單點(diǎn)故障(SPOF)。 擴(kuò)展性kafka使用zookeeper來實現(xiàn)動態(tài)的集群擴(kuò)展,,不需要更改客戶端(producer和consumer)的配置。broker會在zookeeper注冊并保持相關(guān)的元數(shù)據(jù)(topic,,partition信息等)更新,。而客戶端會在zookeeper上注冊相關(guān)的watcher。一旦zookeeper發(fā)生變化,,客戶端能及時感知并作出相應(yīng)調(diào)整,。這樣就保證了添加或去除broker時,各broker間仍能自動實現(xiàn)負(fù)載均衡,。 負(fù)載均衡負(fù)載均衡可以分為兩個部分:producer發(fā)消息的負(fù)載均衡和consumer讀消息的負(fù)載均衡,。 producer有一個到當(dāng)前所有broker的連接池,當(dāng)一個消息需要發(fā)送時,,需要決定發(fā)到哪個broker(即partition),。這是由partitioner實現(xiàn)的,partitioner是由應(yīng)用程序?qū)崿F(xiàn)的,。應(yīng)用程序可以實現(xiàn)任意的分區(qū)機(jī)制,。要實現(xiàn)均衡的負(fù)載均衡同時考慮到消息順序的問題(只有一個partition/broker上的消息能保證按順序投遞),partitioner的實現(xiàn)并不容易,。個人認(rèn)為這一點(diǎn)還有待改進(jìn),。 consumer讀取消息時,除了考慮當(dāng)前的broker情況外,,還要考慮其他consumer的情況,,才能決定從哪個partition讀取消息。具體的機(jī)制還不是很清楚,,需要做更深入的研究,。 性能性能是kafka設(shè)計重點(diǎn)考慮的因素。使用多種方法來保證穩(wěn)定的O(1)性能,。 kafka使用磁盤文件保存收到的消息,。它使用一種類似于WAL(write ahead log)的機(jī)制來實現(xiàn)對磁盤的順序讀寫,,然后再定時的將消息批量寫入磁盤。消息的讀取基本也是順序的,。這正符合MQ的順序讀取和追加寫特性,。 另外,kafka通過批量消息傳輸來減少網(wǎng)絡(luò)傳輸,,并使用java中的sendfile和0拷貝機(jī)制減少從讀取文件到發(fā)送消息間內(nèi)存數(shù)據(jù)拷貝和內(nèi)核用戶態(tài)切換的次數(shù),。 根據(jù)kafka的性能測試報告,它的性能基本達(dá)到了O(1)的復(fù)雜度,。 3. 總結(jié)從以上來看,,個人覺得kafka比較適合用來做簡單的消息傳遞和分發(fā),能支持大數(shù)據(jù)量,。但如果需要實現(xiàn)復(fù)雜的EIP模式,,則不像傳統(tǒng)MQ那么容易。而且,,因為只有partition內(nèi)的消息才能保證傳遞順序,,如果消息的順序很重要,又需要很好的擴(kuò)展性,,使用kafka實現(xiàn)可能會比較困難,。所以,kafka應(yīng)該比較適合處理簡單的事件和消息,,例如數(shù)據(jù)(log)收集,,大量事實數(shù)據(jù)的實時分析(kafka可與MapReduce集成)。 但需要注意的是,,kafka現(xiàn)在還只是Apache的孵化項目,,還不是很成熟,雖然開發(fā)活動還是比較活躍的,。
|
|