假設每張圖片平均的尺寸在200K左右,大概需要占據(jù)的存儲空間是190G,如果您的圖片沒有進行壓縮,那么平均會在1M左右,整體上也就是1TB左右的空間,綜合考慮起來,如果是一個SNS網(wǎng)站,在20萬用戶的時候會接近這個規(guī)模的。
1000萬我所指的是圖片請求,而不是通常所提到的Page View,不去太追究具體每個頁面會有多少的圖片需要請求,以平均15個圖片來計算,大致是每天70萬的PageView,應該來說這是一個中等規(guī)模的網(wǎng)站。
很明顯,一個20萬用戶,每天70PV的網(wǎng)站是我們圖片服務優(yōu)化設計的基準點,這時候我們可以考慮在下列的幾個環(huán)節(jié)做優(yōu)化:
l 緩存:盡可能降低客戶端的重復請求,盡可能降低同一圖片在服務器的重復處理
l 存儲:盡可能服務器代碼獲取原始圖片的時間
l 網(wǎng)絡結構:在硬件設計上盡可能讓系統(tǒng)架構可擴展和易于管理
下面我們依照上述的基準考慮,來看看可以在那些環(huán)節(jié)上都手術,從而提高圖片服務的整體能力:
1. 為客戶端增加緩存的能力
我們知道,許多圖片應用都是需要請求一些小圖片,如用戶頭像,那么這種情況下對于圖片重復請求的情況則不可避免。同時我們也知道,瀏覽器都是有緩存的,為此我們應該盡讓讓瀏覽器從緩存中取的圖片,而不是重復的請求。有兩種方式來為實現(xiàn)客戶端的緩存:
1. 向客戶端增加過期或者緩存控制
對于相對靜態(tài)的圖片,我們可以增加過期策略(Expired),如果我們發(fā)送了下列的Http header:
Expires:Thu, 15 Apr 2010 20:00:00 GMT
則表示當前圖片到2010年5月15日20點過期,在這之前,如果瀏覽器已經(jīng)存在圖片,則不會從新請求。
對于動態(tài)圖片,如在用戶上傳的圖片里寫入簽名檔,我們則可以通過增加Cache-Control的header來幫助瀏覽器根據(jù)條件判斷是否重新請求。
關于expires和cache-control的詳細說明,請參閱相關的文檔,這里不在螯述。
2. 使用etag來強行要求客戶端不重新請求
ETag的作用是告訴瀏覽器緩存,緩存中的內容是否已經(jīng)變化的一種機制。和Last Modified結合使用,告知瀏覽器緩存的生成時間。您可以簡單地將etag理解為服務器端對于對象的唯一名字(token)。
假設我們發(fā)送了這樣的header: ETag: "50b1c1d4f775c61:df3"
當瀏覽器第二次請求該圖片時,會用這樣的格式查詢:
If-None-Match: W/"50b1c1d4f775c61:df3"
如果圖片沒有作任何改變,服務器將會給瀏覽器發(fā)送響應304和空的響應體。
HTTP/1.0 304 Not Modified
正是如此,也避免了圖片的重復請求。
2. 為圖片處理的結果增加緩存
從字面上不難理解,比如請求了圖片的縮略圖,圖片處理是相當耗費資源的,那么我們應該避免重復的圖片轉換,簡單一點地說,張上請求了abcdef.jpg的80x100的縮略圖,服務器為此已經(jīng)生產(chǎn)了縮略圖,然后發(fā)送給張三,那么李四再請求這張圖片的時候,就應該將處理結果發(fā)送給李四,而不是再進行一遍的圖片縮放處理。
而如何緩存這些處理完畢的結果呢?最簡單的做法是放在內容,下一次請求的時候直接從內存將處理結果發(fā)送給瀏覽器。但內存資源始終是有限的,而圖片本身是相對占據(jù)空間的,在訪問量比較大的情況下,如果請求的圖片比較分散,這時候緩存的命中率是一個很大的問題。
為了解決存儲的問題,我們可以提出另外一個方案:將處理結果存儲在文件系統(tǒng),下一次請求直接從文件里讀取輸出結果。存儲空間的問題也就解決了,但是會帶來另外一個問題,100萬張的圖片生成不同尺寸的圖片,那就是100萬的倍數(shù),此時會讓緩存文件變得無比巨大,甚至大過原始圖片的存儲空間,那應該如何解決呢?
我們剛才討論的核心是文件緩存和內存緩存這兩種不同的緩存方式,兩種方式都會存在一些不足之處,為了更好地了解優(yōu)缺點,我們做一個比較:
內存緩存 |
文件緩存 |
l 優(yōu)勢 n 高性能,無任何額外的處理 l 劣勢 n 能夠支持的存儲有限 n 在文件數(shù)比較大的時候緩存命中率比較低 |
l 優(yōu)勢 n 支持比較大的存儲(比如100G) n 整體來性能可以接受 l 劣勢 n 在圖片數(shù)量比較大的情況下,會導致緩存占據(jù)太多的空間 n 業(yè)務出現(xiàn)變更的時候,緩存的管理是一個大問題 |
從列表我們可以看到各自的特點,從傾向來說,文件緩存會有更大的優(yōu)勢,但并不是沒有缺點,尤其在文件數(shù)量龐大的情況下,我們之前的討論也提到過,文件系統(tǒng)對于海量的小文件支持是沒有優(yōu)勢的,而像80x100的用戶頭像,大多情況下不超過10K,你要維護一個超過100萬小文件的地目錄也是有困難的。
這個時候我們需要定義緩存策略,從而在性能和可管理性及其存儲之間找到一個平衡點:
ü 數(shù)量巨大的小圖片,因為不占據(jù)太多的存儲空間,但是從業(yè)務角度來說,卻是需要被頻繁訪問的,從性能的角度考慮,可以把這些數(shù)據(jù)放在內存中,在頻繁訪問的情況下也就不會造成太大的性能瓶頸
ü 對于中等尺寸的圖片,相對來說訪問的頻率沒有小圖片高,但是在存儲上也沒有原始圖片大,可以考慮將這些圖片緩存在文件系統(tǒng)中
ü 對于一些比較大的圖片,因為訪問的頻率比較低,可以考慮不緩存,直接推送到客戶端。
在這樣的原則基礎上,我們可以用下面的兩個指標去決定到底我們需要采用怎樣的緩存策略:
圖片訪問頻率
圖片的字節(jié)大小
圖片訪問頻率越高,越傾向放在內存,反之越傾向不緩存
圖片字節(jié)數(shù)越大,越傾向文件緩存,反之放在內存
至于實際情況應該如何解決,只能夠根據(jù)您的具體業(yè)務做一些合適的調整,在這里我只是介紹了圖片緩存的一些基本原則。
到目前為止,我們已經(jīng)進一步完善了圖片服務,在單機情況下,我們相對詳細地考慮了圖片服務的各個方面,如果業(yè)務壓力不是極其大的情況下,做到這點應該完全可以勝任了。下圖則描述了目前圖片服務的組件結構:
從圖上可以看到,針對圖片服務我們做了一些抽象,Cache Service負責所有涉及到緩存的管理,而Image Processor負責圖片的轉換服務,Image Service會利用這三個核心的組件協(xié)同工作,把原圖片存儲的工作交給Storage Service來完成,將圖片轉換的工作交給Image Processor,將緩存的工作交給Cache Service來處理。
到此,我們能夠清晰地描述圖片服務的工作流程了:
1. 接受瀏覽器的請求
2. 提交給緩存服務,如果已經(jīng)做了緩存,從緩存中輸出圖片,否則進行步驟3
3. 從Storage Service中提取原始圖片
4. 檢查客戶端的參數(shù)請求,如果包括圖片轉換命令,則提交到Image Processor,否則調到步驟7
5. 調用圖片處理的各個子部件(resize,crop等)進行圖片轉化的工作
6. 將處理結果提交給Cache Service
7. 輸出圖片
到目前為止,我們還沒有對Storage Service動手術,不過對于一般性的應用,到這個階段已經(jīng)足夠了,而下一步我們將討論更大數(shù)據(jù)量的存儲,看看應該在那些環(huán)節(jié)上繼續(xù)調整。
我們的所有討論都是限制在一臺PC Server上討論的,后續(xù)我們要嘗試把原始圖片的存儲和前端服務分離。
歡迎光臨 Chinaunix (http://72891.cn/) | Powered by Discuz! X3.2 |