淺談大型Web系統架構


動態應用,是相對於網站靜態內容而言,是指以c/c++、php、Java、perl、.net等服務器端語言開發的網絡應用軟件,比如論壇、網絡相冊、交友、BLOG等常見應用。動態應用系統通常與數據庫系統、緩存系統、分布式存儲系統等密不可分。

大型動態應用系統平台主要是針對於大流量、高並發網站建立的底層系統架構。大型網站的運行需要一個可靠、安全、可擴展、易維護的應用系統平台做為支撐,以保證網站應用的平穩運行。

大型動態應用系統又可分為幾個子系統:

1)Web前端系統

2)負載均衡系統

3)數據庫集群系統

4)緩存系統

5)分布式存儲系統

6)分布式服務器管理系統

7)代碼分發系統

Web前端系統

結構圖:

為了達到不同應用的服務器共享、避免單點故障、集中管理、統一配置等目的,不以應用划分服務器,而是將所有服務器做統一使用,每台服務器都可以對多個應用提供服務,當某些應用訪問量升高時,通過增加服務器節點達到整個服務器集群的性能提高,同時使他應用也會受益。該Web前端系統基於Apache/Lighttpd/Eginx等的虛擬主機平台,提供PHP程序運行環境。服務器對開發人員是透明的,不需要開發人員介入服務器管理

負載均衡系統

負載均衡系統分為硬件和軟件兩種。硬件負載均衡效率高,但是價格貴,比如F5等。軟件負載均衡系統價格較低或者免費,效率較硬件負載均衡系統低,不過對於流量一般或稍大些網站來講也足夠使用,比如lvs, nginx。大多數網站都是硬件、軟件負載均衡系統並用。

數據庫集群系統

結構圖:

由於Web前端采用了負載均衡集群結構提高了服務的有效性和擴展性,因此數據庫必須也是高可靠的,才能保證整個服務體系的高可靠性,如何構建一個高可靠的、可以提供大規模並發處理的數據庫體系?

我們可以采用如上圖所示的方案:

1) 使用 MySQL 數據庫,考慮到Web應用的數據庫讀多寫少的特點,我們主要對讀數據庫做了優化,提供專用的讀數據庫和寫數據庫,在應用程序中實現讀操作和寫操作分別訪問不同的數據庫。

2) 使用 MySQL Replication 機制實現快速將主庫(寫庫)的數據庫復制到從庫(讀庫)。一個主庫對應多個從庫,主庫數據實時同步到從庫。

3) 寫數據庫有多台,每台都可以提供多個應用共同使用,這樣可以解決寫庫的性能瓶頸問題和單點故障問題。

4) 讀數據庫有多台,通過負載均衡設備實現負載均衡,從而達到讀數據庫的高性能、高可靠和高可擴展性。

5) 數據庫服務器和應用服務器分離。

6) 從數據庫使用BigIP做負載均衡。

緩存系統

緩存分為文件緩存、內存緩存、數據庫緩存。在大型Web應用中使用最多且效率最高的是內存緩存。最常用的內存緩存工具是Memcached。使用正確的緩存系統可以達到實現以下目標:

1、使用緩存系統可以提高訪問效率,提高服務器吞吐能力,改善用戶體驗。

2、減輕對數據庫及存儲集服務器的訪問壓力。

3、Memcached服務器有多台,避免單點故障,提供高可靠性和可擴展性,提高性能。

分布式存儲系統

結構圖:

Web系統平台中的存儲需求有下面兩個特點:

1) 存儲量很大,經常會達到單台服務器無法提供的規模,比如相冊、視頻等應用。因此需要專業的大規模存儲系統。

2) 負載均衡cluster中的每個節點都有可能訪問任何一個數據對象,每個節點對數據的處理也能被其他節點共享,因此這些節點要操作的數據從邏輯上看只能是一個整體,不是各自獨立的數據資源。

因此高性能的分布式存儲系統對於大型網站應用來說是非常重要的一環。(這個地方需要加入對某個分布式存儲系統的簡單介紹。)

分布式服務器管理系統

結構圖:

隨着網站訪問流量的不斷增加,大多的網絡服務都是以負載均衡集群的方式對外提供服務,隨之集群規模的擴大,原來基於單機的服務器管理模式已經不能夠滿足我們的需求,新的需求必須能夠集中式的、分組的、批量的、自動化的對服務器進行管理,能夠批量化的執行計划任務。

在分布式服務器管理系統軟件中有一些比較優秀的軟件,其中比較理想的一個是Cfengine。它可以對服務器進行分組,不同的分組可以分別定制系統配置文件、計划任務等配置。它是基於C/S 結構的,所有的服務器配置和管理腳本程序都保存在Cfengine Server上,而被管理的服務器運行着 Cfengine Client 程序,Cfengine Client通過SSL加密的連接定期的向服務器端發送請求以獲取最新的配置文件和管理命令、腳本程序、補丁安裝等任務。

有了Cfengine這種集中式的服務器管理工具,我們就可以高效的實現大規模的服務器集群管理,被管理服務器和 Cfengine Server 可以分布在任何位置,只要網絡可以連通就能實現快速自動化的管理。

代碼發布系統

結構圖:

隨着網站訪問流量的不斷增加,大多的網絡服務都是以負載均衡集群的方式對外提供服務,隨之集群規模的擴大,為了滿足集群環境下程序代碼的批量分發和更新,我們還需要一個程序代碼發布系統。

這個發布系統可以幫我們實現下面的目標:

1) 生產環境的服務器以虛擬主機方式提供服務,不需要開發人員介入維護和直接操作,提供發布系統可以實現不需要登陸服務器就能把程序分發到目標服務器。

2) 我們要實現內部開發、內部測試、生產環境測試、生產環境發布的4個開發階段的管理,發布系統可以介入各個階段的代碼發布。

3) 我們需要實現源代碼管理和版本控制,SVN可以實現該需求。

這里面可以使用常用的工具Rsync,通過開發相應的腳本工具實現服務器集群間代碼同步分發。

 

    • 1、Web層
    • 主體架構可以基於 Struts 1.X/2.X,當然有很多更好的控制層框架供選擇,以快速敏捷為准則吧。 
      抽象出核心庫封裝 控制器和中間層的操作。 
      在大規模集群環境下,session復制會引起嚴重的性能問題。考慮用 集群緩存 + cookie驗證 代替session實現權限控制吧。


      2、Cache層
      配置 Memcache 組成集群緩存 
      對 Memcache 客戶端進行封裝 
      Memcached 節點組成池,調用示意:opList (BizName, 策略 ...)

      3、中間層
      “中間層”可以理解為基於應用和數據之間的層次。它被設計用來為Web應用提供:數據緩存 和 對應用透明的數據訪問——即應用不需要考慮數據表拆分的問題。以服務的方式提供對存儲層的高性能調用以及分布式計算。可供選擇的框架:ICE 、Hadoop 直接基於Memcache開發(減少復雜度,推薦)


      4、存儲
      推薦MySQL,理由:免費,經過實踐檢驗,有大量成熟的案例、解決方案、技術支持。
      小規模:一個 data table 維護存儲服務器陣列,內容 -> mount …… 
      大規模:Master-Slave模式+MySQL Proxy,實現數據庫讀寫分離。在中間層的包裝下,可做如下擴展,以支持更大規模的數據存取: 
      數據庫/表水平拆分,例 User -> User33% + User33% + User34% 
      數據庫/表垂直拆分,例 User -> UserBaseInfo + UserAddrInfo 
      也可考慮使用 LongStore (龍存) 解決方案,由龍存管理存儲陣列……


      5、部署
      划分子域名,每個子域名一個Web應用包,互不干擾 
      靜態資源(css, js, image ...)使用專門的靜態服務器


      6、負載均衡
      小規模:DNS輪詢。
      大規模:F5, 2*X 台F5服務器,F5是L4/L7層交換機,每台至少可處理200萬連接(與服務器內存有關)。
      Ngnix是L7層交換,LVS負載均衡也是一種方案


      7、Web中間件選擇
      Tomcat - 最高400並發 
      Apache - 最高2000並發 
      Ngnix - 優於Apache 
      采用方案:Ngnix + Resin ,理由:
      Resin提供更為快速的servlet引擎 - 選擇Resin。 
      gzip問題 - Resin在單獨處理gzip時存在內存溢出的隱患,因此要加一層 Ngnix。 
      Ngnix 能減少單獨使用Resin時的內存占用 - Resin建立1000個連接使用1000個線程;加Ngnix后,透過其“異步連接”、“建立長連接”機制使Resin內存壓力大大減小。 
      Ngnix 針對Linux系統有性能優化措施 - 0 Copy, send file ... 
      因此采用:1 Ngnix + 1 Resin,一對一。
      靜態服務器采用:Squid + Apache, why? because Squid has cache ability ...


      新變化 - Nginx從0.7.48版本開始,支持了類似Squid的緩存功能。這個緩存是把URL及相關組合當作Key,用md5編碼哈希后保存在硬盤上,所以它可以支持任意URL鏈接,同時也支持 404/301/302 這樣的非200狀態碼。雖然目前官方的Nginx Web緩存服務只能為指定URL或狀態碼設置過期時間,不支持類似Squid的PURGE指令,手動清除指定緩存頁面,但是,通過一個第三方的Nginx 模塊,可以清除指定URL的緩存。


      Nginx的Web緩存服務主要由proxy_cache相關指令集和fastcgi_cache相關指令集構成,前者用於反向代理時,對后端內容源服務器進行緩存,后者主要用於對FastCGI的動態程序進行緩存。兩者的功能基本上一樣。
      最新的Nginx 0.8.31版本,proxy_cache和fastcgi_cache已經比較完善,加上第三方的ngx_cache_purge模塊(用於清除指定 URL的緩存),已經可以完全取代Squid。有的網站已經在生產環境使用了 Nginx 的 proxy_cache 緩存功能超過兩個月,十分穩定,速度不遜於 Squid。

 

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

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

1、HTML靜態化

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

除了門戶和信息發布類型的網站,對於交互性要求很高的社區類型網站來說,盡可能的靜態化也是提高性能的必要手段,將社區內的帖子、文章進行實時的靜態化,有更新的時候再重新靜態化也是大量使用的策略,像Mop的大雜燴就是使用了這樣的策略,網易社區等也是如此。目前很多博客也都實現了靜態化,我使用的這個Blog程序WordPress還沒有靜態化,所以如果面對高負載訪問,www.toplee.com一定不能承受 

同時,html靜態化也是某些緩存策略使用的手段,對於系統中頻繁使用數據庫查詢但是內容更新很小的應用,可以考慮使用html靜態化來實現,比如論壇中論壇的公用設置信息,這些信息目前的主流論壇都可以進行后台管理並且存儲再數據庫中,這些信息其實大量被前台程序調用,但是更新頻率很小,可以考慮將這部分內容進行后台更新的時候進行靜態化,這樣避免了大量的數據庫訪問請求。

在進行html靜態化的時候可以使用一種折中的方法,就是前端使用動態實現,在一定的策略下進行定時靜態化和定時判斷調用,這個能實現很多靈活性的操作,我開發的台球網站故人居(www.8zone.cn)就是使用了這樣的方法,我通過設定一些html靜態化的時間間隔來對動態網站內容進行緩存,達到分擔大部分的壓力到靜態頁面上,可以應用於中小型網站的架構上。故人居網站的地址:http://www.8zone.cn,順便提一下,有喜歡台球的朋友多多支持我這個免費網站:)

2、圖片服務器分離

大家知道,對於Web服務器來說,不管是Apache、IIS還是其他容器,圖片是最消耗資源的,於是我們有必要將圖片與頁面進行分離,這是基本上大型網站都會采用的策略,他們都有獨立的圖片服務器,甚至很多台圖片服務器。這樣的架構可以降低提供頁面訪問請求的服務器系統壓力,並且可以保證系統不會因為圖片問題而崩潰。

在應用服務器和圖片服務器上,可以進行不同的配置優化,比如Apache在配置ContentType的時候可以盡量少支持,盡可能少的LoadModule,保證更高的系統消耗和執行效率。

我的台球網站故人居8zone.cn也使用了圖片服務器架構上的分離,目前是僅僅是架構上分離,物理上沒有分離,由於沒有錢買更多的服務器:),大家可以看到故人居上的圖片連接都是類似img.9tmd.com或者img1.9tmd.com的URL。

另外,在處理靜態頁面或者圖片、js等訪問方面,可以考慮使用lighttpd代替Apache,它提供了更輕量級和更高效的處理能力。

3、數據庫集群和庫表散列
大型網站都有復雜的應用,這些應用必須使用數據庫,那么在面對大量訪問的時候,數據庫的瓶頸很快就能顯現出來,這時一台數據庫將很快無法滿足應用,於是我們需要使用數據庫集群或者庫表散列。

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

上面提到的數據庫集群由於在架構、成本、擴張性方面都會受到所采用DB類型的限制,於是我們需要從應用程序的角度來考慮改善系統架構,庫表散列是常用並且最有效的解決方案。我們在應用程序中安裝業務和應用或者功能模塊將數據庫進行分離,不同的模塊對應不同的數據庫或者表,再按照一定的策略對某個頁面或者功能進行更小的數據庫散列,比如用戶表,按照用戶ID進行表散列,這樣就能夠低成本的提升系統的性能並且有很好的擴展性。sohu的論壇就是采用了這樣的架構,將論壇的用戶、設置、帖子等信息進行數據庫分離,然后對帖子、用戶按照板塊和ID進行散列數據庫和表,最終可以在配置文件中進行簡單的配置便能讓系統隨時增加一台低成本的數據庫進來補充系統性能。

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

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

網站程序開發方面的緩存,Linux上提供的Memcached是常用的緩存方案,不少web編程語言都提供memcache訪問接口,php、perl、c和java都有,可以在web開發中使用,可以實時或者Cron的把數據、對象等內容進行緩存,策略非常靈活。一些大型社區使用了這樣的架構。

另外,在使用web語言開發的時候,各種語言基本都有自己的緩存模塊和方法,PHP有Pear的Cache模塊和eAccelerator加速和Cache模塊,還要知名的Apc、XCache(國人開發的,支持!)php緩存模塊,Java就更多了,.net不是很熟悉,相信也肯定有。

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

6、負載均衡
負載均衡將是大型網站解決高負荷訪問和大量並發請求采用的終極解決辦法。

負載均衡技術發展了多年,有很多專業的服務提供商和產品可以選擇,我個人接觸過一些解決方法,其中有兩個架構可以給大家做參考。另外有關初級的負載均衡DNS輪循和較專業的CDN架構就不多說了。

6.1 硬件四層交換
第四層交換使用第三層和第四層信息包的報頭信息,根據應用區間識別業務流,將整個區間段的業務流分配到合適的應用服務器進行處理。 第四層交換功能就象是虛IP,指向物理服務器。它傳輸的業務服從的協議多種多樣,有HTTP、FTP、NFS、Telnet或其他協議。這些業務在物理服務器基礎上,需要復雜的載量平衡算法。在IP世界,業務類型由終端TCP或UDP端口地址來決定,在第四層交換中的應用區間則由源端和終端IP地址、TCP和UDP端口共同決定。

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

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


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


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

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

 

好濕好濕

架構設計漫長路
最佳實踐我來數
千萬並發沒問題
要點首推數據庫

SQL語句要優化
索引創建有藝術
三大范式不可廢
冗余字段難維護

查詢過多怎么辦
緩存使用是本固
頻繁訪問不用怕
每秒數千扛得住 

更新插入可延遲
消息隊列來輔助
滿天消息不亂飛
定向收集捋清楚

Java代碼執行快
阻塞瓶頸是同步
降低同步鎖優化
請求處理暢無阻

以上全部做到后
還需WebServer來分布
Nginx好選擇
多台Server同服務


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM