Posted on 2011-01-20 23:23
dennis 閱讀(7644)
評論(11) 編輯 收藏 所屬分類:
源碼解讀 、
Hadoop與分布式
最近因為空閑時間有一些,所以去看了不少開源項目,大部分東西如果看過不記錄下來,其實還是相當于沒看,所以想想還是有必要摘要記錄一下。
首先是去了解了
zookeeper這個項目,基于paxos算法的分布式服務(wù)組件,同事對此有非常深入的研究和介紹,具體可以看我們的
團隊Blog。令我感慨的是這么一個非常難以理解的算法,卻用一個簡單的樹狀目錄模型表達出來,并且在這個模型的基礎(chǔ)上衍生出種種應(yīng)用:集群感知、分布式鎖、分布式隊列、分布式并發(fā)原語等等,具體可以看文檔給出的
recipes。在實現(xiàn)這些應(yīng)用的時候,突出強調(diào)的是避免網(wǎng)絡(luò)風暴,例如分布式鎖的實現(xiàn),競爭創(chuàng)建子節(jié)點,節(jié)點序列號最小的獲取鎖,其他節(jié)點等待,但是等待在什么條件上是有講究的,如果所有節(jié)點都等待最小節(jié)點的刪除事件,那么當最小節(jié)點釋放鎖的時候,就需要廣播消息給所有其他等待的節(jié)點;換一個思路,如果每個等待節(jié)點只是等待比它序列號小的節(jié)點上,那么就可以避免這種廣播風暴,變成一個順序喚醒的過程。因此盡管有了zookeeper幫助實現(xiàn)分布式這些服務(wù),但是要實現(xiàn)好仍然有一定難度,具體可以參考官方例子。我本來萌生了基于zookeeper實現(xiàn)一套封裝好的類似j.u.c的服務(wù)框架,后來在郵件列表發(fā)現(xiàn)已經(jīng)有人搞了這么一個基礎(chǔ)類庫放在github上:
https://github.com/openUtility/menagerie 。不過我沒有繼續(xù)深入了,有興趣的朋友可以瞧瞧。
然后又去看了我們淘寶開源的
TimeTunnel。TimeTunnel你可以理解成一個消息中間件,它整個設(shè)計跟我們的產(chǎn)品相當接近,但是兩者的目的完全不同,tt強調(diào)的是高吞吐量,而notify強調(diào)的則是可靠性。TT的通訊層直接采用Facebook的thrift,并且利用zookeeper做集群管理和路由。TT的代碼質(zhì)量很好,有興趣可以拉出來看一下,并且對zookeeper的應(yīng)用也是一個典型的案例。TT在高可用性上的方案也很有特色,所有的服務(wù)器節(jié)點形成一個環(huán),兩兩相互主輔備份,一個節(jié)點掛了,后續(xù)節(jié)點仍然可以提供服務(wù)直到主節(jié)點回來,有點類似一致性哈希的概念。節(jié)點的主從關(guān)系和順序也是通過zookeeper保證。消息順序的實現(xiàn)是通過稱為router的路由到固定節(jié)點做傳輸,router默認是策略不是固定而是RR。TT的數(shù)據(jù)存儲優(yōu)先放在內(nèi)存,并設(shè)置了一個內(nèi)存狀況監(jiān)視的組件,當發(fā)現(xiàn)內(nèi)存放不下的時候,swap到磁盤文件緩存,實現(xiàn)類似內(nèi)存換頁的功能。正常情況數(shù)據(jù)都應(yīng)該在內(nèi)存,當然如果可靠級別要求高的話可以先存磁盤再傳輸。TT目前仍然還是比較適合傳輸日志這樣的文本增量數(shù)據(jù),并且提供了TailFile這樣的python腳本幫你做這個事情,這個腳本可以通過checkpoint做斷點續(xù)傳。在學習這個項目的時候,發(fā)現(xiàn)文檔有很大問題,要么錯誤,要么遺漏,并且代碼也不是最新的,我估計開源出來外面的人用的還不太多,希望慢慢能搞的更好一些。
跟TT類似,另一個追求高吞吐量的MQ是linkedin開源的
kafka。Kafka就跟這個名字一樣,設(shè)計非常獨特。首先,kafka的開發(fā)者們認為不需要在內(nèi)存里緩存什么數(shù)據(jù),操作系統(tǒng)的文件緩存已經(jīng)足夠完善和強大,只要你不搞隨機寫,順序讀寫的性能是非常高效的。kafka的數(shù)據(jù)只會順序append,數(shù)據(jù)的刪除策略是累積到一定程度或者超過一定時間再刪除。Kafka另一個獨特的地方是將消費者信息保存在客戶端而不是MQ服務(wù)器,這樣服務(wù)器就不用記錄消息的投遞過程,每個客戶端都自己知道自己下一次應(yīng)該從什么地方什么位置讀取消息,消息的投遞過程也是采用客戶端主動pull的模型,這樣大大減輕了服務(wù)器的負擔。Kafka還強調(diào)減少數(shù)據(jù)的序列化和拷貝開銷,它會將一些消息組織成Message Set做批量存儲和發(fā)送,并且客戶端在pull數(shù)據(jù)的時候,盡量以zero-copy的方式傳輸,利用sendfile(對應(yīng)java里的FileChannel.transferTo/transferFrom)這樣的高級IO函數(shù)來減少拷貝開銷。可見,kafka是一個精心設(shè)計,特定于某些應(yīng)用的MQ系統(tǒng),這種偏向特定領(lǐng)域的MQ系統(tǒng)我估計會越來越多,垂直化的產(chǎn)品策略值的考慮。
在此期間,我還重新去看了activemq和hornetq的存儲實現(xiàn),從實現(xiàn)上大家都大同小異,append log + data file的模式。Activemq采用異步隊列寫來提高吞吐量,而Hornetq干脆就直接利用JNI調(diào)用原生aio來實現(xiàn)高性能。在搜索Java的aio實現(xiàn)的時候,碰巧發(fā)現(xiàn)Mina的沙箱里有個aioj的實現(xiàn),源碼在:
https://svn.apache.org/repos/asf/mina/sandbox/mheath/aioj/ 。我測試了完全可用,也嘗試改造我們的磁盤存儲組件,可惜提升不多,估計不從整個設(shè)計上調(diào)整服務(wù)器,不大可能從aio上獲益。
最近也重新看起了clojure的一些開源項目,clojure的開源資源在github上也非常豐富,有待挖掘,下次有機會再嘗試介紹一二。