天天看點

大型網站圖檔伺服器架構的演進

在主流的Web站點中,圖檔往往是不可或缺的頁面元素,尤其在大型網站中,幾乎都将面臨“海量圖檔資源”的存儲、通路等相關技術問題。在針對圖檔伺服器的架構擴充中,也會曆經很多曲折甚至是血淚教訓(尤其是早期規劃不足,造成後期架構上很難相容和擴充)。

本文将以一個真實垂直門戶網站的發展曆程,向大家娓娓道來。

建構在Windows平台之上的網站,往往會被業内衆多架構師認為很“保守”。很大部分原因,是由于微軟技術體系的封閉和部分技術人員的短視造成的。由于長期缺乏開源支援,是以隻能“閉門造車”,這樣很容易形成思維局限性和短闆。就拿圖檔伺服器為例子,如果前期沒有容量規劃和可擴充的設計,那麼随着圖檔檔案的不斷增多和通路量的上升,由于在性能、容錯/容災、擴充性等方面的設計不足,後續将會給開發、運維工作帶來很多問題,嚴重時甚至會影響到網站業務正常運作和網際網路公司的發展(這絕不是在危言聳聽)。

之是以選擇Windows平台來建構網站和圖檔伺服器,很大部分由創始團隊的技術背景決定的,早期的技術人員可能更熟悉.NET,或者負責人認為Windows/.NET的易用性、“短平快”的開發模式、人才成本等方面都比較符合創業初期的團隊,自然就選擇了Windows。後期業務發展到一定規模,也很難輕易将整體架構遷移到其它平台上了。當然,對于建構大規模網際網路,更建議首選開源架構,因為有很多成熟的案例和開源生态的支援,避免重複造輪子和支出授權費用。對于遷移難度較大的應用,比較推薦Linux、Mono、Mysql、Memcahed……混搭的架構,同樣能支撐高并發通路和大資料量。

初創時期由于時間緊迫,開發人員水準也很有限等原因。是以通常就直接在website檔案所在的目錄下,建立1個upload子目錄,用于儲存使用者上傳的圖檔檔案。如果按業務再細分,可以在upload目錄下再建立不同的子目錄來區分。例如:upload\QA,upload\Face等。

在資料庫表中儲存的也是”upload/qa/test.jpg”這類相對路徑。

使用者的通路方式如下:

http://www.yourdomain.com/upload/qa/test.jpg

程式上傳和寫入方式:

程式員A通過在web.config中配置實體目錄D:\Web\yourdomain\upload  然後通過stream的方式寫入檔案;

程式員B通過Server.MapPath等方式,根據相對路徑擷取實體目錄  然後也通過stream的方式寫入檔案。

優點:實作起來最簡單,無需任何複雜技術,就能成功将使用者上傳的檔案寫入指定目錄。儲存資料庫記錄和通路起來倒是也很友善。

缺點:上傳方式混亂,嚴重不利于網站的擴充。

針對上述最原始的架構,主要面臨着如下問題:

1.   随着upload目錄中檔案越來越多,所在分區(例如D盤)如果出現容量不足,則很難擴容。隻能停機後更換更大容量的儲存設備,再将舊資料導入。

2.   在部署新版本(部署新版本前通過需要備份)和日常備份website檔案的時候,需要同時操作upload目錄中的檔案,如果考慮到通路量上升,後邊部署由多台Web伺服器組成的負載均衡叢集,叢集節點之間如果做好檔案實時同步将是個難題。

在website站點下面,建立一個名為upload的虛拟目錄,由于虛拟目錄的靈活性,能在一定程度上取代實體目錄,并相容原有的圖檔上傳和通路方式。使用者的通路方式依然是:

優點:配置更加靈活,也能相容老版本的上傳和通路方式。

因為虛拟目錄,可以指向本地任意盤符下的任意目錄。這樣一來,還可以通過接入外置存儲,來進行單機的容量擴充。

缺點:部署成由多台Web伺服器組成的叢集,各個Web伺服器(叢集節點)之間(虛拟目錄下的)需要實時的去同步檔案,由于同步效率和實時性的限制,很難保證某一時刻各節點上檔案是完全一緻的。

基本架構如下圖所示:

大型網站圖檔伺服器架構的演進

從上圖可看出,整個Web伺服器架構已經具備“可擴充、高可用”了,主要問題和瓶頸都集中在多台伺服器之間的檔案同步上。

上述架構中隻能在這幾台Web伺服器上互相“增量同步”,這樣一來,就不支援檔案的“删除、更新”操作的同步了。

早期的想法是,在應用程式層面做控制,當使用者請求在web1伺服器進行上傳寫入的同時,也同步去調用其它web伺服器上的上傳接口,這顯然是得不償失的。是以我們選擇使用Rsync類的軟體來做定時檔案同步的,進而省去了“重複造輪子”的成本,也降低了風險性。

同步操作裡面,一般有比較經典的兩種模型,即推拉模型:所謂“拉”,就是指輪詢地去擷取更新,所謂推,就是發生更改後主動的“推”給其它機器。當然,也可以采用加進階的事件通知機制來完成此類動作。

在高并發寫入的場景中,同步都會出現效率和實時性問題,而且大量檔案同步也是很消耗系統和帶寬資源的(跨網段則更明顯)。  

 沿用虛拟目錄的方式,通過UNC(網絡路徑)的方式實作共享存儲(将upload虛拟目錄指向UNC)

使用者的通路方式1:

使用者的通路方式2(可以配置獨立域名):

http://img.yourdomain.com/upload/qa/test.jpg

支援UNC所在server上配置獨立域名指向,并配置輕量級的web伺服器,來實作獨立圖檔伺服器。

   優點: 通過UNC(網絡路徑)的方式來進行讀寫操作,可以避免多伺服器之間同步相關的問題。相對來講很靈活,也支援擴容/擴充。支援配置成獨立圖檔伺服器和域名通路,也完整相容舊版本的通路規則。   

   缺點 :但是UNC配置有些繁瑣,而且會造成一定的(讀寫和安全)性能損失。可能會出現“單點故障”。如果存儲級别沒有raid或者更進階的災備措施,還會造成資料丢失。

大型網站圖檔伺服器架構的演進

在早期的很多基于Linux開源架構的網站中,如果不想同步圖檔,可能會利用NFS來實作。事實證明,NFS在高并發讀寫和海量存儲方面,效率上存在一定問題,并非最佳的選擇,是以大部分網際網路公司都不會使用NFS來實作此類應用。當然,也可以通過Windows自帶的DFS來實作,缺點是“配置複雜,效率未知,而且缺乏資料大量的實際案例”。另外,也有一些公司采用FTP或Samba來實作。

上面提到的幾種架構,在上傳/下載下傳操作時,都經過了Web伺服器(雖然共享存儲的這種架構,也可以配置獨立域名和站點來提供圖檔通路,但上傳寫入仍然得經過Web伺服器上的應用程式來處理),這對Web伺服器來講無疑是造成巨大的壓力。是以,更建議使用獨立的圖檔伺服器和獨立的域名,來提供使用者圖檔的上傳和通路。

1.  圖檔通路是很消耗伺服器資源的(因為會涉及到作業系統的上下文切換和磁盤I/O操作)。分離出來後,Web/App伺服器可以更專注發揮動态處理的能力。

2.  獨立存儲,更友善做擴容、容災和資料遷移。

3.  浏覽器(相同域名下的)并發政策限制,性能損失。

4.  通路圖檔時,請求資訊中總帶cookie資訊,也會造成性能損失。

5.  友善做圖檔通路請求的負載均衡,友善應用各種緩存政策(HTTP Header、Proxy Cache等),也更加友善遷移到CDN。

......

我們可以使用Lighttpd或者Nginx等輕量級的web伺服器來架構獨立圖檔伺服器。

在建構目前的圖檔伺服器架構之前,可以先徹底撇開web伺服器,直接配置單獨的圖檔伺服器/域名。但面臨如下的問題:

1.  舊圖檔資料怎麼辦?能否繼續相容舊圖檔路徑通路規則?

2.  獨立的圖檔伺服器上需要提供單獨的上傳寫入的接口(服務API對外釋出),安全問題如何保證?

3.  同理,假如有多台獨立圖檔伺服器,是使用可擴充的共享存儲方案,還是采用實時同步機制?

直到應用級别的(非系統級) DFS(例如FastDFS HDFS MogileFs MooseFS、TFS)的流行,簡化了這個問題:執行備援備份、支援自動同步、支援線性擴充、支援主流語言的用戶端api上傳/下載下傳/删除等操作,部分支援檔案索引,部分支援提供Web的方式來通路。

考慮到各DFS的特點,用戶端API語言支援情況(需要支援C#),文檔和案例,以及社群的支援度,我們最終選擇了FastDFS來部署。

唯一的問題是:可能會不相容舊版本的通路規則。如果将舊圖檔一次性導入FastDFS,但由于舊圖檔通路路徑分布存儲在不同業務資料庫的各個表中,整體更新起來也十分困難,是以必須得相容舊版本的通路規則。架構更新往往比做全新架構更有難度,就是因為還要相容之前版本的問題。(給飛機在空中換引擎可比造架飛機難得多)

首先,關閉舊版本上傳入口(避免繼續使用導緻資料不一緻)。将舊圖檔資料通過rsync工具一次性遷移到獨立的圖檔伺服器上(即下圖中描述的Old ImageServer)。在最前端(七層代理,如Haproxy、Nginx)用ACL(通路規則控制),将舊圖檔對應URL規則的請求(正則)比對到,然後将請求直接轉發指定的web 伺服器清單,在該清單中的伺服器上配置好提供圖檔(以Web方式)通路的站點,并加入緩存政策。這樣實作舊圖檔伺服器的分離和緩存,相容了舊圖檔的通路規則并提升舊圖檔通路效率,也避免了實時同步所帶來的問題。

整體架構如圖:

大型網站圖檔伺服器架構的演進

基于FastDFS的獨立圖檔伺服器叢集架構,雖然已經非常的成熟,但是由于國内“南北互聯”和IDC帶寬成本等問題(圖檔是非常消耗流量的),我們最終還是選擇了商用的CDN技術,實作起來也非常容易,原理其實也很簡單,我這裡隻做個簡單的介紹:

将img域名cname到CDN廠商指定的域名上,使用者請求通路圖檔時,則由CDN廠商提供智能DNS解析,将最近的(當然也可能有其它更複雜的政策,例如負載情況、健康狀态等)服務節點位址傳回給使用者,使用者請求到達指定的伺服器節點上,該節點上提供了類似Squid/Vanish的代理緩存服務,如果是第一次請求該路徑,則會從源站擷取圖檔資源傳回用戶端浏覽器,如果緩存中存在,則直接從緩存中擷取并傳回給用戶端浏覽器,完成請求/響應過程。

由于采用了商用CDN服務,是以我們并沒有考慮用Squid/Vanish來重複建構前置代理緩存。

上面的整個叢集架構,可以很友善的做橫向擴充,能滿足一般垂直領域大型網站的圖檔服務需求(當然,像taobao這樣超大規模的可能另當别論)。經測試,提供圖檔通路的單台Nginx伺服器(至強E5四核CPU、16G記憶體、SSD),對小靜态頁面(壓縮後的)可以扛住上萬的并發且毫無壓力。當然,由于圖檔本身體積比純文字的靜态頁面大很多,提供圖檔通路的伺服器的抗并發能力,往往會受限于磁盤的I/O處理能力和IDC提供的帶寬。Nginx的抗并發能力還是非常強的,而且對資源占用很低,尤其是處理靜态資源,似乎都不需要有過多擔心了。可以根據實際通路量的需求,通過調整Nginx參數,Linux核心調優、緩存政策等手段做更大程度的優化,也可以通過增加伺服器或者更新伺服器配置來做擴充,最直接的是通過購買更進階的儲存設備和更大的帶寬,以滿足更大通路量的需求。

值得一提的是,在“雲計算”流行的當下,也推薦高速發展期間的網站,使用“雲存儲”這樣的方案,既能幫你解決各類存儲、擴充、備災的問題,又能做好CDN加速。最重要的是,價格也不貴。

總結,有關圖檔伺服器架構擴充,大緻圍繞這些問題展開:

1.   容量規劃和擴充問題。

2.   資料的同步、備援和容災。

3.   硬體裝置的成本和可靠性(是普通機械硬碟,還是SSD,或者更高端的儲存設備和方案)。

4.   檔案系統的選擇。根據檔案特性(例如檔案大小、讀寫比例等)選擇是用ext3/4或者NFS/GFS/TFS這些開源的(分布式)檔案系統。

5.   圖檔的加速通路。采用商用CDN或者自建的代理緩存、web靜态緩存架構。

6.   舊圖檔路徑和通路規則的相容性,應用程式層面的可擴充,上傳和通路的性能和安全性等。

丁浪,技術架構師。擅長大規模(大流量、高并發、高可用、海量資料)網際網路架構,專注在“高性能,可擴充/伸縮,穩定,安全”的技術架構。 熱衷于技術研究和分享,曾分享和獨立撰寫過大量技術文章。

繼續閱讀