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

從圖上可以看到,針對(duì)圖片服務(wù)我們做了一些抽象,Cache Service負(fù)責(zé)所有涉及到緩存的管理,而Image Processor負(fù)責(zé)圖片的轉(zhuǎn)換服務(wù),Image Service會(huì)利用這三個(gè)核心的組件協(xié)同工作,把原圖片存儲(chǔ)的工作交給Storage Service來完成,將圖片轉(zhuǎn)換的工作交給Image Processor,將緩存的工作交給Cache Service來處理。
到此,我們能夠清晰地描述圖片服務(wù)的工作流程了:
1. 接受瀏覽器的請(qǐng)求
2. 提交給緩存服務(wù),如果已經(jīng)做了緩存,從緩存中輸出圖片,否則進(jìn)行步驟3
3. 從Storage Service中提取原始圖片
4. 檢查客戶端的參數(shù)請(qǐng)求,如果包括圖片轉(zhuǎn)換命令,則提交到Image Processor,否則調(diào)到步驟7
5. 調(diào)用圖片處理的各個(gè)子部件(resize,crop等)進(jìn)行圖片轉(zhuǎn)化的工作
6. 將處理結(jié)果提交給Cache Service
7. 輸出圖片
到目前為止,我們還沒有對(duì)Storage Service動(dòng)手術(shù),不過對(duì)于一般性的應(yīng)用,到這個(gè)階段已經(jīng)足夠了,而下一步我們將討論更大數(shù)據(jù)量的存儲(chǔ),看看應(yīng)該在那些環(huán)節(jié)上繼續(xù)調(diào)整。
我們的所有討論都是限制在一臺(tái)PC Server上討論的,后續(xù)我們要嘗試把原始圖片的存儲(chǔ)和前端服務(wù)分離。 |