2011年(13)
分类: 系统运维
2011-01-23 19:34:12
我们在上一篇里拓展了图片服务的后台存储架构,从性能和可管理性做了一些优化和调整,但对于真正面向用户的图片服务却避而不谈,一台机器存储不够了,我们可以扩展,一台图片服务器不够了,我们又当如何拓展?
我们知道,图片服务的瓶颈在于网络带宽、图片转换处理的CPU耗费,如果是静态文件,会涉及到磁盘IO,如果是内存缓存,会涉及到内存。
您可以用任何你喜欢的语言去实现图片服务,然后让它跑在自己喜欢的操作系统上,我也没有办法去评判不同语言和平台之间的优劣,但是我们可以尝试着探讨在Windows和Linux下的具体实现。
在Windows上跑IIS+ASP.NET 2.0,估计没有人会反对如此做吧?这里的Windows是指Windows Server 2003 SP2,IIS则是6.0的,这也是目前主流的Windows服务器版本,当然了,如果有兴趣关心Windows 2008和脱胎换骨的IIS 7.0,那会有新的解决方案了。
而在Linux下则是推荐用php来作为实现语言,有人则会疑问为何不采用Java或者Python、Ruby之类的动态语言,我的理由是因为图片服务的特点,它需要高可靠、高性能,业务不会太过复杂,并且几乎不用考虑数据对象之间的业务关联,从执行效率上来说,php无可挑剔,同时很容易地和主流的web服务器如Apache、Nginx、lighttpd等通过fastcgi集成,同时解释执行的方式不会让导致内存溢出的问题。
一) 从一台应用服务器变成多台负载均衡,我需要考虑什么?
首先需要考虑的问题是负载均衡,也就是将流量的压力平衡到多台服务器,从技术上有很多可以选择的方案来实现您的负载均衡:
1. DNS轮询:这是最简单的方式,把img.websecretapp.com指向多个IP地址,大多域名解析提供商都会提供这样的服务,但是因为不能够实时地管理服务器状态(比如某一台服务器出现问题了,dns解析还是会继续),对于大多web 2.0网站,也不是推荐采用如此。
2. 硬件负载均衡:如果你有足够的预算,采用硬件来解决是最好不过了,目前市场上最成熟的莫过于F5和Radware,至于采用怎样级别的设备,那就根据你自身业务和预算而定了。
3. 软件负载均衡:对于预算有限的互联网公司,是大多架构师推崇的解决方案。我们也只将讨论使用软件来实现负载均衡。
如果只熟悉Windows系统,可以使用Windows 自带的NLB(Network Load Balancing) 来实现主机级别的负载均衡,而Linux下,你可以使用LVS(Linux Virtual Server)来实现主机级别的负载均衡。解释一下什么叫着“主机级别”,简单地说是基于IP路由的,也就是在IP层将指向同一个IP地址的流量根据策略路由到多台后端的机器。
对于大多软件架构是来说,更加熟悉的是在应用层面的负载均衡,在Windows上并没有太多成熟的可选择方案,大多的解决方案都是基于Linux的。为了实现这个目的,我们首先需要一个负载均衡服务器软件,通过反向代理的方式将用户的请求无缝地转发到实际的应用服务器(也就是我们真实的图片服务器),你可以用Apache、Nginx或者Lighttpd这样的Http服务器来作为你的反向代理服务器,如果不是有其他的应用要承载在这台服务器上,Apache并不是一个好的选择,因为它令人称垢的内存占用问题。Nginx和Lighttpd是不错的选择,至于具体选择哪个,就依赖于自己的熟悉程度了。
因为我们的服务大多是图片数据,如果不是出于特定的考虑,我想并不会对每次图片的查看进行安全检查吧?(当然了,如果你的整个服务是收费的,那是例外),这时候我们可以考虑使用Http缓存服务器Squid来作为负载均衡器。
是选用轻量级的http服务器还是squid,还是根据你的业务来确定,如果你只是想转发请求的话,用轻量级的http服务器,如果想缓存内容的话,可以用Squid。
Windows上面是不是就无能为力了呢?答案是否定的,首先你选择前端来转发请求,不代表着你后台不可以是windows服务器,即便你的所有应用都是架设在windows上,同样也可以用squid或者nginx在前端作为反向代理服务器。
如果你有幸使用Windows Server 2008的话,可以用ARR(Application Request Routing)和URL Rewrite模块来实现负载均衡,而不是依赖于你不熟悉的Linux。
关于负载均衡的实现问题,我不想去讨论太多,如果有兴趣深入了解的,可以去阅读《》,会让你对负载均衡有一个更加全面的了解,网络上也有很多关于混在均衡的介绍。
二) 使用了负载均衡之后,我怎样去保证我的数据是同步的?
这就需要回过头来看负载均衡的算法,从大的的角度来说可以分成持续性的和非持续性两种,持续性指一个特定的客户端发出的请求都被分配到一个实服务组中的同一个实服务器上进行处理,非持续性是指个客户端的不同的请求可能被分配到一个实际服务组中的不同的实服务器上进行处理。界定是否需要使用持续性的原则很简单,那就是客户端请求是否有业务状态需要在服务器端维护。
在没有特殊考虑的情况下,我建议是使用非持续性的,因为那样的假设能够简化很多问题,与此同时负载均衡的成本会比较低。而非持续性算法中最简单的莫过于轮询(Round Robin)算法,也就是随机的将请求转发到真实的服务器(real server)上。
在 这种情况下依旧会出现问题,可别忘记了我们在文章的前头为图片服务器增加了缓存的功能,这时候就存在图片缓存不同步的情况。从业务的角度来说,我们允许图 片服务器各自重新进行图片处理,从而生成自己的缓存,但如果图片数量比较大的话,同时又选择在图片服务器生成本地文件的缓存,就会导致图片服务器需要大量 的磁盘空间。我们可以选择下面的策略来避免这种冲突:
1. 对于频繁访问的小图片,可以通过以下的集中方式实现服务器之间的共享,从而避免重复生成缓存
a) :将所有的图片数据放在memcached中,图片服务器共享访问这些数据
b) 数据库:把图片数据放在键/值对的数据库,如Berkley DB、Tokyo Cabinet等,当然了,放在MySql里也未尝不可,具体方案只有根据你业务的实际压力去测试了
c) 分布式文件系统:比如与MemCached师出同门的,或者
2. 对于中等大小,访问频率不算特别高的图片,要么选择不缓存,每次重新生成,要么和小图片一样的处理方案
3. 对于访问很少,比较大的图片,还是保持之前的策略
在压力非常大的情况下,如果多个应用服务器节点频繁访问图片数据和缓存,也将会导致网络的性能瓶颈,这种情况下可以考虑对前端转发请求的时候是选择性请求,比如依照时间将2007年以前的转发到指定的服务器,将用户大头照转发到另外一台服务器等等,而不是选择最简单的随机轮询策略。
负载均衡的目的是尽可能平衡压力,而选择怎样的算法还是需要根据你具体的业务情况和实际的压力而定,没有一成不变的法则。
三) 应该怎样去确定我的负载均衡和数据存储策略?
文中一直提到的一切以业务实际情况为准而选择适合自己的方案和策略,但是具体是用怎样的角度去判定是否符合业务本身呢?从我自己的理解,有几个重要的参考:
n 所请求图片数据的时间分布:也就是大多用户会访问你何时生成的数据,你应该要对于此有一个清晰的认识,大多情况下像SNS和社区这样的应用,最新上传的图片是访问最大的,为了提高整个服务的性能,你可以考虑将新的图片放在一台单独的服务器上,同时给以比较高的配置。而时间比较久的图片,则可以放在另外机器上。并不是所有的负载均衡都一定要在文件数量上的负载均衡。比如2008年以前的图片用1台服务器,而2008年以后的用3台服务器,虽然从数据量来说这一台需要提供的服务远远大于三台的总和。
n 不同业务的访问量:说到根本,你还是要清楚地知道用户到底请求了哪些图片,比如博客文章的照片和用户大头照比较起来,显然是用户的头像照片会有更大的访问量,那么调整的重点就应该放在用户大头照这块
n 缓存命中率:这是一个非常重要的指标,你需要清楚地知道将图片缓存之后被请求命中的概率,如果一个图片被频繁请求,除了第一次生成,后续的都从发缓存中去取,比如之后被后续请求999次,这时的缓存命中率是99.9%,你绝对需要为此去做缓存,而如果之后只有一次请求,也就是只有50%的命中率,甚至不请求,这时你需要考虑是否有必要为此作缓存了。原则上来说,如果你的请求目标非常分散,而且单一数据的请求次数很低,缓存就不是绝对必要
文 章到此我们已经讨论了一个图片服务在服务端实现的方方面面,也有人会问到一个图片服务有必要设计的如此复杂吗?我的回答还是以你的业务需求为准则,可能在 文章的第一篇您就可以停下来,因为已经满足您的业务需求,也可能是走到第二篇,第三篇,而不是现在的第五篇。我只是渐进式地探讨了一个从非常简单的服务开 始到逐步深入,逐步复杂的互联网应用的完整过程,同时从自己的理解提出了一些需要考虑的方面。如果说本文的第一步分是提出了业务需求,那么后续的逐步完善 则展现了我对大规模互联网应用的理解,也是从程序通往体系结构的演变之路。
我还会用一个篇幅去探讨在前端用户体验的一些实现,虽然没有什么技术含量,但是对于终端用户的体验来说,将会更有意义。