網站如果有很多用戶上傳圖片(相冊,商品圖片),一般的做法是將用戶圖片保存在磁盤上面(數據庫中記錄圖片的地址)。用戶上傳的時候按照原圖、中圖、小圖等各個尺寸都生成一份保存在磁盤上。比如php的網店系統echsop就是這么做的,而shopex之類也大同小異。
這種做法也不是不可以。多生成幾個尺寸,在磁盤上無非多存儲幾份而已,磁盤現在也便宜。
不過,有個問題:運營部經常需要很多尺寸版本的圖片,比如需要80*80,又需要70*80,各個版面隨着活動的需要,尺寸往往不同。有些一張圖片可能需要根據不同的應用場景提供的圖片尺寸不同,假設統計一下有幾十種不同尺寸的縮略圖。難道生成20張保存在磁盤上?磁盤價格固然白菜價。但是要考慮大量圖片請求導致的磁盤讀寫的性能問題。
后來發現,隨着流量大,尤其並發訪問大,圖片非常多的時候,頻繁的讀寫,圖片存儲在磁盤上,磁盤磁頭頻繁定位造成的延時。
后面我了解到,業界比較成熟的做法是實時生成縮略圖。也就是傳遞尺寸,當時就生成(生成也可以保存在磁盤上,以備下回需要的時候繼續使用,也可以不保存,自己控制),這樣子在磁盤上就不用保存很多份了。
看過淘寶網對自己圖片存儲的介紹:http://news.cnblogs.com/n/73189/
了解到如下關鍵點:
淘寶網的圖片文件數量達到286億多個,這些圖片文件包括根據原圖生成的縮略圖。平均圖片大小是17.45K;8K以下圖片占圖片數總量的61%,占存儲容量的11%。
這就給淘寶網的系統帶來了一個巨大的挑戰,眾所周知,對於大多數系統來說,最頭疼的就是大規模的小文件存儲與讀取,因為磁頭需要頻繁的尋道和換道,因此在讀取上容易帶來較長的延時。在大量高並發訪問量的情況下,簡直就是系統的噩夢。
實時生成縮略圖的好處總結如下:
1、節省存儲空間。雖然現在磁盤確實很便宜。1g的成本很低。但是畢竟還是需要錢的。更關鍵一點是,圖片保存在磁盤上讀取時磁頭頻繁定位的性能問題(服務器實時生成消耗的應該是cpu資源,cpu速度很快)
圖片越多時,問題越大。
2、更加靈活響應運營部的多尺寸圖片需求。比如有些一張圖片可能需要根據不同的應用場景提供的圖片尺寸不同,假設統計一下有幾十種不同尺寸的縮略圖。難道生成20張保存在磁盤上?
程序員確實不用糾結保存多少份的問題了。
有些圖片尺寸,只會用到一次,比如做活動使用一次,后面可能永遠都不會被用到。沒必要在上傳圖片的時候消耗cpu資源去生成,浪費磁盤空間去存儲
還是一樣,圖片種類越多,這個問題越明顯。圖片就那么點點就沒問題(比如就是存儲用戶頭像而已,而商品圖片就會用到很多尺寸的版本)
淘寶網提到了他們使用GraphicsMagick進行圖片處理。
搜索到的資料如下
1、ImageMagick:ImageMagick是一套功能強大、穩定而且開源的工具集和開發包,可以用來讀、寫和處理超過89種基本格式的圖片文件
利用ImageMagick,你可以根據web應用程序的需要動態生成圖片, 還可以對一個(或一組)圖片進行改變大小、旋轉、銳化、減色或增加特效等操作,並將操作的結果以相同格式或其它格式保存,對圖片的操作,即可以通過命令行進行,也可以用C/C++、Perl、Java、PHP、Python或Ruby編程來完成。
功能如下:
1. 將圖片從一個格式轉換到另一個格式,包括直接轉換成圖標。
2. 改變尺寸、旋轉、銳化(sharpen)、減色、圖片特效
3. 縮略圖片的合成圖( a montage of image thumbnails)
4. 適於web的背景透明的圖片
5. 將一組圖片作成gif動畫,直接convert
6. 將幾張圖片作成一張組合圖片,montage
7. 在一個圖片上寫字或畫圖形,帶文字陰影和邊框渲染。
8. 給圖片加邊框或框架
9. 取得一些圖片的特性信息
2、 GraphicsMagick
GraphicsMagick 支持大圖片的處理,並且已經做過GB級別的圖像處理實驗。GraphicsMagick能夠動態的生成圖片,特別適用於互聯網的應用。可以用來處理調整尺寸、旋轉、加亮、顏色調整、增加特效等方面
也支持C、C++、Perl、PHP、Tcl、 Ruby等的調用。事實上,GraphicsMagick是從 ImageMagick 5.5.2 分支出來的,但是現在他變得更穩定和優秀,下面就是兩個之間的一些比較。
GM更有效率(測評),能更快的完成處理工作
GM更小更容易安裝
GM已經被Flickr和Etsy使用,每天處理百萬計的圖片
GM與已經安裝的軟件不會發生沖突
GM幾乎沒有安全問題
GM的手冊非常豐富
使用GraphicsMagick常見的做法是:單獨一台圖片服務器用來響應生成縮略圖的請求。nginx+GraphicsMagick+lua結合起來。圖片服務器上安裝nginx,nginx調用lua程序,讓lua程序來執行shell命令(GraphicsMagick原本就是可以通過shell命令來調用的,這里就是讓lua來調用),大體像下面這樣子:
location ~ '/images/([0-9a-z]+)_([0-9]+)x([0-9]+).jpg$' {
root /home/images;
set $image_root = '/home/images';
set $fileName = ngx.arg[1];
set $width = ngx.arg[2];
set $height = ngx.arg[3];
set $origin = $image_root/$fileName.jpg
set $file = $image_root/$fileName_$widthx$height.jpg
#請求的圖片尺寸不存在 ,就實時生成,並且保存一份到磁盤上備下回使用
if (!-f $file) {
rewrite_by_lua '
local command = "gm convert "..ngx.var.origin.." -thumbnail "..ngx.var.width.."x"
..ngx.var.height.." "..ngx.var.file;
os.execute(command);
';
# rewrite_by_lua右邊的單引號里面是lua程序語法。里面關鍵就是os.execute執行一條命令。這條命令就是調用GraphicsMagick
}
這里有篇好文章,專門分析亞馬遜是如何保存圖片的(其實也是實時生成縮略圖的方式):
http://aaugh.com/imageabuse.html
不過是純英文的。
其實大部分網站通過實時生成圖片應該能夠滿足需求了。達到淘寶那樣子需要研發自己的cdn圖片網絡環境,很少公司達到。
有個理論性的東西比較重要:
對數據庫的讀/寫的速度永遠都趕不上文件系統處理的速度。所以把圖片文件丟到磁盤上讓文件系統來維護比較好。只是磁盤頻繁的定位造成的速度慢又是一個問題,呵呵。不過,只是並發訪問量大的時候才會出現。沒到極限不必擔心,避免過度設計。
我寫這篇文章,就是預留以后遇到這種問題,備個解決方案。
15年更新:
恰好進入的一家公司,圖片存儲占用的磁盤空間大。有幾十個t,針對圖片還要進行備份。同一張圖片分為不同的尺寸。這樣占據的空間比較麻煩。
基於存儲成本考慮。使用動態生成圖片尺寸的方式。
硬盤就保存原圖。如果需要a尺寸,b尺寸。傳遞參數,當時生成一個返回,硬盤不保存多個尺寸的圖。
使用了第三方的圖片存儲,沒有自己搭建服務來生成尺寸。之所以使用第三方,因為他們有cdn加速服務,圖片可以就近節點存儲,用戶訪問可以就近節點進行訪問圖片。
目前的硬盤24t。快占滿了。