構(gòu)建在Windows平臺之上的網(wǎng)站,,往往會被業(yè)內(nèi)眾多架構(gòu)師認(rèn)為很“保守”,。很大部分原因,是由于微軟技術(shù)體系的封閉和部分技術(shù)人員的短視造成的。由于長期缺乏開源支持,,所以只能“閉門造車”,這樣很容易形成思維局限性和短板,。就拿圖片服務(wù)器為例子,,如果前期沒有容量規(guī)劃和可擴展的設(shè)計,那么隨著圖片文件的不斷增多和訪問量的上升,,由于在性能,、容錯/容災(zāi)、擴展性等方面的設(shè)計不足,,后續(xù)將會給開發(fā),、運維工作帶來很多問題,嚴(yán)重時甚至?xí)绊懙骄W(wǎng)站業(yè)務(wù)正常運作和互聯(lián)網(wǎng)公司的發(fā)展(這絕不是在危言聳聽),。
之所以選擇Windows平臺來構(gòu)建網(wǎng)站和圖片服務(wù)器,,很大部分由創(chuàng)始團隊的技術(shù)背景決定的,早期的技術(shù)人員可能更熟悉.NET,,或者負(fù)責(zé)人認(rèn)為Windows/.NET的易用性,、“短平快”的開發(fā)模式、人才成本等方面都比較符合創(chuàng)業(yè)初期的團隊,,自然就選擇了Windows,。后期業(yè)務(wù)發(fā)展到一定規(guī)模,也很難輕易將整體架構(gòu)遷移到其它平臺上了,。當(dāng)然,,對于構(gòu)建大規(guī)模互聯(lián)網(wǎng),,更建議首選開源架構(gòu),,因為有很多成熟的案例和開源生態(tài)的支持,避免重復(fù)造輪子和支出授權(quán)費用,。對于遷移難度較大的應(yīng)用,,比較推薦Linux、Mono,、Mysql,、Memcahed……混搭的架構(gòu),,同樣能支撐高并發(fā)訪問和大數(shù)據(jù)量。
單機時代的圖片服務(wù)器架構(gòu)(集中式)
初創(chuàng)時期由于時間緊迫,,開發(fā)人員水平也很有限等原因,。所以通常就直接在website文件所在的目錄下,建立1個upload子目錄,,用于保存用戶上傳的圖片文件,。如果按業(yè)務(wù)再細(xì)分,可以在upload目錄下再建立不同的子目錄來區(qū)分,。例如:upload\QA,upload\Face等,。
在數(shù)據(jù)庫表中保存的也是”upload/qa/test.jpg”這類相對路徑。
用戶的訪問方式如下:
http://upload.chinaz.com/2015/0731/1438326331263.jpg
程序上傳和寫入方式:
程序員A通過在web.config中配置物理目錄D:\Web\yourdomain\upload 然后通過stream的方式寫入文件,;
程序員B通過Server.MapPath等方式,,根據(jù)相對路徑獲取物理目錄 然后也通過stream的方式寫入文件。
優(yōu)點:實現(xiàn)起來最簡單,,無需任何復(fù)雜技術(shù),,就能成功將用戶上傳的文件寫入指定目錄。保存數(shù)據(jù)庫記錄和訪問起來倒是也很方便,。
缺點:上傳方式混亂,,嚴(yán)重不利于網(wǎng)站的擴展。
針對上述最原始的架構(gòu),,主要面臨著如下問題:
- 隨著upload目錄中文件越來越多,,所在分區(qū)(例如D盤)如果出現(xiàn)容量不足,則很難擴容,。只能停機后更換更大容量的存儲設(shè)備,,再將舊數(shù)據(jù)導(dǎo)入。
- 在部署新版本(部署新版本前通過需要備份)和日常備份website文件的時候,,需要同時操作upload目錄中的文件,,如果考慮到訪問量上升,后邊部署由多臺Web服務(wù)器組成的負(fù)載均衡集群,,集群節(jié)點之間如果做好文件實時同步將是個難題,。
集群時代的圖片服務(wù)器架構(gòu)(實時同步)
在website站點下面,新建一個名為upload的虛擬目錄,,由于虛擬目錄的靈活性,,能在一定程度上取代物理目錄,并兼容原有的圖片上傳和訪問方式,。用戶的訪問方式依然是:
http://upload.chinaz.com/2015/0731/1438326331844.jpg
優(yōu)點:配置更加靈活,,也能兼容老版本的上傳和訪問方式。
因為虛擬目錄,,可以指向本地任意盤符下的任意目錄,。這樣一來,,還可以通過接入外置存儲,來進(jìn)行單機的容量擴展,。
缺點:部署成由多臺Web服務(wù)器組成的集群,,各個Web服務(wù)器(集群節(jié)點)之間(虛擬目錄下的)需要實時的去同步文件,由于同步效率和實時性的限制,,很難保證某一時刻各節(jié)點上文件是完全一致的,。
基本架構(gòu)如下圖所示:
從上圖可看出,整個Web服務(wù)器架構(gòu)已經(jīng)具備“可擴展,、高可用”了,,主要問題和瓶頸都集中在多臺服務(wù)器之間的文件同步上。
上述架構(gòu)中只能在這幾臺Web服務(wù)器上互相“增量同步”,,這樣一來,就不支持文件的“刪除,、更新”操作的同步了,。
早期的想法是,在應(yīng)用程序?qū)用孀隹刂?,?dāng)用戶請求在web1服務(wù)器進(jìn)行上傳寫入的同時,,也同步去調(diào)用其它web服務(wù)器上的上傳接口,這顯然是得不償失的,。所以我們選擇使用Rsync類的軟件來做定時文件同步的,,從而省去了“重復(fù)造輪子”的成本,也降低了風(fēng)險性,。
同步操作里面,,一般有比較經(jīng)典的兩種模型,即推拉模型:所謂“拉”,,就是指輪詢地去獲取更新,,所謂推,就是發(fā)生更改后主動的“推”給其它機器,。當(dāng)然,,也可以采用加高級的事件通知機制來完成此類動作。
在高并發(fā)寫入的場景中,,同步都會出現(xiàn)效率和實時性問題,,而且大量文件同步也是很消耗系統(tǒng)和帶寬資源的(跨網(wǎng)段則更明顯)。
集群時代的圖片服務(wù)器架構(gòu)改進(jìn)(共享存儲)
沿用虛擬目錄的方式,,通過UNC(網(wǎng)絡(luò)路徑)的方式實現(xiàn)共享存儲(將upload虛擬目錄指向UNC)
用戶的訪問方式1:
http://upload.chinaz.com/2015/0731/1438326331693.jpg
用戶的訪問方式2(可以配置獨立域名):
http://upload.chinaz.com//
支持UNC所在server上配置獨立域名指向,,并配置輕量級的web服務(wù)器,來實現(xiàn)獨立圖片服務(wù)器,。
優(yōu)點: 通過UNC(網(wǎng)絡(luò)路徑)的方式來進(jìn)行讀寫操作,,可以避免多服務(wù)器之間同步相關(guān)的問題,。相對來講很靈活,也支持?jǐn)U容/擴展,。支持配置成獨立圖片服務(wù)器和域名訪問,,也完整兼容舊版本的訪問規(guī)則。
缺點 :但是UNC配置有些繁瑣,,而且會造成一定的(讀寫和安全)性能損失,。可能會出現(xiàn)“單點故障”,。如果存儲級別沒有raid或者更高級的災(zāi)備措施,,還會造成數(shù)據(jù)丟失。
基本架構(gòu)如下圖所示:
在早期的很多基于Linux開源架構(gòu)的網(wǎng)站中,,如果不想同步圖片,,可能會利用NFS來實現(xiàn)。事實證明,,NFS在高并發(fā)讀寫和海量存儲方面,,效率上存在一定問題,并非最佳的選擇,,所以大部分互聯(lián)網(wǎng)公司都不會使用NFS來實現(xiàn)此類應(yīng)用,。當(dāng)然,也可以通過Windows自帶的DFS來實現(xiàn),,缺點是“配置復(fù)雜,,效率未知,而且缺乏資料大量的實際案例”,。另外,,也有一些公司采用FTP或Samba來實現(xiàn)。
上面提到的幾種架構(gòu),,在上傳/下載操作時,,都經(jīng)過了Web服務(wù)器(雖然共享存儲的這種架構(gòu),也可以配置獨立域名和站點來提供圖片訪問,,但上傳寫入仍然得經(jīng)過Web服務(wù)器上的應(yīng)用程序來處理),,這對Web服務(wù)器來講無疑是造成巨大的壓力。所以,,更建議使用獨立的圖片服務(wù)器和獨立的域名,,來提供用戶圖片的上傳和訪問。
獨立圖片服務(wù)器/獨立域名的好處
- 圖片訪問是很消耗服務(wù)器資源的(因為會涉及到操作系統(tǒng)的上下文切換和磁盤I/O操作),。
- 分離出來后,,Web/App服務(wù)器可以更專注發(fā)揮動態(tài)處理的能力。
- 獨立存儲,更方便做擴容,、容災(zāi)和數(shù)據(jù)遷移,。
- 瀏覽器(相同域名下的)并發(fā)策略限制,性能損失,。 訪問圖片時,,請求信息中總帶cookie信息,也會造成性能損失,。
- 方便做圖片訪問請求的負(fù)載均衡,,方便應(yīng)用各種緩存策略(HTTP Header、Proxy Cache等),,也更加方便遷移到CDN,。
......
我們可以使用Lighttpd或者Nginx等輕量級的web服務(wù)器來架構(gòu)獨立圖片服務(wù)器。
當(dāng)前的圖片服務(wù)器架構(gòu)(分布式文件系統(tǒng)+CDN)
在構(gòu)建當(dāng)前的圖片服務(wù)器架構(gòu)之前,,可以先徹底撇開web服務(wù)器,,直接配置單獨的圖片服務(wù)器/域名。但面臨如下的問題:
- 舊圖片數(shù)據(jù)怎么辦,?能否繼續(xù)兼容舊圖片路徑訪問規(guī)則,?
- 獨立的圖片服務(wù)器上需要提供單獨的上傳寫入的接口(服務(wù)API對外發(fā)布),安全問題如何保證,?
- 同理,假如有多臺獨立圖片服務(wù)器,,是使用可擴展的共享存儲方案,,還是采用實時同步機制?
直到應(yīng)用級別的(非系統(tǒng)級) DFS(例如FastDFS HDFS MogileFs MooseFS,、TFS)的流行,,簡化了這個問題:執(zhí)行冗余備份、支持自動同步,、支持線性擴展,、支持主流語言的客戶端api上傳/下載/刪除等操作,部分支持文件索引,,部分支持提供Web的方式來訪問,。
考慮到各DFS的特點,客戶端API語言支持情況(需要支持C#),,文檔和案例,,以及社區(qū)的支持度,我們最終選擇了FastDFS來部署,。
唯一的問題是:可能會不兼容舊版本的訪問規(guī)則,。如果將舊圖片一次性導(dǎo)入FastDFS,但由于舊圖片訪問路徑分布存儲在不同業(yè)務(wù)數(shù)據(jù)庫的各個表中,整體更新起來也十分困難,,所以必須得兼容舊版本的訪問規(guī)則,。架構(gòu)升級往往比做全新架構(gòu)更有難度,就是因為還要兼容之前版本的問題,。(給飛機在空中換引擎可比造架飛機難得多)
解決方案如下:
首先,,關(guān)閉舊版本上傳入口(避免繼續(xù)使用導(dǎo)致數(shù)據(jù)不一致)。將舊圖片數(shù)據(jù)通過rsync工具一次性遷移到獨立的圖片服務(wù)器上(即下圖中描述的Old Image Server),。在最前端(七層代理,,如Haproxy、Nginx)用ACL(訪問規(guī)則控制),,將舊圖片對應(yīng)URL規(guī)則的請求(正則)匹配到,,然后將請求直接轉(zhuǎn)發(fā)指定的web 服務(wù)器列表,在該列表中的服務(wù)器上配置好提供圖片(以Web方式)訪問的站點,,并加入緩存策略,。這樣實現(xiàn)舊圖片服務(wù)器的分離和緩存,兼容了舊圖片的訪問規(guī)則并提升舊圖片訪問效率,也避免了實時同步所帶來的問題,。
整體架構(gòu)如圖:
基于FastDFS的獨立圖片服務(wù)器集群架構(gòu),,雖然已經(jīng)非常的成熟,但是由于國內(nèi)“南北互聯(lián)”和IDC帶寬成本等問題(圖片是非常消耗流量的),,我們最終還是選擇了商用的CDN技術(shù),,實現(xiàn)起來也非常容易,原理其實也很簡單,,我這里只做個簡單的介紹:
將img域名cname到CDN廠商指定的域名上,,用戶請求訪問圖片時,則由CDN廠商提供智能DNS解析,,將最近的(當(dāng)然也可能有其它更復(fù)雜的策略,,例如負(fù)載情況、健康狀態(tài)等)服務(wù)節(jié)點地址返回給用戶,,用戶請求到達(dá)指定的服務(wù)器節(jié)點上,,該節(jié)點上提供了類似Squid/Vanish的代理緩存服務(wù),如果是第一次請求該路徑,,則會從源站獲取圖片資源返回客戶端瀏覽器,,如果緩存中存在,則直接從緩存中獲取并返回給客戶端瀏覽器,,完成請求/響應(yīng)過程,。
由于采用了商用CDN服務(wù),所以我們并沒有考慮用Squid/Vanish來重復(fù)構(gòu)建前置代理緩存,。
上面的整個集群架構(gòu),,可以很方便的做橫向擴展,能滿足一般垂直領(lǐng)域大型網(wǎng)站的圖片服務(wù)需求(當(dāng)然,像taobao這樣超大規(guī)模的可能另當(dāng)別論),。經(jīng)測試,,提供圖片訪問的單臺Nginx服務(wù)器(至強E5四核CPU、16G內(nèi)存,、SSD),,對小靜態(tài)頁面(壓縮后的)可以扛住上萬的并發(fā)且毫無壓力。當(dāng)然,,由于圖片本身體積比純文本的靜態(tài)頁面大很多,,提供圖片訪問的服務(wù)器的抗并發(fā)能力,往往會受限于磁盤的I/O處理能力和IDC提供的帶寬,。Nginx的抗并發(fā)能力還是非常強的,,而且對資源占用很低,尤其是處理靜態(tài)資源,,似乎都不需要有過多擔(dān)心了,。可以根據(jù)實際訪問量的需求,,通過調(diào)整Nginx參數(shù),,Linux內(nèi)核調(diào)優(yōu)、緩存策略等手段做更大程度的優(yōu)化,,也可以通過增加服務(wù)器或者升級服務(wù)器配置來做擴展,,最直接的是通過購買更高級的存儲設(shè)備和更大的帶寬,以滿足更大訪問量的需求,。
值得一提的是,,在“云計算”流行的當(dāng)下,也推薦高速發(fā)展期間的網(wǎng)站,,使用“云存儲”這樣的方案,,既能幫你解決各類存儲,、擴展,、備災(zāi)的問題,又能做好CDN加速,。最重要的是,,價格也不貴。
總結(jié),,有關(guān)圖片服務(wù)器架構(gòu)擴展,,大致圍繞這些問題展開:
- 容量規(guī)劃和擴展問題。
- 數(shù)據(jù)的同步,、冗余和容災(zāi),。
- 硬件設(shè)備的成本和可靠性(是普通機械硬盤,還是SSD,或者更高端的存儲設(shè)備和方案),。
- 文件系統(tǒng)的選擇,。根據(jù)文件特性(例如文件大小、讀寫比例等)選擇是用ext3/4或者NFS/GFS/TFS這些開源的(分布式)文件系統(tǒng),。
- 圖片的加速訪問,。采用商用CDN或者自建的代理緩存、web靜態(tài)緩存架構(gòu),。
- 舊圖片路徑和訪問規(guī)則的兼容性,,應(yīng)用程序?qū)用娴目蓴U展,上傳和訪問的性能和安全性等,。
作者介紹
丁浪,,技術(shù)架構(gòu)師。擅長大規(guī)模(高并發(fā),、高可用,、海量數(shù)據(jù))互聯(lián)網(wǎng)架構(gòu),專注于打造“高性能,,可擴展/伸縮,,穩(wěn)定,安全”的技術(shù)架構(gòu),。 熱衷于技術(shù)研究和分享,,曾分享和獨立撰寫過大量技術(shù)文章。