豆瓣首席架構師洪強寧 談豆瓣網技術架構
概要
如何應對高并發、大訪問量?如何保證數據的安全性以及數據庫大吞吐量?在海量數據下,如何進行數據表變更?DoubanFS以及DoubanDB的特點以及技術實現?在QConBeijing2009期間,InfoQ中文站有幸采訪了洪強寧,探討了相關話題。
個人簡介
洪強寧,2002年畢業于清華大學,現任北京豆瓣互動科技有限公司首席架構師。洪強寧和他帶領的技術團隊致力于用技術改善人們的文化和生活品質,在網站架構、性能、可伸縮性上進行深入研究。豆瓣網曾獲軟件中國2006年度最佳技術應用網站。
關于會議
QCon全球企業開發大會(QCon Enterprise Software Development Conference)是由C4Media媒體集團InfoQ網站主辦的全球頂級技術盛會,每年在倫敦、舊金山、北京、東京召開。自2007年3月份在倫敦召開首次舉辦以來,已經有包括金融、電信、互聯網、航空航天等領域的近萬名架構師、項目經理、團隊領導者和高級開發人員參加過QCon大會。
我是大概在06年的3月份加入豆瓣的。當時應該是豆瓣的02號程序員。01號是阿北?,F在是任豆瓣的首席架構師。負責豆瓣技術開發的相關工作。
我記得在之前社區中有對豆瓣高并發能力的討論,豆瓣現在的用戶數量以及訪問量如何?用了多長時間達到了現在的水平?
現在的話,我剛才沒有上網,不知道現在是不是已經達到了300萬用戶,如果還沒有達到的話,馬上就會到了,可能是今天,可能是明天。300萬是指我們的注冊用戶,另外還有千萬級的非注冊用戶。訪問量的話,現在應該是兩千萬每天。
如果能達到這樣的訪問量,確實說明豆瓣高并發的能力是相當強,我想請您從技術這個角度介紹一下豆瓣網的架構。
這個話題比較大一點,我剛才在演講的時候,已經表述這方面的問題了??梢赃@么說,最簡單的方法來說,豆瓣網可分割成兩大塊:一塊是前端的Web,也就是用戶在瀏覽器訪問的時候會觸發一系列的操作,從數據庫拿出數據,渲染成HTML頁面反饋給用戶,這是前端;另外一塊是后端,在豆瓣有一個很強的數據挖掘團隊,每天把用戶產生的數據進行分析,進行組合,然后產生出用戶推薦,然后放在數據庫里面,前端會實時的抓取這些數據顯示給用戶。
如果是這樣子,要是讓你重新設計的話,就是說你會覺得有必要改進里面哪些部分嗎?
豆瓣(架構)設計現在在WEB這一端主要是用這么幾種技術:前端是ngix和lighttpd,中間是Quixote的Web框架,后面是MySQL以及我們自己開發的DoubanDB。這些除了Quixote都是比較流行的、尖端的一些技術。Quixote稍微老一點,如果要重新設計的話,可能會在這方面做一些考慮。比如Python社區中的Django、Pylons等等都是可以考慮的,那么在豆瓣的內部的話,我們一般是用web2py,很輕量的一個Web框架來做,也是非常不錯的選擇,它可能需要自己做的事情多一點。但是,也不太可能完全重新設計了。
那如果要緩解高并發所帶來的壓力,Cache的利用肯定是一個非常有效的途徑。那么豆瓣的緩存命中率一般是多大?這方面的策略是怎樣?
Memcache命中率一般都在97%左右,應該還算是比較高的。策略其實是比較簡單的,如果每次要去執行一個比較耗時耗資源的操作,比如說去數據庫查詢的話,就會以Python的Object形式存放在Memcache里面,下次再拿這個數據的時候就直接從Cache中拿就行了。這邊選擇什么樣的東西,盡量有一個Guideline,一個是必須是要耗時的,耗資源的,而且是重復使用的。比如它是耗資源的,但是只用一次,Cache也沒有意義。差不多用這種方法保證Cache的東西都是真正有效的,也提高了命中率。
要提高承受高壓力的流量,另外一個有效的措施是對數據庫來進行分區分片,在這方面豆瓣是怎么做的?
豆瓣現在還沒有達到數據庫分片的程度。我們現在最常見的手段是,按照功能分區。我們會把數據表分成幾個獨立的庫,現在是一共有4個庫。每個表都是庫的一個部分,每個庫會有主副兩個。通過這種方式來減輕數據庫的壓力,當然這個是現在的方案,再往后的話,表的行數會增長,到達一定的程度后,還要進行水平分割,這是肯定的。然后我們現在的技術方面,在操作數據庫之前,首先獲取數據庫的游標,有一個方法,這個方法會干所有的事情,我們以后做的時候會從這個方法中進行判斷該從哪取東西。這個架構已經在了,只是現在還沒有做這一步而已。
數據庫這邊主要采用什么解決方案呢?
在數據庫這邊,我們主要用的是MySQL。MySQL有一個問題,大文本字段會影響它的性能。如果數據量過大的話,它會擠占索引的內存。那么現在一個行之有效的方法是,我們另外建立一套可伸縮的Key-Value數據庫,叫做DoubanDB。我們把不需要索引的大文本字段,放到DoubanDB里面去。MySQL只保存需要索引的Relationship這方面的信息。這樣給MySQL數據庫降低了壓力,也就可以保證它的性能。
比如說像保證數據的安全性,以及數據庫的吞吐量,豆瓣是怎樣的策略呢?
首先DoubanDB會把每個數據在三個節點進行備份,任何一個出現故障都不會影響索取數據。MySQL是通過雙Master方案,同時還會帶1到2個slave,所以說在MySQL中我們會有三到四個的備份。這點是可以放心的。
你剛才說到MySQL的雙Master方案,這方面會不會存在什么問題?比如說同步的問題,等等?
在MySQL里面,雙Master方案是一個比較經典的方案,我們現在用它很大一部分是為了解決我們同步延遲的問題。在做切換的時候,會出現同步延遲的問題,但其實MySQL的同步速度還是可以的,在切換的時候,我們會忍受幾秒鐘等待同步的時間。在做腳本的切換的時候,我們會稍微等一下。
豆瓣的數據表一般是怎么樣的規模?
數據表,這個不好說了,因為不同的表都是不一樣的。我們最大的表是“九點”的Entry表,“九點”的爬蟲爬過來的所有的文章,現在應該有四千萬左右的行數。然后其他的上百萬的表也有很多。還有包括收藏表也有千萬級的行數。
在這種海量數據的情況下,對數據表的就結構變更,一定是一個比較麻煩的問題。常見的情況,比如增加一個新的索引,會導致索引好幾個小時。像豆瓣之前會存在這樣的問題,是怎么解決的呢?
這個問題曾經讓我們吃過苦頭,在忽視它的狀況下就去該表,然后就索了很長時間。后來我們意識到這個問題,如果有表的改動的話,我們會先在一個測試的庫上試驗一下它的時間長短,是不是在可接受的范圍,如果是可接受的范圍,比如說幾分鐘,就做一個定時任務,在深夜里面去執行。如果耗時是不可忍受的,就必須通過其他技術手段,我們現在的手段一般是建一個新表,這個新表從舊表同步數據,然后再寫數據的時候,也會同步,往兩邊寫,一直到兩邊完全一樣了,再把舊表刪掉,大概是這樣一個方式。
剛才您好像提過你們設計了自己的DoubanDB,還有一個是DoubanFS,這兩者關系是怎么樣的?
首先是先出來的DoubanFS,我們剛開始的時候用MogileFS來解決我們可擴展圖片存儲的問題,由于MogileFS有一個重型數據庫,這成為了它的性能瓶頸。我們為了解決這個問題,開發了DoubanFS,基于哈希來尋找節點。之后,我們又發現了新的問題,數據庫中的大文本字段也會影響性能。所以,我們在DoubanFS的基礎上,換了一個底層,做了一些調整,參照Amazon的dynamo思想,搭建了DoubanDB,把文本字段放在DoubanDB里面。做完之后,又反過來用DoubanDB來實現FS,大致是這么一個過程。
DoubanFS跟DoubanDB的實現,他們在對于內容的安全性,或者內容的冗余性…
都是(備份)三份。這都是可以配置的,現在配置是3份。
DoubanDB就是用什么機制實現的?
DoubanDB簡單來說是這樣子:你來一個Key,它是Key-Value數據庫,你要寫或讀的時候,通過這個Key來尋找這個值。拿一個Key對它做哈希,通過Consistent哈希方法去查找它在哪個節點上,然后往這個節點上去寫或讀。在這個節點上,順者哈希的wheel順次的找到第二、三個節點,寫的時候會保證這三個節點都寫,讀的時候是任意一個,如果其中一個讀失敗了,會自動切換到下一個。
您剛才提DoubanDB的話,是采用的技術是?
DoubanDB的底層存儲用的是TokyoCabinet,是一個很輕量級、高效的Key-Value數據庫。我們在它的基礎之上,做了分布式,用這種方式來實現的。
實際上有一些其他的方案可以解決,比如說像Berkeley DB(簡稱BDB)、CouchDB等等,你們為什么要選擇
TokyoCabinet?
最簡單的原因是由于它足夠快,實際上BDB跟它比較類似,BDB更加強大一些。對我們而言,我們在這邊就是需要一個可靠、高效的Key-Value存儲,這兩個其實是我們都可以替換的,只要統一下接口就可以。CouchDB的話就是另外一個東西了,它是一個文檔型數據庫,它不僅僅做了一個Key-Value的工作,它還在這上面做了很多其他的事情,比如它有View的概念,可以進行query。這些TokyoCabinet是沒有的,而我們暫時也不需要這些功能。CouchDB是一個很有意思的數據庫,我們可能會在其他方面(應用),我們也在研究它。
從我們剛才的討論中,Web前端你用了ngix又用了lighttpd。它們都是非常流行的前端,這兩種方案經常打架,豆瓣為什么把它們融合在一塊?
這是歷史原因。我們其實沒有刻意地去傾向某一個。這兩個都是非常優秀的Web Server,都很輕量,都很高效。最開始的時候我們用的是lighttpd,然后是因為出現過一些問題,其實不是lighttpd的問題,但當時我們懷疑可能是lighttpd有問題,就嘗試了一下ngix,覺得這個也不錯,然后這個結構就保留下來了。ngix對開發者和用戶的友好性都更好一些。我舉個例子,比如說重啟,其實在豆瓣的Web Server是經常要重啟的,我們會有一個健康檢查的腳本,定時的檢查網站是不是正常,如果覺得不正常的話,就會做一些保護措施,其中就包括重啟。lighttpd的重啟,是一個很粗暴的Kill。Ngix是一個reload的方案,會先把手頭的事情做完了再重啟。這樣會好很多,而且它會在重啟之前會幫你做一些好的事情。所以,現在我們用Ngix越來越多。Ngix的配置文件也比lighttpd寫起來更舒服一些。
豆瓣現在有一個龐大的用戶群體,針對這樣一些海量數據做好數據挖掘,肯定不是一件容易的事情,能從技術這個角度講講挖掘的實現嗎?
在豆瓣專門有一個算法團隊,他們的主要工作就是數據挖掘。這邊講技術實現的話,可能就將不完了。只能將一些大概,數據挖掘是怎么和前端結合起來的,讓用戶看見的。每天用戶在豆瓣上的操作都會產生很多數據,在豆瓣上面看到的東西,收藏的東西,都會存在數據庫或是訪問日志。每天這些信息都會傳給算法團隊的機器上,然后會從這個數據中建立一個矩陣,你看過什么,干過什么。他們維護了一個很高效的系數矩陣運算庫,然后用它來做各種各樣的嘗試,去看是否能得到好的結果,一旦發現這個結果很好,就會把它寫到數據庫里面。然后用戶在訪問的時候,前端從數據庫中取出推薦給你的數據,然后把這些數據做一些過濾(比如你讀過的東西就不再給你展現了)、調整,最后展現給用戶?;旧鲜沁@么一個邏輯。
從剛才你所描述的內容,可以發現豆瓣其實是一個應用非常多的,幾乎用的都是開源框架吧?
全部是開源的。
我相信你們從社區的智慧以及各方面都會獲取很多東西,我不知道豆瓣對開源社區是不是也做了一些回饋?
是有的,我們最大的回饋形式是patch。我們用很多的開源軟件,這當中就不可避免的有各種各樣的問題,我們會嘗試通過自己的努力解決這些問題,把我們的解決方案反饋給開發者。比較典型的像libmemcached,是一個C的memcached客戶端?,F在也是非常火的,基本是一個官方的C的客戶端。它其實有很多bug,我們在使用的時候發現,去修正它?,F在我們的團隊成員里面有直接就是它的開發成員。比如說像Python的Mako模板,也是用的人非常多的模板。我們也在使用,使用起來發現它的性能稍微弱一些,我們也花了精力對它進行了優化,這個優化現在也是被接受了,在Mako的后來版本發布出來了。然后豆瓣自己也有一些開源的項目,最主要的開源的項目是豆瓣API的訪問客戶端,這個是在google code上面,也有很多志愿者參與進來,幫我們一起修改。然后從另外一個方面來說,豆瓣和國內的開源社區也有緊密的聯系。豆瓣的上線通知就是發在開源組織CPUG的郵件列表里面的,豆瓣的很多成員也是CPUG的成員,會在郵件列表里面去幫助回答問題,討論問題,這也是一種回饋的方式。
豆瓣的開發團隊是怎么樣的?
我們現在開發團隊這邊是11個人,有全職有兼職,還是比較放松。我們采用的是敏捷的方法,但是也不是完全的一模一樣的方式。在豆瓣內部,我們盡可能地去發揮每個人的創造力。比如,在豆瓣作息是自由的,你可以自己決定什么時候來,什么時候走。比如你想在家里面靜下心來寫code,你可以往郵件列表里面發條消息說,我今天不過來了,就可以在家里面。每天會有很多的討論,我們在豆瓣的辦公室是一個獨立的區域。在這個區域里面有白板,大家可以隨時討論。然后每周我們會有一個技術交流會議,大家輪流來發表一下自己最近在看一些什么東西,有什么心得,跟大家分享一下,這些都促進團隊的溝通與發展的,很有用的東西。
看來豆瓣是一個相當開放、技術和興趣驅動的團隊。
我們希望一直保持這樣的樣子。
那現場的觀眾有沒有什么問題?其他記者:我是接著社區那個話題問一下,豆瓣現在有了很多的積累,有很多東西都已經成形了,有沒有考慮說開放一些項目?
我們是有這個計劃的。比如說DoubanDB,實際上我們在創立這個項目的時候,就是說這個項目我們做出來后是要開源的,到現在還沒開源,是因為這個項目還在變化之中。由于開發的時間上的限制,所以現在還和豆瓣本身的數據綁得太緊,我們而且也是在不斷地調整,現在還在調整的過程當中。找一個合適時機,我們會把它跟的豆瓣的數據剝離出來,成為一個可以獨立地去安裝、運行的應用的時候,就會把它拿出來,我想應該很快就能夠做到這點。
非常感謝強寧接受我們的采訪,也恭喜今天在大會的演講上面取得了非常圓滿的成功。
謝謝。
原文鏈接和視頻地址:http://www.infoq.com/cn/interviews/douban-hqn
- 目前還沒評論,等你發揮!