天天看點

大型Web2.0站點建構技術初探(二)

大型Web2.0站點建構技術初探(二)

5. 裡程碑五:2千6百萬賬戶

2005年中期,服務賬戶數達到2千6百萬時,MySpace切換到了還處于beta測試的SQL Server 2005。轉換何太急?主流看法是2005版支援64位處理器。但Benedetto說,"這不是主要原因,盡管這也很重要;主要還是因為我們對記憶體的渴求。"支援64位的資料庫可以管理更多記憶體。

  更多記憶體就意味着更高的性能和更大的容量。原來運作32位版本的SQL Server伺服器,能同時使用的記憶體最多隻有4G。切換到64位,就好像加粗了輸水管的直徑。更新到SQL Server 2005和64位Windows Server 2003後,MySpace每台伺服器配備了32G記憶體,後于2006年再次将配置标準提升到64G。

  意外錯誤

  如果沒有對系統架構的曆次修改與更新,MySpace根本不可能走到今天。但是,為什麼系統還經常吃撐着了?很多使用者抱怨的"意外錯誤"是怎麼引起的呢?

  原因之一是MySpace對Microsoft的Web技術的應用已經進入連Microsoft自己也才剛剛開始探索的領域。比如11月,超出SQL Server最大同時連接配接數,MySpace系統崩潰。Benedetto說,這類可能引發系統崩潰的情況大概三天才會出現一次,但仍然過于頻繁了,以緻惹人惱怒。一旦資料庫罷工,"無論這種情況什麼時候發生,未緩存的資料都不能從SQL Server獲得,那麼你就必然看到一個'意外錯誤'提示。"他解釋說。

  去年夏天,MySpace的Windows 2003多次自動停止服務。後來發現是作業系統一個内置功能惹的禍--預防分布式拒絕服務攻擊(黑客使用很多客戶機向伺服器發起大量連接配接請求,以緻伺服器癱瘓)。MySpace和其他很多頂級大站點一樣,肯定會經常遭受攻擊,但它應該從網絡級而不是依靠Windows本身的功能來解決問題--否則,大量MySpace合法使用者連接配接時也會引起伺服器反擊。

"我們花了大約一個月時間尋找Windows 2003伺服器自動停止的原因。"Benedetto說。最後,通過Microsoft的幫助,他們才知道該怎麼通知伺服器:"别開槍,是友軍。"

  緊接着是在去年7月某個周日晚上,MySpace總部所在地洛杉矶停電,造成整個系統停運12小時。大型Web站點通常要在地理上分布配置多個資料中心以預防單點故障。本來,MySpace還有其他兩個資料中心以應對突發事件,但Web伺服器都依賴于部署在洛杉矶的SAN。沒有洛杉矶的SAN,Web伺服器除了懇求你耐心等待,不能提供任何服務。

Benedetto說,主資料中心的可靠性通過下列措施保證:可接入兩張不同電網,另有後備電源和一台儲備有30天燃料的發電機。但在這次事故中,不僅兩張電網失效,而且在切換到備份電源的過程中,操作員燒掉了主動力線路。

2007年中,MySpace在另兩個後備站點上也建設了SAN。這對分擔負荷大有幫助--正常情況下,每個SAN都能負擔三分之一的資料通路量。而在緊急情況下,任何一個站點都可以獨立支撐整個服務,Benedetto說。

MySpace仍然在為提高穩定性奮鬥,雖然很多使用者表示了足夠信任且能原諒偶現的錯誤頁面。

"作為開發人員,我憎惡Bug,它太氣人了。"Dan Tanner這個31歲的德克薩斯軟體工程師說,他通過MySpace重新聯系到了高中和大學同學。"不過,MySpace對我們的用處很大,是以我們可以原諒偶發的故障和錯誤。" Tanner說,如果站點某天出現故障甚至崩潰,恢複以後他還是會繼續使用。

  這就是為什麼Drew在論壇裡咆哮時,大部分使用者都告訴他應該保持平靜,如果等幾分鐘,問題就會解決的原因。Drew無法平靜,他寫道,"我已經兩次給MySpace發郵件,而它說一小時前還是正常的,現在出了點問題……完全是一堆廢話。"另一個使用者回複說,"畢竟它是免費的。"Benedetto坦承100%的可靠性不是他的目标。"它不是銀行,而是一個免費的服務。"他說。

  換句話說,MySpace的偶發故障可能造成某人最後更新的個人資料丢失,但并不意味着網站弄丢了使用者的錢财。"關鍵是要認識到,與保證站點性能相比,丢失少許資料的故障是可接受的。"Benedetto說。是以,MySpace甘冒丢失2分鐘到2小時内任意點資料的危險,在SQL Server配置裡延長了"checkpoint"操作--它将待更新資料永久記錄到磁盤--的間隔時間,因為這樣做可以加快資料庫的運作。

Benedetto說,同樣,開發人員還經常在幾個小時内就完成構思、編碼、測試和釋出全過程。這有引入Bug的風險,但這樣做可以更快實作新功能。而且,因為進行大規模真實測試不具可行性,他們的測試通常是在僅以部分活躍使用者為對象,且使用者對軟體新功能和改進不知就裡的情況下進行的。因為事實上不可能做真實的加載測試,他們做的測試通常都是針對站點。

"我們犯過大量錯誤,"Benedetto說,"但到頭來,我認為我們做對的還是比做錯的多。"

七、 從LiveJournal背景發展看大規模網站性能優化方法

LiveJournal是99年始于校園中的項目,幾個人出于愛好做了這樣一個應用,以實作以下功能:
  • 部落格,論壇
  • 社會性網絡,找到朋友
  • 聚合,把朋友的文章聚合在一起

LiveJournal采用了大量的開源軟體,甚至它本身也是一個開源軟體。

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

  • 2004年4月份:280萬注冊使用者。
  • 2005年4月份:680萬注冊使用者。
  • 2005年8月份:790萬注冊使用者。
  • 達到了每秒鐘上千次的頁面請求及處理。
  • 使用了大量MySQL伺服器。
  • 使用了大量通用元件。
二、LiveJournal架構現狀概況

三、從LiveJournal發展中學習

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

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

1、一台伺服器

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

最終問題出現了,網站越來越慢,已經無法通過優過化來解決的地步,需要更多的伺服器,這時LJ開始提供付費服務,可能是想通過這些錢來購買新的伺服器,以解決當時的困境。

毫無疑問,當時LJ存在巨大的單點問題,所有的東西都在那台伺服器的鐵皮盒子裡裝着

2、兩台伺服器

用付費服務賺來的錢LJ買了兩台伺服器:一台叫做Kenny的Dell 6U機器用于提供Web服務,一台叫做Cartman的Dell 6U伺服器用于提供資料庫服務。

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

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

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

3、四台伺服器

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

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

然後問題又出現了:

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

4、五台伺服器

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

實作同步時要注意幾個事項:
  • 讀操作資料庫選擇算法處理,要選一個目前負載輕一點的資料庫。
  • 在從資料庫伺服器上隻能進行讀操作
  • 準備好應對同步過程中的延遲,處理不好可能會導緻資料庫同步的中斷。隻需要對寫操作進行判斷即可,讀操作不存在同步問題。

5、更多伺服器

有錢了,當然要多買些伺服器。部署後快了沒多久,又開始慢了。這次有更多的Web伺服器,更多的資料庫伺服器,存在 IO與CPU争用。于是采用了BIG-IP作為負載均衡解決方案。

6、現在我們在哪裡:

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

資料庫的架構是最大的問題。由于增加的資料庫都是以Slave模式添加到應用内,這樣唯一的好處就是将讀操作分布到了多台機器,但這樣帶來的後果就是寫操作被大量分發,每台機器都要執行,伺服器越多,浪費就越大,随着寫操作的增加,用于服務讀操作的資源越來越少。

由一台分布到兩台

最終效果

現在我們發現,我們并不需要把這些資料在如此多的伺服器上都保留一份。伺服器上已經做了RAID,資料庫也進行了備份,這麼多的備份完全是對資源的浪費,屬于備援極端過度。那為什麼不把資料分布存儲呢?

問題發現了,開始考慮如何解決。現在要做的就是把不同使用者的資料分布到不同的伺服器上進行存儲,以實作資料的分布式存儲,讓每台機器隻為相對固定的使用者服務,以實作平行的架構和良好的可擴充性。

為了實作使用者分組,我們需要為每一個使用者配置設定一個組标記,用于标記此使用者的資料存放在哪一組資料庫伺服器中。每組資料庫由一個master及幾個slave組成,并且slave的數量在2-3台,以實作系統資源的最合理配置設定,既保證資料讀操作分布,又避免資料過度備援以及同步操作對系統資源的過度消耗。

由一台(一組)中心伺服器提供使用者分組控制。所有使用者的分組資訊都存儲在這台機器上,所有針對使用者的操作需要先查詢這台機器得到使用者的組号,然後再到相應的資料庫組中擷取資料。

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

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

  • 在資料庫組内不要使用自增ID,以便于以後在資料庫組之間遷移使用者,以實作更合理的I/O,磁盤空間及負載分布。
  • 将userid,postid存儲在全局伺服器上,可以使用自增,資料庫組中的相應值必須以全局伺服器上的值為準。全局伺服器上使用事務型資料庫InnoDB。
  • 在資料庫組之間遷移使用者時要萬分小心,當遷移時使用者不能有寫操作。
7、現在我們在哪裡 問題:
  • 一個全局主伺服器,挂掉的話所有使用者注冊及寫操作就挂掉。
  • 每個資料庫組一個主伺服器,挂掉的話這組使用者的寫操作就挂掉。
  • 資料庫組從伺服器挂掉的話會導緻其它伺服器負載過大。

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

Master-Master實作時需要注意:

  • 一個Master出錯後恢複同步,最好由伺服器自動完成。
  • 數字配置設定,由于同時在兩台機器上寫,有些ID可能會沖突。
解決方案:
  • 奇偶數配置設定ID,一台機器上寫奇數,一台機器上寫偶數
  • 通過全局伺服器進行配置設定(LJ采用的做法)。

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

8、現在我們在哪裡

現在插播一條廣告,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.com和LiveJournal.com的同學們拿這個文檔參加了兩次MySQL Con,兩次OS Con,以及衆多的其它會議,無私的把他們的經驗分享出來,值得我們學習。在web2.0時代快速開發得到大家越來越多的重視,但良好的設計仍是每一個應用的基礎,希望web2.0們在成長為Top500網站的路上,不要因為架構阻礙了網站的發展。

八、 說說大型高并發高負載網站的系統架構

我在Cernet做過撥号接入平台的搭建,而後在Yahoo3721負載搜尋引擎前端平台開發,又在貓撲處理過大型社群貓撲大雜燴的架構更新等工作,同時自己接觸和開發過不少大中型網站的子產品,是以在大型網站應對高負載和并發的解決方案上有一些積累和經驗,可以和大家一起探讨一下。

一個小型的網站,比如個人網站,可以使用最簡單的html靜态頁面就實作了,配合一些圖檔達到美化效果,所有的頁面均存放在一個目錄下,這樣的網站對系統架構、性能的要求都很簡單,随着網際網路業務的不斷豐富,網站相關的技術經過這些年的發展,已經細分到很細的方方面面,尤其對于大型網站來說,所采用的技術更是涉及面非常廣,從硬體到軟體、程式設計語言、資料庫、WebServer、防火牆等各個領域都有了很高的要求,已經不是原來簡單的html靜态網站所能比拟的。

大型網站,比如門戶網站。在面對大量使用者通路、高并發請求方面,基本的解決方案集中在這樣幾個環節:使用高性能的伺服器、高性能的資料庫、高效率的程式設計語言、還有高性能的Web容器。但是除了這幾個方面,還沒法根本解決大型網站面臨的高負載和高并發問題。

上面提供的幾個解決思路在一定程度上也意味着更大的投入,并且這樣的解決思路具備瓶頸,沒有很好的擴充性,下面我從低成本、高性能和高擴張性的角度來說說我的一些經驗。

1、HTML靜态化

其實大家都知道,效率最高、消耗最小的就是純靜态化的html頁面,是以我們盡可能使我們的網站上的頁面采用靜态頁面來實作,這個最簡單的方法其實也是最有效的方法。但是對于大量内容并且頻繁更新的網站,我們無法全部手動去挨個實作,于是出現了我們常見的資訊釋出系統CMS,像我們常通路的各個門戶站點的新聞頻道,甚至他們的其他頻道,都是通過資訊釋出系統來管理和實作的,資訊釋出系統可以實作最簡單的資訊錄入自動生成靜态頁面,還能具備頻道管理、權限管理、自動抓取等功能,對于一個大型網站來說,擁有一套高效、可管理的CMS是必不可少的。

除了門戶和資訊釋出類型的網站,對于互動性要求很高的社群類型網站來說,盡可能的靜态化也是提高性能的必要手段,将社群内的文章、文章進行實時的靜态化,有更新的時候再重新靜态化也是大量使用的政策,像Mop的大雜燴就是使用了這樣的政策,網易社群等也是如此。

同時,html靜态化也是某些緩存政策使用的手段,對于系統中頻繁使用資料庫查詢但是内容更新很小的應用,可以考慮使用html靜态化來實作,比如論壇中論壇的公用設定資訊,這些資訊目前的主流論壇都可以進行背景管理并且存儲再資料庫中,這些資訊其實大量被前台程式調用,但是更新頻率很小,可以考慮将這部分内容進行背景更新的時候進行靜态化,這樣避免了大量的資料庫通路請求。

2、圖檔伺服器分離

大家知道,對于Web伺服器來說,不管是Apache、IIS還是其他容器,圖檔是最消耗資源的,于是我們有必要将圖檔與頁面進行分離,這是基本上大型網站都會采用的政策,他們都有獨立的圖檔伺服器,甚至很多台圖檔伺服器。這樣的架構可以降低提供頁面通路請求的伺服器系統壓力,并且可以保證系統不會因為圖檔問題而崩潰,在應用伺服器和圖檔伺服器上,可以進行不同的配置優化,比如apache在配置ContentType的時候可以盡量少支援,盡可能少的LoadModule,保證更高的系統消耗和執行效率。

3、資料庫叢集和庫表散列

大型網站都有複雜的應用,這些應用必須使用資料庫,那麼在面對大量通路的時候,資料庫的瓶頸很快就能顯現出來,這時一台資料庫将很快無法滿足應用,于是我們需要使用資料庫叢集或者庫表散列。

在資料庫叢集方面,很多資料庫都有自己的解決方案,Oracle、Sybase等都有很好的方案,常用的MySQL提供的Master/Slave也是類似的方案,您使用了什麼樣的DB,就參考相應的解決方案來實施即可。

上面提到的資料庫叢集由于在架構、成本、擴張性方面都會受到所采用DB類型的限制,于是我們需要從應用程式的角度來考慮改善系統架構,庫表散列是常用并且最有效的解決方案。我們在應用程式中安裝業務和應用或者功能子產品将資料庫進行分離,不同的子產品對應不同的資料庫或者表,再按照一定的政策對某個頁面或者功能進行更小的資料庫散列,比如使用者表,按照使用者ID進行表散列,這樣就能夠低成本的提升系統的性能并且有很好的擴充性。sohu的論壇就是采用了這樣的架構,将論壇的使用者、設定、文章等資訊進行資料庫分離,然後對文章、使用者按照闆塊和ID進行散列資料庫和表,最終可以在配置檔案中進行簡單的配置便能讓系統随時增加一台低成本的資料庫進來補充系統性能。

4、緩存

緩存一詞搞技術的都接觸過,很多地方用到緩存。網站架構和網站開發中的緩存也是非常重要。這裡先講述最基本的兩種緩存。進階和分布式的緩存在後面講述。

架構方面的緩存,對Apache比較熟悉的人都能知道Apache提供了自己的緩存子產品,也可以使用外加的Squid子產品進行緩存,這兩種方式均可以有效的提高Apache的通路響應能力。

網站程式開發方面的緩存,Linux上提供的Memory Cache是常用的緩存接口,可以在web開發中使用,比如用Java開發的時候就可以調用MemoryCache對一些資料進行緩存和通訊共享,一些大型社群使用了這樣的架構。另外,在使用web語言開發的時候,各種語言基本都有自己的緩存子產品和方法,PHP有Pear的Cache子產品,Java就更多了,.net不是很熟悉,相信也肯定有。

5、鏡像

鏡像是大型網站常采用的提高性能和資料安全性的方式,鏡像的技術可以解決不同網絡接入商和地域帶來的使用者通路速度差異,比如ChinaNet和EduNet之間的差異就促使了很多網站在教育網内搭建鏡像站點,資料進行定時更新或者實時更新。在鏡像的細節技術方面,這裡不闡述太深,有很多專業的現成的解決架構和産品可選。也有廉價的通過軟體實作的思路,比如Linux上的rsync等工具。

6、負載均衡

負載均衡将是大型網站解決高負荷通路和大量并發請求采用的終極解決辦法。

負載均衡技術發展了多年,有很多專業的服務提供商和産品可以選擇,我個人接觸過一些解決方法,其中有兩個架構可以給大家做參考。

  • 硬體四層交換

第四層交換使用第三層和第四層資訊包的報頭資訊,根據應用區間識别業務流,将整個區間段的業務流配置設定到合适的應用伺服器進行處理。 第四層交換功能就象是虛IP,指向實體伺服器。它傳輸的業務服從的協定多種多樣,有HTTP、FTP、NFS、Telnet或其他協定。這些業務在實體伺服器基礎上,需要複雜的載量平衡算法。在IP世界,業務類型由終端TCP或UDP端口位址來決定,在第四層交換中的應用區間則由源端和終端IP位址、TCP和UDP端口共同決定。

在硬體四層交換産品領域,有一些知名的産品可以選擇,比如Alteon、F5等,這些産品很昂貴,但是物有所值,能夠提供非常優秀的性能和很靈活的管理能力。Yahoo中國當初接近2000台伺服器使用了三四台Alteon就搞定了。

  • 軟體四層交換

大家知道了硬體四層交換機的原理後,基于OSI模型來實作的軟體四層交換也就應運而生,這樣的解決方案實作的原理一緻,不過性能稍差。但是滿足一定量的壓力還是遊刃有餘的,有人說軟體實作方式其實更靈活,處理能力完全看你配置的熟悉能力。

軟體四層交換我們可以使用Linux上常用的LVS來解決,LVS就是Linux Virtual Server,他提供了基于心跳線heartbeat的實時災難應對解決方案,提高系統的魯棒性,同時可供了靈活的虛拟VIP配置和管理功能,可以同時滿足多種應用需求,這對于分布式的系統來說必不可少。

一個典型的使用負載均衡的政策就是,在軟體或者硬體四層交換的基礎上搭建squid叢集,這種思路在很多大型網站包括搜尋引擎上被采用,這樣的架構低成本、高性能還有很強的擴張性,随時往架構裡面增減節點都非常容易。這樣的架構我準備空了專門詳細整理一下和大家探讨。

對于大型網站來說,前面提到的每個方法可能都會被同時使用到,我這裡介紹得比較淺顯,具體實作過程中很多細節還需要大家慢慢熟悉和體會,有時一個很小的squid參數或者apache參數設定,對于系統性能的影響就會很大,希望大家一起讨論,達到抛磚引玉之效。