從LiveJournal後臺發展看大規模網站性能優化方法

從LiveJournal後臺發展看大規模網站性能優化方法

於敦德 2006-3-16

一、LiveJournal發展歷程

LiveJournal是99年始於校園中的項目,幾個人出於愛好做了這樣一個應用,以實現以下功能:
  • 博客,論壇
  • 社會性網絡,找到朋友
  • 聚合,把朋友的文章聚合在一起
LiveJournal採用了大量的開源軟件,甚至它本身也是一個開源軟件。

在上線後,LiveJournal實現了非常快速的增長:

  • 2004年4月份:280萬註冊用戶。
  • 2005年4月份:680萬註冊用戶。
  • 2005年8月份:790萬註冊用戶。
  • 達到了每秒鐘上千次的頁面請求及處理。
  • 使用了大量MySQL服務器。
  • 使用了大量通用組件。

二、LiveJournal架構現狀概況

livejournal_backend.png

三、從LiveJournal發展中學習

LiveJournal從1臺服務器發展到100臺服務器,這其中經歷了無數的傷痛,但同時也摸索出瞭解決這些問題的方法,通過對LiveJournal的學習,可以讓我們避免LJ曾經犯過的錯誤,並且從一開始就對系統進行良好的設計,以避免後期的痛苦。

下面我們一步一步看LJ發展的腳步。

1、一臺服務器

一臺別人捐助的服務器,LJ最初就跑在上面,就像Google開始時候用的破服務器一樣,值得我們尊敬。這個階段,LJ的人以驚人的速度熟悉的 Unix的操作管理,服務器性能出現過問題,不過還好,可以通過一些小修小改應付過去。在這個階段裏LJ把CGI升級到了FastCGI。

最終問題出現了,網站越來越慢,已經無法通過優過化來解決的地步,需要更多的服務器,這時LJ開始提供付費服務,可能是想通過這些錢來購買新的服務器,以解決當時的困境。
毫無疑問,當時LJ存在巨大的單點問題,所有的東西都在那臺服務器的鐵皮盒子裏裝着。

LJ-backend-7.png

2、兩臺服務器

用付費服務賺來的錢LJ買了兩臺服務器:一臺叫做Kenny的Dell 6U機器用於提供Web服務,一臺叫做Cartman的Dell 6U服務器用於提供數據庫服務。

LJ-backend-8.png

LJ有了更大的磁盤,更多的計算資源。但同時網絡結構還是非常簡單,每臺機器兩塊網卡,Cartman通過內網爲Kenny提供MySQL數據庫服務。

暫時解決了負載的問題,新的問題又出現了:

  • 原來的一個單點變成了兩個單點。
  • 沒有冷備份或熱備份。
  • 網站速度慢的問題又開始出現了,沒辦法,增長太快了。
  • Web服務器上CPU達到上限,需要更多的Web服務器。

3、四臺服務器

又買了兩臺,Kyle和Stan,這次都是1U的,都用於提供Web服務。目前LJ一共有3臺Web服務器和一臺數據庫服務器。這時需要在3臺Web服務器上進行負載均橫。

LJ-backend-9.png

LJ把Kenny用於外部的網關,使用mod_backhand進行負載均橫。

然後問題又出現了:

  • 單點故障。數據庫和用於做網關的Web服務器都是單點,一旦任何一臺機器出現問題將導致所有服務不可用。雖然用於做網關的Web服務器可以通過保持心跳同步迅速切換,但還是無法解決數據庫的單點,LJ當時也沒做這個。
  • 網站又變慢了,這次是因爲IO和數據庫的問題,問題是怎麼往應用裏面添加數據庫呢?

4、五臺服務器

又買了一臺數據庫服務器。在兩臺數據庫服務器上使用了數據庫同步(Mysql支持的Master-Slave模式),寫操作全部針對主數據庫(通過Binlog,主服務器上的寫操作可以迅速同步到從服務器上),讀操作在兩個數據庫上同時進行(也算是負載均橫的一種吧)。

LJ-backend-10.png

實現同步時要注意幾個事項:

  • 讀操作數據庫選擇算法處理,要選一個當前負載輕一點的數據庫。
  • 在從數據庫服務器上只能進行讀操作
  • 準備好應對同步過程中的延遲,處理不好可能會導致數據庫同步的中斷。只需要對寫操作進行判斷即可,讀操作不存在同步問題。

5、更多服務器

有錢了,當然要多買些服務器。部署後快了沒多久,又開始慢了。這次有更多的Web服務器,更多的數據庫服務器,存在 IO與CPU爭用。於是採用了BIG-IP作爲負載均衡解決方案。

LJ-backend-11.png

6、現在我們在哪裏:

LJ-backend-1.png

現在服務器基本上夠了,但性能還是有問題,原因出在架構上。

數據庫的架構是最大的問題。由於增加的數據庫都是以Slave模式添加到應用內,這樣唯一的好處就是將讀操作分佈到了多臺機器,但這樣帶來的後果就是寫操作被大量分發,每臺機器都要執行,服務器越多,浪費就越大,隨着寫操作的增加,用於服務讀操作的資源越來越少。

LJ-backend-2.png

由一臺分佈到兩臺

LJ-backend-3.png

最終效果

現在我們發現,我們並不需要把這些數據在如此多的服務器上都保留一份。服務器上已經做了RAID,數據庫也進行了備份,這麼多的備份完全是對資源的浪費,屬於冗餘極端過度。那爲什麼不把數據分佈存儲呢?

問題發現了,開始考慮如何解決。現在要做的就是把不同用戶的數據分佈到不同的服務器上進行存儲,以實現數據的分佈式存儲,讓每臺機器只爲相對固定的用戶服務,以實現平行的架構和良好的可擴展性。

爲了實現用戶分組,我們需要爲每一個用戶分配一個組標記,用於標記此用戶的數據存放在哪一組數據庫服務器中。每組數據庫由一個master及幾個 slave組成,並且slave的數量在2-3臺,以實現系統資源的最合理分配,既保證數據讀操作分佈,又避免數據過度冗餘以及同步操作對系統資源的過度 消耗。

LJ-backend-4.png

由一臺(一組)中心服務器提供用戶分組控制。所有用戶的分組信息都存儲在這臺機器上,所有針對用戶的操作需要先查詢這臺機器得到用戶的組號,然後再到相應的數據庫組中獲取數據。

這樣的用戶架構與目前LJ的架構已經很相像了。

在具體的實現時需要注意幾個問題:

  • 在數據庫組內不要使用自增ID,以便於以後在數據庫組之間遷移用戶,以實現更合理的I/O,磁盤空間及負載分佈。
  • 將userid,postid存儲在全局服務器上,可以使用自增,數據庫組中的相應值必須以全局服務器上的值爲準。全局服務器上使用事務型數據庫InnoDB。
  • 在數據庫組之間遷移用戶時要萬分小心,當遷移時用戶不能有寫操作。

7、現在我們在哪裏

LJ-backend-5.png

問題:

  • 一個全局主服務器,掛掉的話所有用戶註冊及寫操作就掛掉。
  • 每個數據庫組一個主服務器,掛掉的話這組用戶的寫操作就掛掉。
  • 數據庫組從服務器掛掉的話會導致其它服務器負載過大。

對於Master-Slave模式的單點問題,LJ採取了Master-Master模式來解決。所謂Master-Master實際上是人工實現的,並不是由MySQL直接提供的,實際上也就是兩臺機器同時是Master,也同時是Slave,互相同步。

Master-Master實現時需要注意:

  • 一個Master出錯後恢復同步,最好由服務器自動完成。
  • 數字分配,由於同時在兩臺機器上寫,有些ID可能會衝突。

解決方案:

  • 奇偶數分配ID,一臺機器上寫奇數,一臺機器上寫偶數
  • 通過全局服務器進行分配(LJ採用的做法)。

Master-Master模式還有一種用法,這種方法與前一種相比,仍然保持兩臺機器的同步,但只有一臺機器提供服務(讀和寫),在每天晚上的時候進行輪換,或者出現問題的時候進行切換。

8、現在我們在哪裏

LJ-backend-6.png

現在插播一條廣告,MyISAM VS InnoDB。

使用InnoDB:

  • 支持事務
  • 需要做更多的配置,不過值得,可以更安全的存儲數據,以及得到更快的速度。

使用MyISAM:

  • 記錄日誌(LJ用它來記網絡訪問日誌)
  • 存儲只讀靜態數據,足夠快。
  • 併發性很差,無法同時讀寫數據(添加數據可以)
  • MySQL非正常關閉或死機時會導致索引錯誤,需要使用myisamchk修復,而且當訪問量大時出現非常頻繁。

9、緩存

去年我寫過一篇文章介紹memcached,它就是由LJ的團隊開發的一款緩存工具,以key-value的方式將數據存儲到分佈的內存中。LJ緩存的數據:

  • 12臺獨立服務器(不是捐贈的)
  • 28個實例
  • 30GB總容量
  • 90-93%的命中率(用過squid的人可能知道,squid內存加磁盤的命中率大概在70-80%)

如何建立緩存策略?

想緩存所有的東西?那是不可能的,我們只需要緩存已經或者可能導致系統瓶頸的地方,最大程度的提交系統運行效率。通過對MySQL的日誌的分析我們可以找到緩存的對象。

緩存的缺點?

  • 沒有完美的事物,緩存也有缺點:
  • 增大開發量,需要針對緩存處理編寫特殊的代碼。
  • 管理難度增加,需要更多人蔘與系統維護。
  • 當然大內存也需要錢。

10、Web訪問負載均衡

在數據包級別使用BIG-IP,但BIG-IP並不知道我們內部的處理機制,無法判斷由哪臺服務器對這些請求進行處理。反向代理並不能很好的起到作用,不是已經夠快了,就是達不到我們想要的效果。

所以,LJ又開發了Perlbal。特點:

  • 快,小,可管理的http web 服務器/代理
  • 可以在內部進行轉發
  • 使用Perl開發
  • 單線程,異步,基於事件,使用epoll , kqueue
  • 支持Console管理與http遠程管理,支持動態配置加載
  • 多種模式:web服務器,反向代理,插件
  • 支持插件:GIF/PNG互換?

11、MogileFS

LJ使用開源的MogileFS作爲分佈式文件存儲系統。MogileFS使用非常簡單,它的主要設計思想是:

  • 文件屬於類(類是最小的複製單位)
  • 跟蹤文件存儲位置
  • 在不同主機上存儲
  • 使用MySQL集羣統一存儲分佈信息
  • 大容易廉價磁盤

到目前爲止就這麼多了,更多文檔可以在http://www.danga.com/words/找到。Danga.comLiveJournal.com的 同學們拿這個文檔參加了兩次MySQL Con,兩次OS Con,以及衆多的其它會議,無私的把他們的經驗分享出來,值得我們學習。在web2.0時代快速開發得到大家越來越多的重視,但良好的設計仍是每一個應 用的基礎,希望web2.0們在成長爲Top500網站的路上,不要因爲架構阻礙了網站的發展。

參考資料:http://www.danga.com/words/2005_oscon/oscon-2005.pdf

感謝向靜推薦了這篇文檔給我。

 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章