• UID12
  • 登录2016-06-14
  • 粉丝111
  • 关注50
  • 发帖1415
  • 主页
  • 金币8540枚
社区居民
最爱沙发
忠实会员
喜欢达人
原创写手
极分享 发布于2015-08-14 11:27
0/1796

大型网站图片服务器架构的演进

楼层直达
在主流的Web站点中,图片往往是不可或缺的页面元素,尤其在大型网站中,几乎都将面临“海量图片资源”的存储、访问等相关技术问题。在针对图片服务器的架构扩展中,也会历经很多曲折甚至是血泪教训(尤其是早期规划不足,造成后期架构上很难兼容和扩展)。

本文将以一个真实垂直门户网站的发展历程,向大家娓娓道来。

构建在Windows平台之上的网站,往往会被业内众多技术认为很“保守”,甚至会有点。很大部分原因,是由于微软技术体系的封闭和部分技术人员的短视造成的(当然,主要还是人的问题)。由于长期缺乏开源支持,所以很多人只能“闭门造车”,这样很容易形成思维局限性和短板。以图片服务器为例子,如果前期没有容量规划和可扩展的设计,那么随着图片文件的不断增多和访问量的上升,由于在性能、容错/容灾、扩展性等方面的设计不足,后续将会给开发、运维工作带来很多问题,严重时甚至会影响到网站业务正常运作和互联网公司的发展(这绝不是在危言耸听)。

很多公司之所以选择Windows(.NET)平台来构建网站和图片服务器,很大部分由创始团队的技术背景决定的,早期的技术人员可能更熟悉.NET,或者团队的负责人认为Windows/.NET的易用性、“短平快”的开发模式、人才成本等方面都比较符合创业初期的团队,自然就选择了Windows。后期业务发展到一定规模,也很难轻易将整体架构迁移到其它开源平台上了。当然,对于构建大规模互联网,更建议首选开源架构,因为有很多成熟的案例和开源生态的支持(也会有很多坑,就看是你自己最先去踩坑,还是在别人踩了修复之后你再用),避免重复造轮子和支出高额授权费用。对于迁移难度较大的应用,个人比较推荐Linux、Mono、Jexus、Mysql、Memcahed、Redis……混搭的架构,同样能支撑具有高并发访问和大数据量等特点的互联网应用。

单机时代的图片服务器架构(集中式)

初创时期由于时间紧迫,开发人员水平也很有限等原因。所以通常就直接在website文件所在的目录下,建立1个upload子目录,用于保存用户上传的图片文件。如果按业务再细分,可以在upload目录下再建立不同的子目录来区分。例如:upload\QA,upload\Face等。

在数据库表中保存的也是”upload/qa/test.jpg”这类相对路径。

用户的访问方式如下:

http://www.yourdomain.com/upload/qa/test.jpg

程序上传和写入方式:

程序员A通过在web.config中配置物理目录D:\Web\yourdomain\upload  然后通过stream的方式写入文件;

程序员B通过Server.MapPath等方式,根据相对路径获取物理目录  然后也通过stream的方式写入文件。

优点:实现起来最简单,无需任何复杂技术,就能成功将用户上传的文件写入指定目录。保存数据库记录和访问起来倒是也很方便。

缺点:上传方式混乱,严重不利于网站的扩展。

针对上述最原始的架构,主要面临着如下问题:
  • 随着upload目录中文件越来越多,所在分区(例如D盘)如果出现容量不足,则很难扩容。只能停机后更换更大容量的存储设备,再将旧数据导入。
  • 在部署新版本(部署新版本前通过需要备份)和日常备份website文件的时候,需要同时操作upload目录中的文件,如果考虑到访问量上升,后边部署由多台Web服务器组成的负载均衡集群,集群节点之间如果做好文件实时同步将是个难题。
集群时代的图片服务器架构(实时同步)

在website站点下面,新建一个名为upload的虚拟目录,由于虚拟目录的灵活性,能在一定程度上取代物理目录,并兼容原有的图片上传和访问方式。用户的访问方式依然是:

http://www.yourdomain.com/upload/qa/test.jpg
  • 优点:配置更加灵活,也能兼容老版本的上传和访问方式。

因为虚拟目录,可以指向本地任意盘符下的任意目录。这样一来,还可以通过接入外置存储,来进行单机的容量扩展。
  • 缺点:部署成由多台Web服务器组成的集群,各个Web服务器(集群节点)之间(虚拟目录下的)需要实时的去同步文件,由于同步效率和实时性的限制,很难保证某一时刻各节点上文件是完全一致的。

基本架构如下图所示:



在早期的很多基于Linux开源架构的网站中,如果不想同步图片,可能会利用NFS来实现。事实证明,NFS在高并发读写和海量存储方面,效率上存在一定问题,并非最佳的选择,所以大部分互联网公司都不会使用NFS来实现此类应用。当然,也可以通过Windows自带的DFS来实现,缺点是“配置复杂,效率未知,而且缺乏资料大量的实际案例”。另外,也有一些公司采用FTP或Samba来实现。

上面提到的几种架构,在上传/下载操作时,都经过了Web服务器(虽然共享存储的这种架构,也可以配置独立域名和站点来提供图片访问,但上传写入仍然得经过Web服务器上的应用程序来处理),这对Web服务器来讲无疑是造成巨大的压力。所以,更建议使用独立的图片服务器和独立的域名,来提供用户图片的上传和访问。

独立图片服务器/独立域名的好处

  • 图片访问是很消耗服务器资源的(因为会涉及到操作系统的上下文切换和磁盘I/O操作)。分离出来后,Web/App服务器可以更专注发挥动态处理的能力。
  • 独立存储,更方便做扩容、容灾和数据迁移。
  • 浏览器(相同域名下的)并发策略限制,性能损失。
  • 访问图片时,请求信息中总带cookie信息,也会造成性能损失。
  • 方便做图片访问请求的负载均衡,方便应用各种缓存策略(HTTP Header、Proxy Cache等),也更加方便迁移到CDN。
......

我们可以使用Lighttpd或者Nginx等轻量级的web服务器来架构独立图片服务器。

当前的图片服务器架构(分布式文件系统+CDN)

在构建当前的图片服务器架构之前,可以先彻底撇开web服务器,直接配置单独的图片服务器/域名。但面临如下的问题:
  • 旧图片数据怎么办?能否继续兼容旧图片路径访问规则?
  • 独立的图片服务器上需要提供单独的上传写入的接口(服务API对外发布),安全问题如何保证?
  • 同理,假如有多台独立图片服务器,是使用可扩展的共享存储方案,还是采用实时同步机制?

直到应用级别的(非系统级) DFS(例如FastDFS HDFS MogileFs MooseFS、TFS)的流行,简化了这个问题:执行冗余备份、支持自动同步、支持线性扩展、支持主流语言的客户端api上传/下载/删除等操作,部分支持文件索引,部分支持提供Web的方式来访问。

考虑到各DFS的特点,客户端API语言支持情况(需要支持C#),文档和案例,以及社区的支持度,我们最终选择了FastDFS来部署。

唯一的问题是:可能会不兼容旧版本的访问规则。如果将旧图片一次性导入FastDFS,但由于旧图片访问路径分布存储在不同业务数据库的各个表中,整体更新起来也十分困难,所以必须得兼容旧版本的访问规则。架构升级往往比做全新架构更有难度,就是因为还要兼容之前版本的问题。(给飞机在空中换引擎可比造架飞机难得多)

解决方案如下:

首先,关闭旧版本上传入口(避免继续使用导致数据不一致)。将旧图片数据通过rsync工具一次性迁移到独立的图片服务器上(即下图中描述的Old Image Server)。在最前端(七层代理,如Haproxy、Nginx)用ACL(访问规则控制),将旧图片对应URL规则的请求(正则)匹配到,然后将请求直接转发指定的web 服务器列表,在该列表中的服务器上配置好提供图片(以Web方式)访问的站点,并加入缓存策略。这样实现旧图片服务器的分离和缓存,兼容了旧图片的访问规则并提升旧图片访问效率,也避免了实时同步所带来的问题。

整体架构如图:



基于FastDFS的独立图片服务器集群架构,虽然已经非常的成熟,但是由于国内“南北互联”和IDC带宽成本等问题(图片是非常消耗流量的),我们最终还是选择了商用的CDN技术,实现起来也非常容易,原理其实也很简单,我这里只做个简单的介绍:

将img域名cname到CDN厂商指定的域名上,用户请求访问图片时,则由CDN厂商提供智能DNS解析,将最近的(当然也可能有其它更复杂的策略,例如负载情况、健康状态等)服务节点地址返回给用户,用户请求到达指定的服务器节点上,该节点上提供了类似Squid/Vanish的代理缓存服务,如果是第一次请求该路径,则会从源站获取图片资源返回客户端浏览器,如果缓存中存在,则直接从缓存中获取并返回给客户端浏览器,完成请求/响应过程。

由于采用了商用CDN服务,所以我们并没有考虑用Squid/Vanish来自行构建前置代理缓存。

上面的整个集群架构,可以很方便的做横向扩展,能满足一般垂直领域中大型网站的图片服务需求(当然,像taobao这样超大规模的可能另当别论)。经测试,提供图片访问的单台Nginx服务器(至强E5四核CPU、16G内存、SSD),对小静态页面(压缩后大概只有10kb左右的)可以扛住几千个并发且毫无压力。当然,由于图片本身体积比纯文本的静态页面大很多,提供图片访问的服务器的抗并发能力,往往会受限于磁盘的I/O处理能力和IDC提供的带宽。Nginx的抗并发能力还是非常强的,而且对资源占用很低,尤其是处理静态资源,似乎都不需要有过多担心了。可以根据实际访问量的需求,通过调整Nginx的参数,对Linux内核做调优,加入分级缓存策略等手段能够做更大程度的优化,也可以通过增加服务器或者升级服务器配置来做扩展,最直接的是通过购买更高级的存储设备和更大的带宽,以满足更大访问量的需求。

值得一提的是,在“云计算”流行的当下,也推荐高速发展期间的网站,使用“云存储”这样的方案,既能帮你解决各类存储、扩展、备灾的问题,又能做好CDN加速。最重要的是,价格也不贵。

总结,有关图片服务器架构扩展,大致围绕这些问题展开:

  • 容量规划和扩展问题。
  • 数据的同步、冗余和容灾。
  • 硬件设备的成本和可靠性(是普通机械硬盘,还是SSD,或者更高端的存储设备和方案)。
  • 文件系统的选择。根据文件特性(例如文件大小、读写比例等)选择是用ext3/4或者NFS/GFS/TFS这些开源的(分布式)文件系统。
  • 图片的加速访问。采用商用CDN或者自建的代理缓存、web静态缓存架构。
  • 旧图片路径和访问规则的兼容性,应用程序层面的可扩展,上传和访问的性能和安全性等。

0人打赏
您需要登录后才可以回帖
发表回复
极贡献
技术问答
专题荟萃
程序人生
视觉设计
Android开发
iOS开发
编程语言
前端开发
后端开发
服务器架构
软件测试
运维方案
创业路上



最热文章墙

  • 66732/361   【精品推荐】200多种Android动画效果的强悍框架,太全了,不看这个,再有动画的问题,不理你了^@^

  • 37631/190   情人节福利,程序员表白的正确姿势:改几行代码就变成自己的表白了

  • 34362/143   省时省力的Android组件群来了,非常棒的原型参考

  • 34097/249   【精品推荐】Android版产品级的音乐播放器源码,功能太强大了,最好的产品原型有木有?

  • 33327/0   Python爬虫:常用浏览器的useragent

  • 27377/2   超全!整理常用的iOS第三方资源

  • 26400/71   原创表白APP,以程序员的姿势备战新年后的7夕,持续完善中!

  • 25613/142   2016抢红包软件及源码

  • 21095/30   麻省理工的一帮疯子,真的实现了随意操控万物!(绝对黑科技)

  • 20798/25   Android工程师面试题大全

  • 20464/27   2016程序员跳槽全攻略

  • 20251/9   GitHub上排名前50的iOS项目:总有一款你用得着

  • 19647/155   Android版类似UC浏览器:非常赞,产品级的源码

  • 19470/20   码魂:程序员的牛B漫画

  • 17636/10   2016年最全的Android面试考题+答案 精编版

  • 17566/3   吐槽那些程序员的搞笑牛逼注释

  • 16565/42   一个绚丽的loading动效分析与实现!

  • 16559/1   iOS 动画总结

  • 16368/84   Android小而全的博客源码:非常适合全面掌握开发技巧

  • 16354/73   【持续更新中】Android福利贴(二):资料源码大放送

  • 15691/45   惊艳的App引导页:背景图片切换加各个页面动画效果

  • 15342/23   个人收集的Android 各类功能源代码

  • 15324/10   女程序员的梦,众网友的神回复

  • 15083/11   年会上现场review代码是怎么样的体验!

  • 15075/5   新一代Android渠道打包工具:1000个渠道包只需要5秒

  • 14590/80   仿京东商城客户端Android最新版,不错的原型和学习资料

  • 14458/23   珍藏多年的素材,灵感搜寻网站

  • 14422/53   基于瀑布流的美女图片浏览App,有注释的源代码

  • 14198/17   用JavaScript 来开发iOS和Android 原生应用:React Native开源框架中文版来啦

  • 14050/98   Android带弹幕的视频播放器源码,来自大名鼎鼎的Bilibili弹幕网站

  • 14011/20   Android福利第三波【Android电子书】

  • 13565/75   【精品推荐】类似360安全卫士安Android源码:非常赞的产品原型

  • 13512/15   基于Android支付宝支付设计和开发方案

  • 13384/18   65条最常用正则表达式,你要的都在这里了

  • 13284/0   iOS中文版资源库,非常全

  • 12984/17   什么是真正的黑客:收获12200+Stars,人气远超微软开源VS

  • 12589/11   有木有这样一张酷图帮你集齐所有git命令超实用

  • 12390/7   一张图搞定iOS学习路线,非常全面

  • 12373/7   用程序员的姿势抢过年的火车票

  • 11972/10   成为Java顶尖程序员 ,看这11本书就够了

  • 11826/44   在线音乐播放器完整版(商用级的源码):非常赞,可听免费高品质专辑

  • 11701/18   一张图搞定Android学习路线,非常全面

  • 11609/10   微信支付终于成功了(安卓,iOS),在此分享

  • 11487/3   基于Node.js的强大爬虫,能直接发布抓取的文章哦

  • 11486/0   GitHub iOS 库和框架Top100 

  • 11261/29   【持续更新中】Android福利贴(一):资料源码

  • 11075/61   【技巧一】搭配Android Studio,如何实现App远程真机debug?

  • 10692/4   46 个非常有用的 PHP 代码片段

  • 10584/3   即时通信第三方库

  • 10273/8   流媒体视频直播方案

  • 10135/9   B站建开源工作组:APP想支持炫酷弹幕的看过来

  • 10061/9   烧了5亿美金,这家神秘的公司即将颠覆人类未来!

  • 10053/18   八个最优秀的Android Studio插件

  • 9848/2   【精品推荐】高质量PHP代码的50个实用技巧:非常值得收藏

  • 9798/10   中国黑客的隐秘江湖:攻守对立,顶尖高手月入千万美元

  • 9276/6   开箱即用!Android四款系统架构工具

  • 9090/10   十大技巧快速提升Android应用开发性能

  • 9059/3   一张图看清Linux 内核运行原理

  • 9050/3   10款GitHub上最火爆的国产开源项目——可以媲美西半球

  • 8772/1   Android性能优化视频,文档以及工具

  • 返回顶部