网站若是有不少用户上传图片(相册,商品图片),通常的作法是将用户图片保存在磁盘上面(数据库中记录图片的地址)。用户上传的时候按照原图、中图、小图等各个尺寸都生成一份保存在磁盘上。好比php的网店系统echsop就是这么作的,而shopex之类也大同小异。php
这种作法也不是不能够。多生成几个尺寸,在磁盘上无非多存储几份而已,磁盘如今也便宜。html
不过,有个问题:运营部常常须要不少尺寸版本的图片,好比须要80*80,又须要70*80,各个版面随着活动的须要,尺寸每每不一样。有些一张图片可能须要根据不一样的应用场景提供的图片尺寸不一样,假设统计一下有几十种不一样尺寸的缩略图。难道生成20张保存在磁盘上?磁盘价格当然白菜价。可是要考虑大量图片请求致使的磁盘读写的性能问题。nginx
后来发现,随着流量大,尤为并发访问大,图片很是多的时候,频繁的读写,图片存储在磁盘上,磁盘磁头频繁定位形成的延时。程序员
后面我了解到,业界比较成熟的作法是实时生成缩略图。也就是传递尺寸,当时就生成(生成也能够保存在磁盘上,以备下回须要的时候继续使用,也能够不保存,本身控制),这样子在磁盘上就不用保存不少份了。web
看过淘宝网对本身图片存储的介绍:http://news.cnblogs.com/n/73189/shell
了解到以下关键点:数据库
淘宝网的图片文件数量达到286亿多个,这些图片文件包括根据原图生成的缩略图。平均图片大小是17.45K;8K如下图片占图片数总量的61%,占存储容量的11%。编程
这就给淘宝网的系统带来了一个巨大的挑战,众所周知,对于大多数系统来讲,最头疼的就是大规模的小文件存储与读取,由于磁头须要频繁的寻道和换道,所以在读取上容易带来较长的延时。在大量高并发访问量的状况下,简直就是系统的噩梦。安全
实时生成缩略图的好处总结以下:服务器
一、节省存储空间。虽然如今磁盘确实很便宜。1g的成本很低。可是毕竟仍是须要钱的。更关键一点是,图片保存在磁盘上读取时磁头频繁定位的性能问题(服务器实时生成消耗的应该是cpu资源,cpu速度很快)
图片越多时,问题越大。
二、更加灵活响应运营部的多尺寸图片需求。好比有些一张图片可能须要根据不一样的应用场景提供的图片尺寸不一样,假设统计一下有几十种不一样尺寸的缩略图。难道生成20张保存在磁盘上?
程序员确实不用纠结保存多少份的问题了。
有些图片尺寸,只会用到一次,好比作活动使用一次,后面可能永远都不会被用到。不必在上传图片的时候消耗cpu资源去生成,浪费磁盘空间去存储
仍是同样,图片种类越多,这个问题越明显。图片就那么点点就没问题(好比就是存储用户头像而已,而商品图片就会用到不少尺寸的版本)
淘宝网提到了他们使用GraphicsMagick进行图片处理。
搜索到的资料以下
一、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. 取得一些图片的特性信息
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,针对图片还要进行备份。同一张图片分为不一样的尺寸。这样占据的空间比较麻烦。
基于存储成本考虑。使用动态生成图片尺寸的方式。
使用了第三方的图片存储,没有本身搭建服务来生成尺寸。之因此使用第三方,由于他们有cdn加速服务,图片能够就近节点存储,用户访问能够就近节点进行访问图片。
目前的硬盘24t。快占满了。