linugb118--java space

          Java

          【轉(zhuǎn)】豆瓣架構(gòu)

           各位觀眾朋友大家好,這里是InfoQ中文站的賴翥翔,現(xiàn)在在首屆QCon北京大會(huì)的現(xiàn)場(chǎng),坐在我旁邊的是來(lái)自豆瓣網(wǎng)的洪強(qiáng)寧。強(qiáng)寧你好,向大家介紹一下自己以及自己和豆瓣的聯(lián)系。 
          我是大概在06年的3月份加入豆瓣的。當(dāng)時(shí)應(yīng)該是豆瓣的02號(hào)程序員。01號(hào)是阿北?,F(xiàn)在是任豆瓣的首席架構(gòu)師。負(fù)責(zé)豆瓣技術(shù)開發(fā)的相關(guān)工作。
           我記得在之前社區(qū)中有對(duì)豆瓣高并發(fā)能力的討論,豆瓣現(xiàn)在的用戶數(shù)量以及訪問量如何?用了多長(zhǎng)時(shí)間達(dá)到了現(xiàn)在的水平? 
          現(xiàn)在的話,我剛才沒有上網(wǎng),不知道現(xiàn)在是不是已經(jīng)達(dá)到了300萬(wàn)用戶,如果還沒有達(dá)到的話,馬上就會(huì)到了,可能是今天,可能是明天。300萬(wàn)是指我們的注冊(cè)用戶,另外還有千萬(wàn)級(jí)的非注冊(cè)用戶。訪問量的話,現(xiàn)在應(yīng)該是兩千萬(wàn)每天。
           如果能達(dá)到這樣的訪問量,確實(shí)說明豆瓣高并發(fā)的能力是相當(dāng)強(qiáng),我想請(qǐng)您從技術(shù)這個(gè)角度介紹一下豆瓣網(wǎng)的架構(gòu)。 
          這個(gè)話題比較大一點(diǎn),我剛才在演講的時(shí)候,已經(jīng)表述這方面的問題了??梢赃@么說,最簡(jiǎn)單的方法來(lái)說,豆瓣網(wǎng)可分割成兩大塊:一塊是前端的Web,也就是用戶在瀏覽器訪問的時(shí)候會(huì)觸發(fā)一系列的操作,從數(shù)據(jù)庫(kù)拿出數(shù)據(jù),渲染成HTML頁(yè)面反饋給用戶,這是前端;另外一塊是后端,在豆瓣有一個(gè)很強(qiáng)的數(shù)據(jù)挖掘團(tuán)隊(duì),每天把用戶產(chǎn)生的數(shù)據(jù)進(jìn)行分析,進(jìn)行組合,然后產(chǎn)生出用戶推薦,然后放在數(shù)據(jù)庫(kù)里面,前端會(huì)實(shí)時(shí)的抓取這些數(shù)據(jù)顯示給用戶。
           如果是這樣子,要是讓你重新設(shè)計(jì)的話,你會(huì)覺得有必要改進(jìn)里面哪些部分嗎? 
          豆瓣(架構(gòu))設(shè)計(jì)現(xiàn)在在WEB這一端主要是用這么幾種技術(shù):前端是nginx和lighttpd,中間是Quixote的Web框架,后面是MySQL以及我們自己開發(fā)的DoubanDB。這些除了Quixote都是一些比較流行的、尖端的技術(shù)。Quixote稍微老一點(diǎn),如果要重新設(shè)計(jì)的話,可能會(huì)在這方面做一些考慮。比如Python社區(qū)中的Django、Pylons等等都是可以考慮的,那么在豆瓣的內(nèi)部的話,我們一般是用web.py,很輕量的一個(gè)Web框架來(lái)做,也是非常不錯(cuò)的選擇,它可能需要自己做的事情多一點(diǎn)。但是,也不太可能完全重新設(shè)計(jì)了。
           那如果要緩解高并發(fā)所帶來(lái)的壓力,Cache的利用肯定是一個(gè)非常有效的途徑。那么豆瓣的緩存命中率一般是多大?這方面的策略是怎樣? 
          Memcache命中率一般都在97%左右,應(yīng)該還算是比較高的。策略其實(shí)是比較簡(jiǎn)單的,如果每次要去執(zhí)行一個(gè)比較耗時(shí)耗資源的操作,比如說去數(shù)據(jù)庫(kù)查詢的話,就會(huì)以Python的Object形式存放在Memcache里面,下次再拿這個(gè)數(shù)據(jù)的時(shí)候就直接從Cache中拿就行了。這邊選擇什么樣的東西,盡量有一個(gè)Guideline,必須是要耗時(shí)的,耗資源的,而且是重復(fù)使用的。比如它是耗資源的,但是只用一次,Cache也沒有意義。差不多用這種方法保證Cache的東西都是真正有效的,也提高了命中率。
           要提高承受高壓力的流量,另外一個(gè)有效的措施是對(duì)數(shù)據(jù)庫(kù)來(lái)進(jìn)行分區(qū)分片,在這方面豆瓣是怎么做的? 
          豆瓣現(xiàn)在還沒有達(dá)到數(shù)據(jù)庫(kù)分片的程度。我們現(xiàn)在最常見的手段是,按照功能分區(qū)。我們會(huì)把數(shù)據(jù)表分成幾個(gè)獨(dú)立的庫(kù),現(xiàn)在是一共有4個(gè)庫(kù)。每個(gè)表都是庫(kù)的一個(gè)部分,每個(gè)庫(kù)會(huì)有主副兩個(gè)。通過這種方式來(lái)減輕數(shù)據(jù)庫(kù)的壓力,當(dāng)然這個(gè)是現(xiàn)在的方案,再往后的話,表的行數(shù)會(huì)增長(zhǎng),到達(dá)一定的程度后,還要進(jìn)行水平分割,這是肯定的。然后我們現(xiàn)在的技術(shù)方面,在操作數(shù)據(jù)庫(kù)之前,首先獲取數(shù)據(jù)庫(kù)的游標(biāo),有一個(gè)方法,這個(gè)方法會(huì)干所有的事情,我們以后做的時(shí)候會(huì)從這個(gè)方法中進(jìn)行判斷該從哪取東西。這個(gè)架構(gòu)已經(jīng)在了,只是現(xiàn)在還沒有做這一步而已。
           數(shù)據(jù)庫(kù)這邊主要采用什么解決方案呢? 
          在數(shù)據(jù)庫(kù)這邊,我們主要用的是MySQL。MySQL有一個(gè)問題,大文本字段會(huì)影響它的性能。如果數(shù)據(jù)量過大的話,它會(huì)擠占索引的內(nèi)存。那么現(xiàn)在一個(gè)行之有效的方法是,我們另外建立一套可伸縮的Key-Value數(shù)據(jù)庫(kù),叫做DoubanDB。我們把不需要索引的大文本字段,放到DoubanDB里面去。MySQL只保存需要索引的Relationship這方面的信息。這樣給MySQL數(shù)據(jù)庫(kù)降低了壓力,也就可以保證它的性能。
           比如說像保證數(shù)據(jù)的安全性,以及數(shù)據(jù)庫(kù)的吞吐量,豆瓣是怎樣的策略呢? 
          首先DoubanDB會(huì)把每個(gè)數(shù)據(jù)在三個(gè)節(jié)點(diǎn)進(jìn)行備份,任何一個(gè)出現(xiàn)故障都不會(huì)影響索取數(shù)據(jù)。MySQL是通過雙Master方案,同時(shí)還會(huì)帶1到2個(gè)slave,所以說在MySQL中我們會(huì)有三到四個(gè)的備份。這點(diǎn)是可以放心的。
           你剛才說到MySQL的雙Master方案,這方面會(huì)不會(huì)存在什么問題?比如說同步的問題,等等? 
          在MySQL里面,雙Master方案是一個(gè)比較經(jīng)典的方案,我們現(xiàn)在用它很大一部分是為了解決我們同步延遲的問題。在做切換的時(shí)候,會(huì)出現(xiàn)同步延遲的問題,但其實(shí)MySQL的同步速度還是可以的,在切換的時(shí)候,我們會(huì)忍受幾秒鐘等待同步的時(shí)間。在做腳本的切換的時(shí)候,我們會(huì)稍微等一下。
           豆瓣的數(shù)據(jù)表一般是怎么樣的規(guī)模? 
          數(shù)據(jù)表,這個(gè)不好說了,因?yàn)椴煌谋矶际遣灰粯拥摹N覀冏畲蟮谋硎?#8220;九點(diǎn)”的Entry表,“九點(diǎn)”的爬蟲爬過來(lái)的所有的文章,現(xiàn)在應(yīng)該有四千萬(wàn)左右的行數(shù)。然后其他的上百萬(wàn)的表也有很多。還有包括收藏表也有千萬(wàn)級(jí)的行數(shù)。
           在這種海量數(shù)據(jù)的情況下,對(duì)數(shù)據(jù)表的就結(jié)構(gòu)變更,一定是一個(gè)比較麻煩的問題。常見的情況,比如增加一個(gè)新的索引,會(huì)導(dǎo)致索引好幾個(gè)小時(shí)。像豆瓣之前會(huì)存在這樣的問題,是怎么解決的呢? 
          這個(gè)問題曾經(jīng)讓我們吃過苦頭,在忽視它的狀況下就去改表,然后就鎖了很長(zhǎng)時(shí)間。后來(lái)我們意識(shí)到這個(gè)問題,如果有表的改動(dòng)的話,我們會(huì)先在一個(gè)測(cè)試的庫(kù)上試驗(yàn)一下它的時(shí)間長(zhǎng)短,是不是在可接受的范圍,如果是可接受的范圍,比如說幾分鐘,就做一個(gè)定時(shí)任務(wù),在深夜里面去執(zhí)行。如果耗時(shí)是不可忍受的,就必須通過其他技術(shù)手段,我們現(xiàn)在的手段一般是建一個(gè)新表,這個(gè)新表從舊表同步數(shù)據(jù),然后再寫數(shù)據(jù)的時(shí)候,也會(huì)同步,往兩邊寫,一直到兩邊完全一樣了,再把舊表刪掉,大概是這樣一個(gè)方式。
           剛才您好像提過你們?cè)O(shè)計(jì)了自己的DoubanDB,還有一個(gè)是DoubanFS,這兩者關(guān)系是怎么樣的? 
          首先是先出來(lái)的DoubanFS,我們剛開始的時(shí)候用MogileFS來(lái)解決我們可擴(kuò)展圖片存儲(chǔ)的問題,由于MogileFS有一個(gè)重型數(shù)據(jù)庫(kù),這成為了它的性能瓶頸。我們?yōu)榱私鉀Q這個(gè)問題,開發(fā)了DoubanFS,基于哈希來(lái)尋找節(jié)點(diǎn)。之后,我們又發(fā)現(xiàn)了新的問題,數(shù)據(jù)庫(kù)中的大文本字段也會(huì)影響性能。所以,我們?cè)贒oubanFS的基礎(chǔ)上,換了一個(gè)底層,做了一些調(diào)整,參照Amazon的dynamo思想,搭建了DoubanDB,把文本字段放在DoubanDB里面。做完之后,又反過來(lái)用DoubanDB來(lái)實(shí)現(xiàn)FS,大致是這么一個(gè)過程。
           DoubanFS跟DoubanDB的實(shí)現(xiàn),他們?cè)趯?duì)于內(nèi)容的安全性,或者內(nèi)容的冗余性… 
          都是(備份)三份。這都是可以配置的,現(xiàn)在的配置是3份。
           DoubanDB就是用什么機(jī)制實(shí)現(xiàn)的? 
          DoubanDB簡(jiǎn)單來(lái)說是這樣子:你來(lái)一個(gè)Key,它是Key-Value數(shù)據(jù)庫(kù),你要寫或讀的時(shí)候,通過這個(gè)Key來(lái)尋找這個(gè)值。拿一個(gè)Key對(duì)它做哈希,通過Consistent哈希方法去查找它在哪個(gè)節(jié)點(diǎn)上,然后往這個(gè)節(jié)點(diǎn)上去寫或讀。在這個(gè)節(jié)點(diǎn)上,順著哈希的wheel順次的找到第二、三個(gè)節(jié)點(diǎn),寫的時(shí)候會(huì)保證這三個(gè)節(jié)點(diǎn)都寫,讀的時(shí)候是任意一個(gè),如果其中一個(gè)讀失敗了,會(huì)自動(dòng)切換到下一個(gè)。
           您剛才提DoubanDB的話,是采用的技術(shù)是? 
          DoubanDB的底層存儲(chǔ)用的是TokyoCabinet,是一個(gè)很輕量級(jí)、高效的Key-Value數(shù)據(jù)庫(kù)。我們?cè)谒幕A(chǔ)之上,做了分布式,用這種方式來(lái)實(shí)現(xiàn)的。
           實(shí)際上有一些其他的方案可以解決,比如說像Berkeley DB(簡(jiǎn)稱BDB)、CouchDB等等,你們?yōu)槭裁匆x擇TokyoCabinet? 
          最簡(jiǎn)單的原因是由于它足夠快,實(shí)際上BDB跟它比較類似,BDB更加強(qiáng)大一些。對(duì)我們而言,我們?cè)谶@邊就是需要一個(gè)可靠、高效的Key-Value存儲(chǔ),這兩個(gè)其實(shí)是我們都可以替換的,只要統(tǒng)一下接口就可以。CouchDB的話就是另外一個(gè)東西了,它是一個(gè)文檔型數(shù)據(jù)庫(kù),它不僅僅做了一個(gè)Key-Value的工作,它還在這上面做了很多其他的事情,比如它有View的概念,可以進(jìn)行query。這些TokyoCabinet是沒有的,而我們暫時(shí)也不需要這些功能。CouchDB是一個(gè)很有意思的數(shù)據(jù)庫(kù),我們可能會(huì)在其他方面(應(yīng)用),我們也在研究它。
           從我們剛才的討論中,Web前端你用了nginx又用了lighttpd。它們都是非常流行的前端,這兩種方案經(jīng)常打架,豆瓣為什么把它們?nèi)诤显谝粔K? 
          這是歷史原因。我們其實(shí)沒有刻意地去傾向某一個(gè)。這兩個(gè)都是非常優(yōu)秀的Web Server,都很輕量,都很高效。最開始的時(shí)候我們用的是lighttpd,然后是因?yàn)槌霈F(xiàn)過一些問題,其實(shí)不是lighttpd的問題,但當(dāng)時(shí)我們懷疑可能是lighttpd有問題,就嘗試了一下nginx,覺得這個(gè)也不錯(cuò),然后這個(gè)結(jié)構(gòu)就保留下來(lái)了。nginx對(duì)開發(fā)者和用戶的友好性都更好一些。我舉個(gè)例子,比如說重啟,其實(shí)在豆瓣的Web Server是經(jīng)常要重啟的,我們會(huì)有一個(gè)健康檢查的腳本,定時(shí)的檢查網(wǎng)站是不是正常,如果覺得不正常的話,就會(huì)做一些保護(hù)措施,其中就包括重啟。lighttpd的重啟,是一個(gè)很粗暴的Kill。Nginx是一個(gè)reload的方案,會(huì)先把手頭的事情做完了再重啟。這樣會(huì)好很多,而且它會(huì)在重啟之前會(huì)幫你做一些好的事情。所以,現(xiàn)在我們用Nginx越來(lái)越多。Nginx的配置文件也比lighttpd寫起來(lái)更舒服一些。
           豆瓣現(xiàn)在有一個(gè)龐大的用戶群體,針對(duì)這樣一些海量數(shù)據(jù)做好數(shù)據(jù)挖掘,肯定不是一件容易的事情,能從技術(shù)這個(gè)角度講講挖掘的實(shí)現(xiàn)嗎? 
          在豆瓣專門有一個(gè)算法團(tuán)隊(duì),他們的主要工作就是數(shù)據(jù)挖掘。這邊講技術(shù)實(shí)現(xiàn)的話,可能就講不完了。只能講一些大概,數(shù)據(jù)挖掘是怎么和前端結(jié)合起來(lái)的,讓用戶看見的。每天用戶在豆瓣上的操作都會(huì)產(chǎn)生很多數(shù)據(jù),在豆瓣上面看到的東西,收藏的東西,都會(huì)存在數(shù)據(jù)庫(kù)或是訪問日志。每天這些信息都會(huì)傳到算法團(tuán)隊(duì)的機(jī)器上,然后會(huì)從這個(gè)數(shù)據(jù)中建立一個(gè)稀疏矩陣,你看過什么,干過什么。他們維護(hù)了一個(gè)很高效的稀疏矩陣運(yùn)算庫(kù),然后用它來(lái)做各種各樣的嘗試,去看是否能得到好的結(jié)果,一旦發(fā)現(xiàn)這個(gè)結(jié)果很好,就會(huì)把它寫到數(shù)據(jù)庫(kù)里面。然后用戶在訪問的時(shí)候,前端從數(shù)據(jù)庫(kù)中取出推薦給你的數(shù)據(jù),然后把這些數(shù)據(jù)做一些過濾(比如你讀過的東西就不再給你展現(xiàn)了)、調(diào)整,最后展現(xiàn)給用戶。基本上是這么一個(gè)邏輯。
           從剛才你所描述的內(nèi)容,可以發(fā)現(xiàn)豆瓣其實(shí)是一個(gè)應(yīng)用非常多的,幾乎用的都是開源框架吧? 
          全部是開源的。
           我相信你們從社區(qū)的智慧以及各方面都會(huì)獲取很多東西,我不知道豆瓣對(duì)開源社區(qū)是不是也做了一些回饋? 
          是有的,我們最大的回饋形式是patch。我們用很多的開源軟件,這當(dāng)中就不可避免的有各種各樣的問題,我們會(huì)嘗試通過自己的努力解決這些問題,把我們的解決方案反饋給開發(fā)者。比較典型的像libmemcached,是一個(gè)C的memcached客戶端?,F(xiàn)在也是非?;鸬模臼且粋€(gè)官方的C的客戶端。它其實(shí)有很多bug,我們?cè)谑褂玫臅r(shí)候發(fā)現(xiàn),去修正它?,F(xiàn)在我們的團(tuán)隊(duì)成員里面有直接就是它的開發(fā)成員。比如說像Python的Mako模板,也是用的人非常多的模板。我們也在使用,使用起來(lái)發(fā)現(xiàn)它的性能稍微弱一些,我們也花了精力對(duì)它進(jìn)行了優(yōu)化,這個(gè)優(yōu)化現(xiàn)在也是被接受了,在Mako的后來(lái)版本發(fā)布出來(lái)了。然后豆瓣自己也有一些開源的項(xiàng)目,最主要的開源的項(xiàng)目是豆瓣API的訪問客戶端,這個(gè)是在google code上面,也有很多志愿者參與進(jìn)來(lái),幫我們一起修改。然后從另外一個(gè)方面來(lái)說,豆瓣和國(guó)內(nèi)的開源社區(qū)也有緊密的聯(lián)系。豆瓣的上線通知就是發(fā)在開源組織CPUG的郵件列表里面的,豆瓣的很多成員也是CPUG的成員,會(huì)在郵件列表里面去幫助回答問題,討論問題,這也是一種回饋的方式。
           豆瓣的開發(fā)團(tuán)隊(duì)是怎么樣的? 
          我們現(xiàn)在開發(fā)團(tuán)隊(duì)這邊是11個(gè)人,有全職有兼職,還是比較放松。我們采用的是敏捷的方法,但是也不是完全的一模一樣的方式。在豆瓣內(nèi)部,我們盡可能地去發(fā)揮每個(gè)人的創(chuàng)造力。比如,在豆瓣作息是自由的,你可以自己決定什么時(shí)候來(lái),什么時(shí)候走。比如你想在家里面靜下心來(lái)寫code,你可以往郵件列表里面發(fā)條消息說,我今天不過來(lái)了,就可以在家里面。每天會(huì)有很多的討論,我們?cè)诙拱甑霓k公室是一個(gè)獨(dú)立的區(qū)域。在這個(gè)區(qū)域里面有白板,大家可以隨時(shí)討論。然后每周我們會(huì)有一個(gè)技術(shù)交流會(huì)議,大家輪流來(lái)發(fā)表一下自己最近在看一些什么東西,有什么心得,跟大家分享一下,這些都促進(jìn)團(tuán)隊(duì)的溝通與發(fā)展的,很有用的東西。
           看來(lái)豆瓣是一個(gè)相當(dāng)開放、技術(shù)和興趣驅(qū)動(dòng)的團(tuán)隊(duì)。 
          我們希望一直保持這樣的樣子。
           那現(xiàn)場(chǎng)的觀眾有沒有什么問題?其他記者:我是接著社區(qū)那個(gè)話題問一下,豆瓣現(xiàn)在有了很多的積累,有很多東西都已經(jīng)成形了,有沒有考慮說開放一些項(xiàng)目?
          我們是有這個(gè)計(jì)劃的。比如說DoubanDB,實(shí)際上我們?cè)趧?chuàng)立這個(gè)項(xiàng)目的時(shí)候,就是說這個(gè)項(xiàng)目我們做出來(lái)后是要開源的,到現(xiàn)在還沒開源,是因?yàn)檫@個(gè)項(xiàng)目還在變化之中。由于開發(fā)的時(shí)間上的限制,所以現(xiàn)在還和豆瓣本身的數(shù)據(jù)綁得太緊,我們而且也是在不斷地調(diào)整,現(xiàn)在還在調(diào)整的過程當(dāng)中。找一個(gè)合適時(shí)機(jī),我們會(huì)把它跟的豆瓣的數(shù)據(jù)剝離出來(lái),成為一個(gè)可以獨(dú)立地去安裝、運(yùn)行的應(yīng)用的時(shí)候,就會(huì)把它拿出來(lái),我想應(yīng)該很快就能夠做到這點(diǎn)。
           非常感謝強(qiáng)寧接受我們的采訪,也恭喜今天在大會(huì)的演講上面取得了非常圓滿的成功。 
          謝謝。

          posted on 2010-03-15 13:48 linugb118 閱讀(202) 評(píng)論(0)  編輯  收藏


          只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           

          My Links

          Blog Stats

          常用鏈接

          留言簿(1)

          隨筆檔案

          搜索

          最新評(píng)論

          閱讀排行榜

          評(píng)論排行榜

          主站蜘蛛池模板: 灵宝市| 莲花县| 兖州市| 宜黄县| 台中市| 涟源市| 裕民县| 安塞县| 巩留县| 都兰县| 崇信县| 亚东县| 漯河市| 彰化市| 姚安县| 乐清市| 临汾市| 日土县| 隆安县| 浮山县| 通山县| 嵩明县| 天气| 临邑县| 兴仁县| 邯郸县| 陈巴尔虎旗| 拉萨市| 绿春县| 乌什县| 青海省| 玉门市| 沂南县| 扶沟县| 眉山市| 巢湖市| 濮阳市| 常德市| 弋阳县| 海淀区| 聂荣县|