https://blog.csdn.net/dinglang_2009/article/details/31450731
在主流的Web站点中,图片往往是不可或缺的页面元素,尤其在大型站点中,差点儿都将面临“海量图片资源”的存储、訪问等相关技术问题。
在针对图片server的架构扩展中,也会历经非常多曲折甚至是血泪教训(尤其是早期规划不足。造成后期架构上非常难兼容和扩展)。
本文将以一个真实垂直门户站点的发展历程,向大家娓娓道来。
构建在Windows平台之上的站点。往往会被业内众多架构师觉得非常“保守”。非常大部分原因,是因为微软技术体系的封闭和部分技术人员的短视造成的。因为长期缺乏开源支持,所以仅仅能“闭门造车”,这样非常easy形成思维局限性和短板。就拿图片server为样例,假设前期没有容量规划和可扩展的设计。那么随着图片文件的不断增多和訪问量的上升,因为在性能、容错/容灾、扩展性等方面的设计不足。兴许将会给开发、运维工作带来非常多问题,严重时甚至会影响到站点业务正常运作和互联网公司的发展(这绝不是在危言耸听)。
之所以选择Windows平台来构建站点和图片server,非常大部分由创始团队的技术背景决定的,早期的技术人员可能更熟悉.NET,或者负责人觉得Windows/.NET的易用性、“短平快”的开发模式、人才成本等方面都比較符合创业初期的团队,自然就选择了Windows。后期业务发展到一定规模。也非常难轻易将总体架构迁移到其他平台上了。当然,对于构建大规模互联网,更建议首选开源架构。因为有非常多成熟的案例和开源生态的支持。避免反复造轮子和支出授权费用。对于迁移难度较大的应用。比較推荐Linux、Mono、Mysql、Memcahed……混搭的架构,相同能支撑高并发訪问和大数据量。
单机时代的图片server架构(集中式)
初创时期因为时间紧迫,开发者水平也非常有限等原因。所以通常就直接在website文件所在的文件夹下,建立1个upload子文件夹。用于保存用户上传的图片文件。假设按业务再细分,能够在upload文件夹下再建立不同的子文件夹来区分。比如:uploadQA,uploadFace等。
在数据库表中保存的也是”upload/qa/test.jpg”这类相对路径。
用户的訪问方式例如以下:
http://www.yourdomain.com/upload/qa/test.jpg
程序上传和写入方式:
程序猿A通过在web.config中配置物理文件夹D:Webyourdomainupload 然后通过stream的方式写入文件;
程序猿B通过Server.MapPath等方式,依据相对路径获取物理文件夹 然后也通过stream的方式写入文件。
长处:实现起来最简单,无需不论什么复杂技术。就能成功将用户上传的文件写入指定文件夹。保存数据库记录和訪问起来倒是也非常方便。
缺点:上传方式混乱,严重不利于站点的扩展。
针对上述最原始的架构,主要面临着例如以下问题:
1. 随着upload文件夹中文件越来越多,所在分区(比如D盘)假设出现容量不足,则非常难扩容。
仅仅能停机后更换更大容量的存储设备,再将旧数据导入。
2. 在部署新版本号(部署新版本号前通过须要备份)和日常备份website文件的时候,须要同一时候操作upload文件夹中的文件,假设考虑到訪问量上升,后边部署由多台Webserver组成的负载均衡集群,集群节点之间假设做好文件实时同步将是个难题。
集群时代的图片server架构(实时同步)
在website站点以下。新建一个名为upload的虚拟文件夹。因为虚拟文件夹的灵活性,能在一定程度上代替物理文件夹,并兼容原有的图片上传和訪问方式。用户的訪问方式依旧是:
http://www.yourdomain.com/upload/qa/test.jpg
长处:配置更加灵活,也能兼容老版本号的上传和訪问方式。
因为虚拟文件夹。能够指向本地随意盘符下的随意文件夹。这样一来,还能够通过接入外置存储。来进行单机的容量扩展。
缺点:部署成由多台Webserver组成的集群。各个Webserver(集群节点)之间(虚拟文件夹下的)须要实时的去同步文件。因为同步效率和实时性的限制,非常难保证某一时刻各节点上文件是全然一致的。
基本架构例如以下图所看到的:
从上图可看出。整个Webserver架构已经具备“可扩展、高可用”了。主要问题和瓶颈都集中在多台server之间的文件同步上。
上述架构中仅仅能在这几台Webserver上互相“增量同步”,这样一来,就不支持文件的“删除、更新”操作的同步了。
早期的想法是。在应用程序层面做控制,当用户请求在web1server进行上传写入的同一时候。也同步去调用其他webserver上的上传接口。这显然是得不偿失的。所以我们选择使用Rsync类的软件来做定时文件同步的。从而省去了“反复造轮子”的成本,也减少了风险性。
同步操作里面,一般有比較经典的两种模型,即推拉模型:所谓“拉”,就是指轮询地去获取更新。所谓推,就是发生更改后主动的“推”给其他机器。当然,也能够採用加高级的事件通知机制来完毕此类动作。
在高并发写入的场景中,同步都会出现效率和实时性问题,并且大量文件同步也是非常消耗系统和带宽资源的(跨网段则更明显)。
集群时代的图片server架构改进(共享存储)
沿用虚拟文件夹的方式,通过UNC(网络路径)的方式实现共享存储(将upload虚拟文件夹指向UNC)
用户的訪问方式1:
http://www.yourdomain.com/upload/qa/test.jpg
用户的訪问方式2(能够配置独立域名):
http://img.yourdomain.com/upload/qa/test.jpg
支持UNC所在server上配置独立域名指向,并配置轻量级的webserver,来实现独立图片server。
长处: 通过UNC(网络路径)的方式来进行读写操作,能够避免多server之间同步相关的问题。相对来讲非常灵活。也支持扩容/扩展。支持配置成独立图片server和域名訪问,也完整兼容旧版本号的訪问规则。
缺点 :可是UNC配置有些繁琐。并且会造成一定的(读写和安全)性能损失。可能会出现“单点故障”。假设存储级别没有raid或者更高级的灾备措施,还会造成数据丢失。
基本架构例如以下图所看到的:
在早期的非常多基于Linux开源架构的站点中。假设不想同步图片,可能会利用NFS来实现。
事实证明。NFS在高并发读写和海量存储方面,效率上存在一定问题,并不是最佳的选择,所以大部分互联网公司都不会使用NFS来实现此类应用。当然,也能够通过Windows自带的DFS来实现,缺点是“配置复杂,效率未知。并且缺乏资料大量的实际案例”。另外,也有一些公司採用FTP或Samba来实现。
上面提到的几种架构。在上传/下载操作时。都经过了Webserver(尽管共享存储的这种架构,也能够配置独立域名和站点来提供图片訪问,但上传写入仍然得经过Webserver上的应用程序来处理),这对Webserver来讲无疑是造成巨大的压力。
所以,更建议使用独立的图片server和独立的域名。来提供用户图片的上传和訪问。
独立图片server/独立域名的长处
1. 图片訪问是非常消耗server资源的(因为会涉及到操作系统的上下文切换和磁盘I/O操作)。
分离出来后,Web/Appserver能够更专注发挥动态处理的能力。
2. 独立存储,更方便做扩容、容灾和数据迁移。
3. 浏览器(相同域名下的)并发策略限制,性能损失。
4. 訪问图片时,请求信息中总带cookie信息,也会造成性能损失。
5. 方便做图片訪问请求的负载均衡,方便应用各种缓存策略(HTTP Header、Proxy Cache等),也更加方便迁移到CDN。
......
我们能够使用Lighttpd或者Nginx等轻量级的webserver来架构独立图片server。
当前的图片server架构(分布式文件系统+CDN)
在构建当前的图片server架构之前。能够先彻底撇开webserver。直接配置单独的图片server/域名。
但面临例如以下的问题:
1. 旧图片数据怎么办?是否能继续兼容旧图片路径訪问规则?
2. 独立的图片server上须要提供单独的上传写入的接口(服务API对外公布),安全问题怎样保证?
3. 同理,假如有多台独立图片server。是使用可扩展的共享存储方案,还是採用实时同步机制?
直到应用级别的(非系统级) DFS(比如FastDFS HDFS MogileFs MooseFS、TFS)的流行。简化了这个问题:运行冗余备份、支持自己主动同步、支持线性扩展、支持主流语言的clientapi上传/下载/删除等操作。部分支持文件索引,部分支持提供Web的方式来訪问。
考虑到各DFS的特点,clientAPI语言支持情况(须要支持C#),文档和案例。以及社区的支持度,我们终于选择了FastDFS来部署。
唯一的问题是:可能会不兼容旧版本号的訪问规则。假设将旧图片一次性导入FastDFS。但因为旧图片訪问路径分布存储在不同业务数据库的各个表中,总体更新起来也十分困难,所以必须得兼容旧版本号的訪问规则。
架构升级往往比做全新架构更有难度,就是因为还要兼容之前版本号的问题。
(给飞机在空中换引擎可比造架飞机难得多)
解决方式例如以下:
首先,关闭旧版本号上传入口(避免继续使用导致数据不一致)。将旧图片数据通过rsync工具一次性迁移到独立的图片server上(即下图中描写叙述的Old ImageServer)。在最前端(七层代理,如Haproxy、Nginx)用ACL(訪问规则控制)。将旧图片相应URL规则的请求(正则)匹配到,然后将请求直接转发指定的web server列表。在该列表中的server上配置好提供图片(以Web方式)訪问的站点。并添加缓存策略。
这样实现旧图片server的分离和缓存,兼容了旧图片的訪问规则并提升旧图片訪问效率,也避免了实时同步所带来的问题。
总体架构如图:
基于FastDFS的独立图片server集群架构,尽管已经非常的成熟,可是因为国内“南北互联”和IDC带宽成本等问题(图片是非常消耗流量的),我们终于还是选择了商用的CDN技术,实现起来也非常easy。原理事实上也非常简单,我这里仅仅做个简单的介绍:
将img域名cname到CDN厂商指定的域名上,用户请求訪问图片时。则由CDN厂商提供智能DNS解析。将近期的(当然也可能有其他更复杂的策略,比如负载情况、健康状态等)服务节点地址返回给用户,用户请求到达指定的server节点上,该节点上提供了相似Squid/Vanish的代理缓存服务,假设是第一次请求该路径,则会从源站获取图片资源返回client浏览器。假设缓存中存在,则直接从缓存中获取并返回给client浏览器,完毕请求/响应过程。
因为採用了商用CDN服务,所以我们并没有考虑用Squid/Vanish来反复构建前置代理缓存。
上面的整个集群架构,能够非常方便的做横向扩展,能满足一般垂直领域大型站点的图片服务需求(当然,像taobao这样超大规模的可能另当别论)。经測试。提供图片訪问的单台Nginxserver(至强E5四核CPU、16G内存、SSD)。对小静态页面(压缩后的)能够扛住上万的并发且毫无压力。
当然,因为图片本身体积比纯文本的静态页面大非常多,提供图片訪问的server的抗并发能力。往往会受限于磁盘的I/O处理能力和IDC提供的带宽。Nginx的抗并发能力还是非常强的。并且对资源占用非常低,尤其是处理静态资源,似乎都不须要有过多操心了。能够依据实际訪问量的需求。通过调整Nginx參数,Linux内核调优、缓存策略等手段做更大程度的优化,也能够通过添加server或者升级server配置来做扩展,最直接的是通过购买更高级的存储设备和更大的带宽,以满足更大訪问量的需求。
值得一提的是,在“云计算”流行的当下,也推荐快速发展期间的站点,使用“云存储”这种方案。既能帮你解决各类存储、扩展、备灾的问题。又能做好CDN加速。最重要的是,价格也不贵。
总结,有关图片server架构扩展。大致环绕这些问题展开:
1. 容量规划和扩展问题。
2. 数据的同步、冗余和容灾。
3. 硬件设备的成本和可靠性(是普通机械硬盘。还是SSD,或者更高端的存储设备和方案)。
4. 文件系统的选择。依据文件特性(比如文件大小、读写比例等)选择是用ext3/4或者NFS/GFS/TFS这些开源的(分布式)文件系统。
5. 图片的加速訪问。
採用商用CDN或者自建的代理缓存、web静态缓存架构。
6. 旧图片路径和訪问规则的兼容性,应用程序层面的可扩展,上传和訪问的性能和安全性等。
作者介绍
丁浪,技术架构师。擅长大规模(大流量、高并发、高可用、海量数据)互联网架构,专注在“高性能,可扩展/伸缩,稳定。安全”的技术架构。 热衷于技术研究和分享,曾分享和独立撰写过大量技术文章。
本文首发于InfoQ社区,版权全部,转载请注明出处。