阿里雲團隊暢談圖片服務架構演進
現在幾乎任何一個網站、Web App以及移動APP等應用都需要有圖片展示的功能,對於圖片功能從下至上都是很重要的。必須要具有前瞻性的規劃好圖片伺服器,圖片的上傳和下載速度至關重要,當然這並不是說一上來就搞很NB的架構,至少具備一定擴充套件性和穩定性。雖然各種架構設計都有,在這裡我只是談談我的一些個人想法。
對於圖片伺服器來說IO無疑是消耗資源最為嚴重的,對於web應用來說需要將圖片伺服器做一定的分離,否則很可能因為圖片伺服器的IO負載導致應用崩潰。因此尤其對於大型網站和應用來說,非常有必要將圖片伺服器和應用伺服器分離,構建獨立的圖片伺服器叢集,構建獨立的圖片伺服器其主要優勢:
1)分擔Web伺服器的I/O負載-將耗費資源的圖片服務分離出來,提高伺服器的效能和穩定性。
2)能夠專門對圖片伺服器進行優化-為圖片服務設定有針對性的快取方案,減少頻寬網路成本,提高訪問速度。
3)提高網站的可擴充套件性-通過增加圖片伺服器,提高圖片服務吞吐能力。
從傳統網際網路的web1.0,歷經web2.0時代以及發展到現在的web3.0,隨著圖片儲存規模的增加,圖片伺服器的架構也在逐漸發生變化,以下主要論述三個階段的圖片伺服器架構演進。
初始階段
在介紹初始階段的早期的小型圖片伺服器架構之前,首先讓我們瞭解一下NFS技術,NFS是Network File System的縮寫,即網路檔案系統。NFS是由Sun開發並發展起來的一項用於在不同機器,不同作業系統之間通過網路互相分享各自的檔案。NFS
server也可以看作是一個FILE SERVER,用於在UNIX類系統之間共享檔案,可以輕鬆的掛載(mount)到一個目錄上,操作起來就像本地檔案一樣的方便。
如果不想在每臺圖片伺服器同步所有圖片,那麼NFS是最簡單的檔案共享方式。NFS是個分散式的客戶機/伺服器檔案系統,NFS的實質在於使用者間計算機的共享,使用者可以聯結到共享計算機並象訪問本地硬碟一樣訪問共享計算機上的檔案。具體實現思路是:
1)所有前端web伺服器都通過nfs掛載3臺圖片伺服器export出來的目錄,以接收web伺服器寫入的圖片。然後[圖片1]伺服器掛載另外兩臺圖片伺服器的export目錄到本地給apache對外提供訪問。
2) 使用者上傳圖片
使用者通過Internet訪問頁面提交上傳請求post到web伺服器,web伺服器處理完圖片後由web伺服器拷貝到對應的mount本地目錄。
3)使用者訪問圖片
使用者訪問圖片時,通過[圖片1]這臺圖片伺服器來讀取相應mount目錄裡邊的圖片。
以上架構存在的問題:
1)效能:現有結構過度依賴nfs,當圖片伺服器的nfs伺服器有問題時,可能影響到前端web伺服器。NFS的問題主要是鎖的問題. 很容易造成死鎖, 只有硬體重啟才能解決。尤其當圖片達到一定的量級後,nfs會有嚴重的效能問題。
2)高可用:對外提供下載的圖片伺服器只有一臺,容易出現單點故障。
3) 擴充套件性:圖片伺服器之間的依賴過多,而且橫向擴充套件餘地不夠。
4) 儲存:web伺服器上傳熱點不可控,造成現有圖片伺服器空間佔用不均衡。
5) 安全性:nfs方式對於擁有web伺服器的密碼的人來說,可以隨意修改nfs裡邊的內容,安全級別不高。
當然圖片伺服器的圖片同步可以不採用NFS,也可以採用ftp或rsync,採用ftp這樣的話每個圖片伺服器就都儲存一份圖片的副本,也起到了備份的作用。但是缺點是將圖片ftp到伺服器比較耗時,如果使用非同步方式去同步圖片的話又會有延時,不過一般的小圖片檔案也還好了。使用rsync同步,當資料檔案達到一定的量級後,每次rsync掃描會耗時很久也會帶來一定的延時性。
發展階段
當網站達到一定的規模後,對圖片伺服器的效能和穩定性有一定的要求後,上述NFS圖片服務架構面臨著挑戰,嚴重的依賴NFS,而且系統存在單點機器容易出現故障,需要對整體架構進行升級。於是出現了上圖圖片伺服器架構,出現了分散式的圖片儲存。
其實現的具體思路如下:
1)使用者上傳圖片到web伺服器後,web伺服器處理完圖片,然後再由前端web伺服器把圖片post到到[圖片1]、[圖片2]…[圖片N]其中的一個,圖片伺服器接收到post過來的圖片,然後把圖片寫入到本地磁碟並返回對應成功狀態碼。前端web伺服器根據返回狀態碼決定對應操作,如果成功的話,處理生成各尺寸的縮圖、打水印,把圖片伺服器對應的ID和對應圖片路徑寫入DB資料庫。
2) 上傳控制
我們需要調節上傳時,只需要修改web伺服器post到的目的圖片伺服器的ID,就可以控制上傳到哪臺圖片儲存伺服器,對應的圖片儲存伺服器只需要安裝nginx同時提供一個python或者php服務接收並儲存圖片,如果不想不想開啟python或者php服務,也可以編寫一個nginx擴充套件模組。
3) 使用者訪問流程
使用者訪問頁面的時候,根據請求圖片的URL到對應圖片伺服器去訪問圖片。
如:
此階段的圖片伺服器架構,增加了負載均衡和分散式圖片儲存,能夠在一定程度上解決併發訪問量高和儲存量大的問題。負載均衡在有一定財力的情況下可以考慮F5硬負載,當然也可以考慮使用開源的LVS軟負載(同時還可開啟快取功能)。此時將極大提升訪問的併發量,可以根據情況隨時調配伺服器。當然此時也存在一定的瑕疵,那就是可能在多臺Squid上存在同一張圖片,因為訪問圖片時可能第一次分到squid1,在LVS過期後第二次訪問到squid2或者別的,當然相對併發問題的解決,此種少量的冗餘完全在我們的允許範圍之內。在該系統架構中二級快取可以使用squid也可以考慮使用varnish或者traffic server,對於cache的開源軟體選型要考率以下幾點
1)效能:varnish本身的技術上優勢要高於squid,它採用了“Visual Page Cache”技術,在記憶體的利用上,Varnish比Squid具有優勢,它避免了Squid頻繁在記憶體、磁碟中交換檔案,效能要比Squid高。varnish是不能cache到本地硬碟上的。還有強大的通過Varnish管理埠,可以使用正則表示式快速、批量地清除部分快取。nginx是用第三方模組ncache做的緩衝,其效能基本達到varnish,但在架構中nginx一般作為反向(靜態檔案現在用nginx的很多,併發能支援到2萬+)。在靜態架構中,如果前端直接面對的是cdn活著前端了4層負載的話,完全用nginx的cache就夠了。
2)避免檔案系統式的快取,在檔案資料量非常大的情況下,檔案系統的效能很差,像squid,nginx的proxy_store,proxy_cache之類的方式快取,當快取的量級上來後,效能將不能滿足要求。開源的traffic server直接用裸盤快取,是一個不錯的選擇,國內大規模應用並公佈出來的主要是淘寶,並不是因為它做的差,而是開源時間晚。Traffic Server 在 Yahoo 內部使用了超過 4 年,主要用於 CDN 服務,CDN 用於分發特定的HTTP 內容,通常是靜態的內容如圖片、JavaScript、CSS。當然使用leveldb之類的做快取,我估計也能達到很好的效果。
3)穩定性:squid作為老牌勁旅快取,其穩定性更可靠一些,從我身邊一些使用者反饋來看varnish偶爾會出現crash的情況。Traffic Server在雅虎目前使用期間也沒有出現已知的資料損壞情況,其穩定性相對也比較可靠,對於未來我其實更期待Traffic Server在國內能夠擁有更多的使用者。
以上圖片服務架構設計消除了早期的NFS依賴以及單點問題,時能夠均衡圖片伺服器的空間,提高了圖片伺服器的安全性等問題,但是又帶來一個問題是圖片伺服器的橫向擴充套件冗餘問題。只想在普通的硬碟上儲存,首先還是要考慮一下物理硬碟的實際處理能力。是 7200 轉的還是 15000 轉的,實際表現差別就很大。至於檔案系統選擇,需要做一些效能方面的測試,從官方的一些測試資料來看,reiserFs更適合儲存一些小圖片檔案。建立檔案系統的時候 Inode 問題也要加以考慮,選擇合適大小的 inode size ,因為Linux 為每個檔案分配一個稱為索引節點的號碼inode,可以將inode簡單理解成一個指標,它永遠指向本檔案的具體儲存位置。一個檔案系統允許的inode節點數是有限的,如果檔案數量太多,即使每個檔案都是0位元組的空檔案,系統最終也會因為節點空間耗盡而不能再建立檔案,因此需要在空間和速度上做取捨,構造合理的檔案目錄索引。
雲端儲存階段
2011年李彥巨集在百度聯盟峰會上就提到過網際網路的讀圖時代已經到來,圖片服務早已成為一個網際網路應用中佔比很大的部分,對圖片的處理能力也相應地變成企業和開發者的一項基本技能,圖片的下載和上傳速度顯得更加重要,要想處理好圖片,需要面對的三個主要問題是:大流量、高併發、海量儲存。
阿里雲端儲存服務(OpenStorageService,簡稱OSS),是阿里雲對外提供的海量,安全,低成本,高可靠的雲端儲存服務。使用者可以通過簡單的 REST介面,在任何時間、任何地點上傳和下載資料,也可以使用WEB頁面對資料進行管理。同時,OSS提供Java、Python、PHP SDK,簡化使用者的程式設計。基於OSS,使用者可以搭建出各種多媒體分享網站、網盤、個人企業資料備份等基於大規模資料的服務。在以下圖片雲端儲存主要以阿里雲的雲端儲存OSS為切入點介紹,上圖為OSS雲端儲存的簡單架構示意圖。
真正意義上的“雲端儲存”,不是儲存而是提供雲服務,使用雲端儲存服務的主要優勢有以下幾點:
1)使用者無需瞭解儲存裝置的型別、介面、儲存介質等。
2)無需關心資料的儲存路徑。
3)無需對儲存裝置進行管理、維護。
4)無需考慮資料備份和容災
5)簡單接入雲端儲存,盡情享受儲存服務。
架構模組組成1)KV Engine
OSS中的Object源資訊和資料檔案都是存放在KV Engine上。在6.15的版本,V Engine將使用0.8.6版本,並使用為OSS提供的OSSFileClient。
2)Quota
此模組記錄了Bucket和使用者的對應關係,和以分鐘為單位的Bucket資源使用情況。Quota還將提供HTTP介面供Boss系統查詢。
3)安全模組
安全模組主要記錄User對應的ID和Key,並提供OSS訪問的使用者驗證功能。
OSS術語名詞彙
1 )Access Key ID & Access Key Secret (API金鑰)
使用者註冊OSS時,系統會給使用者分配一對Access Key ID & Access Key Secret,稱為ID對,用於標識使用者,為訪問OSS做簽名驗證。
2) Service
OSS提供給使用者的虛擬儲存空間,在這個虛擬空間中,每個使用者可擁有一個到多個Bucket。
3) Bucket
Bucket是OSS上的名稱空間;Bucket名在整個OSS中具有全域性唯一性,且不能修改;儲存在OSS上的每個Object必須都包含在某個Bucket中。一個應用,例如圖片分享網站,可以對應一個或多個Bucket。一個使用者最多可建立10個Bucket,但每個Bucket中存放的Object的數量和大小總和沒有限制,使用者不需要考慮資料的可擴充套件性。
4) Object
在OSS中,使用者的每個檔案都是一個Object,每個檔案需小於5TB。Object包含key、data和user meta。其中,key是Object的名字;data是Object的資料;user meta是使用者對該object的描述。
其使用方式非常簡單,如下為java sdk:
OSSClient ossClient = new OSSClient(accessKeyId,accessKeySecret);
PutObjectResult result = ossClient.putObject(bucketname, bucketKey, inStream, new ObjectMetadata());
執行以上程式碼即可將圖片流上傳至OSS伺服器上。
分散式檔案系統
用分散式儲存有幾個好處,分散式能自動提供冗餘,不需要我們去備份,擔心資料安全,在檔案數量特別大的情況下,備份是一件很痛苦的事情,rsync掃一次可能是就是好幾個小時,還有一點就是分散式儲存動態擴容方便。當然在國內的其他一些檔案系統裡,TFS()和FASTDFS也有一些使用者,但是TFS的優勢更是針對一些小檔案儲存,主要是淘寶在用。另外FASTDFS在併發高於300寫入的情況下出現效能問題,穩定性不夠友好。OSS儲存使用的是阿里雲基於飛天5k平臺自主研發的高可用,高可靠的分散式檔案系統盤古。分散式檔案系統盤古和Google的GFS類似,盤古的架構是Master-Slave主從架構,Master負責元資料管理,Sliave叫做Chunk Server,負責讀寫請求。其中Master是基於Paxos的多Master架構,一個Master死了之後,另外一個Master可以很快接過去,基本能夠做到故障恢復在一分鐘以內 。檔案是按照分片存放,每個會分三個副本,放在不同的機架上,最後提供端到端的資料校驗。
HAPROXY負載均衡
基於haproxy的自動hash架構 ,這是一種新的快取架構,由nginx作為最前端,代理到快取機器。 nginx後面是快取組,由nginx經過url hash後將請求分到快取機器。
這個架構方便純squid快取升級,可以在squid的機器上加裝nginx。 nginx有快取的功能,可以將一些訪問量特大的連結直接快取在nginx上,就不用經過多一次代理的請求,能夠保證圖片伺服器的高可用、高效能。比如favicon.ico和網站的logo。 負載均衡負責OSS所有的請求的負載均衡,後臺的http伺服器故障會自動切換,從而保證了OSS的服務不間斷。
CDN
阿里雲CDN服務是一個遍佈全國的分散式快取系統,能夠將網站檔案(如圖片或JavaScript程式碼檔案)快取到全國多個城市機房中的伺服器上,當一個使用者訪問你的網站時,會就近到靠近TA的城市的伺服器上獲取資料,這樣終端使用者訪問你的服務速度會非常快。
阿里雲CDN服務在全國部署超過100個節點,能提供給使用者優良的網路加速效果。當網站業務突然爆發增長時,無需手忙腳亂地擴容網路頻寬,使用CDN服務即可輕鬆應對。和OSS服務一樣,使用CDN,需要先在aliyun.com網站上開通CDN服務。開通後,需要在網站上的管理中心建立你的distribution(即分發頻道),每個distribution由兩個必須的部分組成:distribution ID和源站地址。
使用阿里雲OSS和CDN可以非常方便的針對每個bucket進行內容加速,因為每個bucket對應一個獨立的二級域名,針對每個檔案進行CDN刪除,簡單、經濟地解決服務的儲存和網路問題,畢竟大多數網站或應用的儲存和網路頻寬多半是被圖片或視訊消耗掉的。
從整個業界來看,最近這樣的面向個人使用者的雲端儲存如國外的DropBox和Box.net非常受歡迎,國內的雲端儲存目前比較不錯的主要有七牛雲端儲存和又拍雲端儲存。
上傳下載分而治之
圖片伺服器的圖片下載比例遠遠高於上傳比例,業務邏輯的處理也區別明顯,上傳服器對圖片重新命名,記錄入庫資訊,下載伺服器對圖片新增水印、修改尺寸之類的動態處理。從高可用的角度,我們能容忍部分圖片下載失敗,但絕不能有圖片上傳失敗,因為上傳失敗,意味著資料的丟失。上傳與下載分開,能保證不會因下載的壓力影響圖片的上傳,而且還有一點,下載入口和上傳入口的負載均衡策略也有所不同。上傳需要經過Quota Server記錄使用者和圖片的關係等邏輯處理,下載的邏輯處理如果繞過了前端快取處理,穿透後端業務邏輯處理,需要從OSS獲取圖片路徑資訊。近期阿里雲會推出基於CDN就近上傳的功能,自動選擇離使用者最近的CDN節點,使得資料的上傳下載速度均得到最優化。相較傳統IDC,訪問速度提升數倍。
圖片防盜鏈處理
如果服務不允許防盜鏈,那麼訪問量會引起頻寬、伺服器壓力等問題。比較通用的解決方案是在nginx或者squid反向代理軟體上新增refer ACL判斷,OSS也提供了基於refer的防盜鏈技術。當然OSS也提供了更為高階的URL簽名防盜鏈,其其實現思路如下:
首先,確認自己的bucket許可權是private,即這個bucket的所有請求必須在簽名認證通過後才被認為是合法的。然後根據操作型別、要訪問的bucket、要訪問的object以及超時時間,動態地生成一個經過簽名的URL。通過這個簽名URL,你授權的使用者就可以在該簽名URL過期時間前執行相應的操作。
簽名的Python程式碼如下:
h=hmac.new(“OtxrzxIsfpFjA7SwPzILwy8Bw21TLhquhboDYROV”, “GET\n\n\n1141889120\n/oss-example/oss-api.jpg”,sha);
urllib.quote_plus (base64.encodestring(h.digest()).strip());
其中method可以是PUT、GET、HEAD、DELETE中的任意一種;最後一個引數“timeout”是超時的時間,單位是秒。一個通過上面Python方法,計算得到的簽名URL為:
http://oss-example.oss-cn-hangzhou.aliyuncs.com/oss-api.jpg?OSSAccessKeyId=44CF9590006BF252F707&Expires=1141889120&Signature=vjbyPxybdZaNmGa%2ByT272YEAiv4%3D
通過這種動態計算簽名URL的方法,可以有效地保護放在OSS上的資料,防止被其他人盜鏈。
圖片編輯處理API
對於線上圖片的編輯處理,GraphicsMagick(GraphicsMagick())對於從事網際網路的技術人員應該不會陌生。GraphicsMagick是從 ImageMagick 5.5.2 分支出來的,但是現在他變得更穩定和優秀,GM更小更容易安裝、GM更有效率、GM的手冊非常豐富GraphicsMagick的命令與ImageMagick基本是一樣的。
GraphicsMagick 提供了包括裁、縮放、合成、打水印、影象轉換、填充等非常豐富的介面API,其中的開發包SDK也非常豐富,包括了JAVA(im4java)、C、C++、Perl、PHP、Tcl、Ruby等的呼叫,支援超過88中影象格式,包括重要的DPX、GIF、JPEG、JPEG-2000、PNG、PDF、PNM和TIFF,GraphicsMagick可以再絕大多數的平臺上使用,Linux、Mac、Windows都沒有問題。但是獨立開發這些圖片處理服務,對伺服器的IO要求相對要高一些,而且目前這些開源的圖片處理編輯庫,相對來說還不是很穩定,筆者在使用GraphicsMagick 的時候就遇到了tomcat 程序crash情況,需要手動重啟tomcat服務。
阿里雲目前已經對外開放圖片處理API,包括了大多數常用處理解決方案:縮圖、打水印、文字水印、樣式、管道等。開發者可以非常方便的使用如上圖片處理方案,希望越來越多的開發者能夠基於OSS開放出更多優秀的產品。