在主流的Web站點(diǎn)中,圖片往往是不可或缺的頁面元素,尤其在大型網(wǎng)站中,幾乎都將面臨“海量圖片資源”的存儲、訪問等相關(guān)技術(shù)問題。在針對圖片服務(wù)器的架構(gòu)擴(kuò)展中,也會曆經(jīng)很多曲折甚至是血淚教訓(xùn)(尤其是早期規(guī)劃不足,造成後期架構(gòu)上很難兼容和擴(kuò)展)。 本文將以一個真實(shí)垂直門戶網(wǎng)站的發(fā)展曆程,向大家娓娓道來。 構(gòu)建在Windows平臺之上的網(wǎng)站,往往會被業(yè)內(nèi)眾多技術(shù)認(rèn)為很“保守”,甚至?xí)悬c(diǎn)。很大部分原因,是由於微軟技術(shù)體系的封閉和部分技術(shù)人員的短視造成的(當(dāng)然,主要還是人的問題)。由於長期缺乏開源支持,所以很多人只能“閉門造車”,這樣很容易形成思維局限性和短板。以圖片服務(wù)器為例子,如果前期沒有容量規(guī)劃和可擴(kuò)展的設(shè)計,那麼隨著圖片文件的不斷增多和訪問量的上升,由於在性能、容錯/容災(zāi)、擴(kuò)展性等方面的設(shè)計不足,後續(xù)將會給開發(fā)、運(yùn)維工作帶來很多問題,嚴(yán)重時甚至?xí)绊懙骄W(wǎng)站業(yè)務(wù)正常運(yùn)作和互聯(lián)網(wǎng)公司的發(fā)展(這絕不是在危言聳聽)。 很多公司之所以選擇Windows()平臺來構(gòu)建網(wǎng)站和圖片服務(wù)器,很大部分由創(chuàng)始團(tuán)隊的技術(shù)背景決定的,早期的技術(shù)人員可能更熟悉.NET,或者團(tuán)隊的負(fù)責(zé)人認(rèn)為Windows/.NET的易用性、“短平快”的開發(fā)模式、人才成本等方面都比較符合創(chuàng)業(yè)初期的團(tuán)隊,自然就選擇了Windows。後期業(yè)務(wù)發(fā)展到一定規(guī)模,也很難輕易將整體架構(gòu)遷移到其它開源平臺上了。當(dāng)然,對於構(gòu)建大規(guī);ヂ(lián)網(wǎng),更建議首選開源架構(gòu),因?yàn)橛泻芏喑墒斓陌咐烷_源生態(tài)的支持(也會有很多坑,就看是你自己最先去踩坑,還是在別人踩了修復(fù)之後你再用),避免重復(fù)造輪子和支出高額授權(quán)費(fèi)用。對於遷移難度較大的應(yīng)用,個人比較推薦Linux、Mono、Jexus、Mysql、Memcahed、Redis……混搭的架構(gòu),同樣能支撐具有高並發(fā)訪問和大數(shù)據(jù)量等特點(diǎn)的互聯(lián)網(wǎng)應(yīng)用。 初創(chuàng)時期由於時間緊迫,開發(fā)人員水平也很有限等原因。所以通常就直接在website文件所在的目錄下,建立1個upload子目錄,用於保存用戶上傳的圖片文件。如果按業(yè)務(wù)再細(xì)分,可以在upload目錄下再建立不同的子目錄來區(qū)分。例如:upload\QA,upload\Face等。 在數(shù)據(jù)庫表中保存的也是”upload/qa/test.jpg”這類相對徑。 用戶的訪問方式如下:
從上圖可看出,整個Web服務(wù)器架構(gòu)已經(jīng)具備“可擴(kuò)展、高可用”了,主要問題和瓶頸都集中在多臺服務(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ā)生更改後主動的“推”給其它機(jī)器。當(dāng)然,也可以采用加高級的事件通知機(jī)制來完成此類動作。 在高並發(fā)寫入的場景中,同步都會出現(xiàn)效率和實(shí)時性問題,而且大量文件同步也是很消耗系統(tǒng)和帶寬資源的(跨網(wǎng)段則更明顯)。 沿用虛擬目錄的方式,通過UNC(網(wǎng)絡(luò)徑)的方式實(shí)現(xiàn)共享存儲(將upload虛擬目錄指向UNC) 用戶的訪問方式1:
在早期的很多基於Linux開源架構(gòu)的網(wǎng)站中,如果不想同步圖片,可能會利用NFS來實(shí)現(xiàn)。事實(shí)證明,NFS在高並發(fā)讀寫和海量存儲方面,效率上存在一定問題,並非最佳的選擇,所以大部分互聯(lián)網(wǎng)公司都不會使用NFS來實(shí)現(xiàn)此類應(yīng)用。當(dāng)然,也可以通過Windows自帶的DFS來實(shí)現(xiàn),缺點(diǎn)是“配置復(fù)雜,效率未知,而且缺乏資料大量的實(shí)際案例”。另外,也有一些公司采用FTP或Samba來實(shí)現(xiàn)。 提到的幾種架構(gòu),在上傳/下載操作時,都經(jīng)過了Web服務(wù)器(雖然共享存儲的這種架構(gòu),也可以配置獨(dú)立域名和站點(diǎn)來提供圖片訪問,但上傳寫入仍然得經(jīng)過Web服務(wù)器上的應(yīng)用程序來處理),這對Web服務(wù)器來講無疑是造成巨大的壓力。所以,更建議使用獨(dú)立的圖片服務(wù)器和獨(dú)立的域名,來提供用戶圖片的上傳和訪問。 直到應(yīng)用級別的(非系統(tǒng)級) DFS(例如FastDFS HDFS MogileFs MooseFS、TFS)的流行,簡化了這個問題:執(zhí)行冗餘備份、支持自動同步、支持線性擴(kuò)展、支持主流語言的客戶端api上傳/下載/刪除等操作,部分支持文件索引,部分支持提供Web的方式來訪問。 考慮到各DFS的特點(diǎn),客戶端API語言支持情況(需要支持C#),文檔和案例,以及社區(qū)的支持度,我們最終選擇了FastDFS來部署。 唯一的問題是:可能會不兼容舊版本的訪問規(guī)則。如果將舊圖片一次性導(dǎo)入FastDFS,但由於舊圖片訪問徑分布存儲在不同業(yè)務(wù)數(shù)據(jù)庫的各個表中,整體更新起來也十分困難,所以必須得兼容舊版本的訪問規(guī)則。架構(gòu)升級往往比做全新架構(gòu)更有難度,就是因?yàn)檫要兼容之前版本的問題。(給飛機(jī)在空中換引擎可比造架飛機(jī)難得多) 首先,關(guān)閉舊版本上傳入口(避免繼續(xù)使用導(dǎo)致數(shù)據(jù)不一致)。將舊圖片數(shù)據(jù)通過rsync工具一次性遷移到獨(dú)立的圖片服務(wù)器上(即下圖中描述的Old Image Server)。在最前端(七層代理,如Haproxy、Nginx)用ACL(訪問規(guī)則控制),將舊圖片對應(yīng)URL規(guī)則的請求(正則)匹配到,然後將請求直接轉(zhuǎn)發(fā)指定的web 服務(wù)器列表,在該列表中的服務(wù)器上配置好提供圖片(以Web方式)訪問的站點(diǎn),並加入緩存策略。這樣實(shí)現(xiàn)舊圖片服務(wù)器的分離和緩存,兼容了舊圖片的訪問規(guī)則並提升舊圖片訪問效率,也避免了實(shí)時同步所帶來的問題。 整體架構(gòu)如圖: 基於FastDFS的獨(dú)立圖片服務(wù)器集群架構(gòu),雖然已經(jīng)非常的成熟,但是由於國內(nèi)“南北互聯(lián)”和IDC帶寬成本等問題(圖片常消耗流量的),我們最終還是選擇了商用的CDN技術(shù),實(shí)現(xiàn)起來也非常容易,原理其實(shí)也很簡單,我這裏只做個簡單的介紹: 將img域名cname到CDN廠商指定的域名上,用戶請求訪問圖片時,則由CDN廠商提供智能DNS解析,將最近的(當(dāng)然也可能有其它更復(fù)雜的策略,例如負(fù)載情況、健康狀態(tài)等)服務(wù)節(jié)點(diǎn)地址返回給用戶,用戶請求到達(dá)指定的服務(wù)器節(jié)點(diǎn)上,該節(jié)點(diǎn)上提供了類似Squid/Vanish的代理緩存服務(wù),如果是第一次請求該徑,則會從源站獲取圖片資源返回客戶端瀏覽器,如果緩存中存在,則直接從緩存中獲取並返回給客戶端瀏覽器,完成請求/響應(yīng)過程。 由於采用了商用CDN服務(wù),所以我們並沒有考慮用Squid/Vanish來自行構(gòu)建前置代理緩存。 的整個集群架構(gòu),可以很方便的做橫向擴(kuò)展,能滿足一般垂直領(lǐng)域中大型網(wǎng)站的圖片服務(wù)需求(當(dāng)然,像taobao這樣超大規(guī)模的可能另當(dāng)別論)。經(jīng)測試,提供圖片訪問的單臺Nginx服務(wù)器(至強(qiáng)E5四核CPU、16G內(nèi)存、SSD),對小靜態(tài)頁面(壓縮後大概只有10kb左右的)可以扛住幾千個並發(fā)且毫無壓力。當(dāng)然,由於圖片本身體積比純文本的靜態(tài)頁面大很多,提供圖片訪問的服務(wù)器的抗並發(fā)能力,往往會受限於磁盤的I/O處理能力和IDC提供的帶寬。Nginx的抗並發(fā)能力還常強(qiáng)的,而且對資源占用很低,尤其是處理靜態(tài)資源,似乎都不需要有過多擔(dān)心了?梢愿鶕(jù)實(shí)際訪問量的需求,通過調(diào)整Nginx的參數(shù),對Linux內(nèi)核做調(diào)優(yōu),加入分級緩存策略等手段能夠做更大程度的優(yōu)化,也可以通過增加服務(wù)器或者升級服務(wù)器配置來做擴(kuò)展,最直接的是通過購買更高級的存儲設(shè)備和更大的帶寬,以滿足更大訪問量的需求。 值得一提的是,在“雲(yún)計算”流行的當(dāng)下,也推薦高速發(fā)展期間的網(wǎng)站,使用“雲(yún)存儲”這樣的方案,既能幫你解決各類存儲、擴(kuò)展、備災(zāi)的問題,又能做好CDN加速。最重要的是,價格也不貴。 總結(jié),有關(guān)圖片服務(wù)器架構(gòu)擴(kuò)展,大致圍繞這些問題展開: |