1 介绍
现在很多的网站上都会用到大量的图片,而图片是网页传输中占主要的数据量,也是影响网站性能的主要因素。因此很多网站都会将图片存储从网站中分离出来,另外架构一个或多个服务器来存储图片,将图片放到一个虚拟目录中,而网页上的图片都用一个URL地址来指向这些服务器上的图片的地址,这样的话网站的性能就明显提高了,图片服务器(ImageServer)的概念也就产生了。
1.1 图片服务器的优势
1, 分担Web服务器的I/O负载-将耗费资源的图片服务分离出来,提高服务器的性能和稳定性。
2, 能够专门对图片服务器进行优化-为图片服务设置有针对性的缓存方案,减少带宽成本,提高访问速度。
3, 提高网站的可扩展性-通过增加图片服务器,提高图片吞吐能力。
1.2 图片服务器的注意事项
1, 选择适合图片存储的物理介质和文件系统
2, 使用物理上独立的服务器
3, 如果拥有多台图片服务器,要考虑服务器之间的图片同步问题
4, 使用独立域名
5, 制定合理的缓存策略
6, 使用图片处理模块对用户上传的图片进行再加工
1.3 图片服务器的架构
图片是网站中必不可少的一个组成部分,随着网站的不断发展,对图片的处理也将随着访问的增长,图片的增加提出不断改进的需求, 网站初期,所有的一切都从简图片所存在的位置通常会在站点下的Images文件夹。
随着访问的增加,IIS压力的增大,开始做拆分,将图片文件夹作为单独站点提取出来如http://images.***.com/(可能根据需要会拆分成多个图片服务器,与具体业务环境相关),拆分之后很好的将单个IIS应用池的压力分担到2个乃至多个上,大大提高访问瓶颈。随着访问的进一步增加,服务器压力已经无法支撑,这时我们需要将图片站点作为独立服务器存在。在访问图片的过程中,我们可能会面临一个图片有多个图片尺寸的需求,前期我们通常会在保存页面的过程中保存我们需要的各个尺寸图片,但随着所需尺寸的不同,保存图片时需要的尺寸越来越多,这时我们如何应对?
IIS服务器的并发访问意味着随着用户的进一步增加,我们单台图片服务器已经不足以应对了,此时我们如何进一步扩展?
如上图所示,我们此时可针对这两个问题做出统一解决方案,在前端添加squid缓存服务器,添加一台或者多台动态切图服务器。Squid或者Nginx代理缓存服务器能够极大的提升图片系统的并发访问,使系统突破现有限制。动态切图服务器主要的作用是针对不同尺寸的图片访问调取原图临时生成符合需求的图片并返回。原图的存储区可以与图片服务放在一起,也可以讲图片放于单独的服务器上。
在此种结构中,并发的最大访问限制将是squid或者其他代理服务器的系统瓶颈,当切图服务压力增大时,只需添加相应切图服务器即可,图片存储区的增长也可通过添加硬盘或者服务器进行解决。
如果您的站点访问量还在进一步增长,squid的访问瓶颈即将被突破,这时我们又该如何应对呢?
如上图所示,采用多台Squid或Nginx服务器,在前端添加F5或LVS负载均衡(同时还可开启缓存功能)。此时将极大提升访问的并发量,可以根据情况随时调配服务器。当然此时也存在一定的瑕疵,那就是可能在多台Squid上存在同一张图片,因为访问图片时可能第一次分到squid1,在F5过期后第二次访问到squid2或者别的,当然相对并发问题的解决,此种少量的冗余完全在我们的允许范围之内。在做了这许多的工作后,如果条件允许对图片服务器做下CDN,那将会对您站点的图片访问质量有更大的提升。
1.4 图片存储架构
1.4.1 部署独立图片服务器的必要性
我们知道,无论对于Apache还是IIS,图片始终是最消耗系统资源的,如果将图片服务和应用服务放在同一个服务器的话,应用服务器很容易会因为图片的高I/O负载而崩溃,因此对于有些大型网站项目,我们有必要将图片服务器和应用服务器分离。部署独立的图片服务器(甚至是服务器集群)是大型网站图片存储解决方案中最基础的,因为有了独立的图片服务器后,我们才能对图片服务器做更有针对性的性能优化,比如从硬件角度说,图片服务器可以配置高端的硬盘,7200转的换成15000转的,而CPU却只要一般就可以了;从软件角度说,可以为图片服务器配置特殊的文件系统来满足对图片的I/O请求,如淘宝的TFS,就很好地解决了大规模小图片文件带来的I/O噩梦,同时,我们也可以采用nginx、squid来代理图片请求等等。
1.4.2 采用独立域名
注意,这里是指独立域名,不是子域哦,比如yahoo.com图片服务器用了yimg.com的域名,而不是用二级域名img.yahoo.com,这是为什么呢?个人觉得原因主要有以下几点:
1、同一域名下浏览器的并发连接数有限制,一般在2 - 6之间,下图列举了各个浏览器的并发连接数(下图供参考)
这样,我们如果给图片服务器配置独立的域名,那么在一个页面中加载图片时,就可以突破浏览器连接数的限制,理论上,增加一个独立域名,并发连接数加倍。
2、由于cookie的原因,对缓存不利
比如有一张图片http://www.test.com/img/xx.gif,那么当我们向它发起请求的时候,会带上www.test.com域名下的cookie,由于大部分web cache都只缓存不带cookie的请求,这样就导致每次的图片请求都不能命中cache,而仍旧要去原始服务器获取图片,导致图片缓存意义不大。所以,还是给单独搞一个图片独立域名吧,当然,不只是图片,css和js文件也可以参照这个思路来搞。
3、方便CDN同步
1.4.3 图片服务器分离后,如何进行图片上传和图片同步
当然任何事物都具有两面性,图片服务器分离固然提升了图片访问的效率,大大缓解了服务器因图片造成的I/O瓶颈,但是分离以后图片的上传和同步就成了一个大问题了。下面就我个人的想法谈谈几种解决方案。
1、NFS共享方式
如果你不想在每台图片服务器同步所有图片,那NFS共享是最简单也最实用的方式。NFS是个分布式的客户机/服务器文件系统,NFS的实质在于用户间计算机的共享,用户可以联结到共享计算机并象访问本地硬盘一样访问共享计算机上的文件。
具体实现思路是:web服务器通过nfs挂载多台图片服务器export出来的目录,用户先将图片上传到web服务器,然后将上传的图片通过程序拷贝到这个mount目录中去,这样那几台图片服务器就也能访问到刚上传的图片了(注意,只是共享了,并没有真正拷贝到图片服务器)。再给那几台图片服务器绑定独立域名,于是浏览器端就可以用单独的域名来访问图片了。这种方式基本不会有因同步造成的延时,但需要依赖nfs,nfs挂掉会影响web服务器。如下图
至于如何配置nfs,大家google一下,或者看一下这篇文章,是在Linux下配置NFS的
2、利用FTP同步
和上面nfs不一样的是,用户上传完图片后是利用ftp同步到各个图片服务器的,php、java、asp.net基本上都能操作ftp。这样的话每个图片服务器就都保存一份图片的副本,也起到了备份的作用。但是缺点是将图片ftp到服务器比较耗时,如果异步去同步的话又会有延时,不过一般的小图片文件也还好了。
2 图片服务器的URL HASH架构剖析
2.1 什么是url hash 架构
url hash架构对url进行一次hash算法,然后通过hash结果找到对应的服务器。因为针对单一个url的hash结果是一样的,所以理论上这个url会被永久分配到固定的一台服务器上。另外因为经过了hash算法,所以分配url就很均匀,同时访问量也可以达到均衡。
2.2 为什么要用url hash架构
1, 图片服务器的特点一是访问量很大,二是容量也很大,通过简单的负载均衡,可以解决访问量大的问题,但是容量的问题并没有改善。所以会造成容灾问题。
2, 容灾问题:系统某个时间段被访问的数据严重超出缓存集群中最小单机的容纳容量就会造成容灾,容灾会使大量单一链接穿透,直接对后台的IO性能影响很大。
3, 虽然可以通过增加缓存容量的配置来解决容灾问题,但是内存总是有限的,为每一台机器增加超大内存成本上也开销很大,另外在squid中也不宜配置很大的磁盘缓存,否则squid中的hash表会很大,性能很差。
4, 通过hash架构,可以充分利用缓存集群的内存,容灾问题就不再取决于缓存集群中最小单机的容纳容量,而是缓存集群中所有机器的容纳容量之和。
2.3 各种url hash架构
1)基于dns的hash架构。
2)基于nginx的自动hash架构。
3)基于nginx的手动hash架构。
2.3.1 基于dns的hash架构
dns的hash架构图
dns的hash架构说明
这个架构适合面向用户的图片系统,比如论坛、相册、博客中的图片上传。这样它才能够保证文件名有一致的规范。
这个架构图分了36个域名,图片文件名是用md5值起的,在md5值中取一位字母就可以表明它是在哪个域名里,域名就对应了机器,上传分发的时候也是根据此字母来分发。
dns的hash架构的优缺点
优点:
1)使用了dns分流,成本较低,而且dns性能高,不用维护。
2)可突破IE默认每主机2个线程的限制。
缺点:
1)可用性方面,如果有一台机器宕机,则指向这台机器的请求无法读取。
2)分流方面,只能全部同步,成本较高
3)只适用于面向用户的系统
2.3.2 基于nginx的自动手动hash架构
nginx的自动hash架构图
nginx的自动hash架构说明
这是一种新的缓存架构,由nginx作为最前端,代理到缓存机器。
后面是缓存组,由nginx经过url hash后将请求分到缓存机器。
这个架构方便纯squid缓存升级,可以在squid的机器上加装nginx。
有缓存的功能,可以将一些访问量特大的链接直接缓存在nginx上,就不用经过多一次代理的请求。比如favicon.ico和网站的logo。
nginx的自动hash架构优缺点
优点
)高性能
)使用方便,后台是什么样关系不大
)有很高的可用性
)缓存架构,分流方便
)可直接在nginx代理缓存部分链接
缺点
分流可控性弱,增减缓存机器都会引起缓存重新分配,意味着缓存全部失效。
nginx的手动hash架构说明
,这个架构图和自动hash的架构是一样的,唯一有差别的是hash算法的变化,自动hash是用nginx upstream hash模块自带的hash算法来实现分流,这个手动架构是自己设计一个算法来实现。
,算法设计思路是从url中取一个字符来作分流依据,比如定义链接的倒数第10个字符来分流,同样可以分配得很均匀。
,手动架构可以避免自动架构中增减机器带来的缓存失效问题,另外可以精确知道一个链接到底存在哪台缓存上。
nginx的手动hash架构优缺点
优点
)基本可以继承自动架构的优点
)避免增减机器的问题
)精确知道链接存储在哪台缓存上
缺点
配置较复杂,要分配均匀配置不易。
Hash架构对bbs架构优化
,先前讲的bbs架构采用的是lvs+squid作为前端,这样的话squidclient更新缓存时需要更新所有的squid,这个效率很低下,使用hash架构就可以使squidclient每次只需要清理一台squid,效率大为提升。
,推荐的是使用nginx手动hash架构,它可以精确知道链接会存在哪台机器上,这样就可以配置精确的备份机器。
3 nginx图片服务器的架构方案
图片服务通常数据容量较大,而且访问也频繁,鉴于此,图片服务就会有两种问题,一是存储问题,二是访问量问题。
存储问题就是硬盘容量问题, 花钱买硬盘就可以了,看似简单,但着实也是最苦的问题。按目前探索来看,最好的方式是:在任何时刻遇到硬盘空间不够时,买颗硬盘插上,最多改改配置,就能 立刻利用;另外,硬盘要能充分利用,不然图片存储量大再加上备份,很恐怖,最好是每颗硬盘都用上100%的空间。
访问量也是个大问题,如 果服务不允许防盗链,那么访问量会引起带宽、服务器压力等问题,有钱的话直接扔CDN,没钱或者有更多的钱,就自己做吧。根据垣古不变的真理“越老的图, 访问量也相对较少”这一点,分成两大部分,一边处理最新的图片,一边处理老旧的图片。最新的图片访问量大,但存储量较少;老图片访问量低,但存储量大。
3.1 拟定一个存储目录规则
/a/b/abcde.jpg这样的hash方式下多加一个日期的目录变成:/200810/16/a/b/abcde.jpg或者/2008/10/16/a/b/abcde.jpg。按日期制定这个目录规则后,就可以按年月来拆机器了。
3.2 分机器,分硬盘
lvs做负载均衡负责新图片;另一组服务器做旧图片访问和备份。新图机器找几台好点的服务器,SCSI硬盘;旧图机 器没太大要求,PC机就行,找够硬盘就可以,现在IDE的1T硬盘也不太贵,最好再搭个raid就省事了,最主要是这些机器要多。如下图:
说明一下:
1、图片服务通过lvs作为入口,处理能力上还是有保障的。
2、利用nginx直接对外服务,不必用squid。
3、图中的红线是指主nginx会将/2006和/2007年的图片分别代理到两台存档服务器,如果发现主nginx的cpu占用比较大,那么可以考虑使用nginx的proxy_store将图片存到主服务器上,定期清理。
4、图中有一台存储分配服务器,作为图片服务更新图片的统一入口,有新图片或者修改图片的话,由这台服务器负责将图片放到正确的服务器上去。
5、旧图片服务器当前用年份来划分,每年增加两台服务器,亦可是加两块硬盘,注意,不要相信raid,一定要有两台机器,地理上分在两个城市则更好。
6、因为旧数据2006和2007年的数据基本上是没有变化的,所以假如硬盘够大,那么可以把两年的数据合并在一起。
7、如果细心定制,那么旧图片服务器的硬盘100%塞满是可以的,旧数据的容量基本上不会大幅增长,小小预留1-2G空间就可以了。