版权声明:本文为博主原创文章,未经博主同意不得转载。

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文件夹下再建立不同的子文件夹来区分。比如: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的方式写入文件。

长处:实现起来最简单,无需不论什么复杂技术。就能成功将用户上传的文件写入指定文件夹。保存数据库记录和訪问起来倒是也非常方便。

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

针对上述最原始的架构,主要面临着例如以下问题:

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社区,版权全部,转载请注明出处。  

大型站点图片server架构的演进的更多相关文章

  1. Windows平台网站图片服务器架构的演进[转]

    构建在Windows平台之上的网站,往往会被业内众多架构师认为很“保守”.很大部分原因,是由于微软技术体系的封闭和部分技术人员的短视造成 的.由于长期缺乏开源支持,所以只能“闭门造车”,这样很容易形成 ...

  2. Windows平台网站图片服务器架构的演进

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

  3. 大并发server架构 && 大型站点架构演变

    server的三条要求: 高性能:对于大量请求,及时高速的响应 高可用:7*24 不间断,出现问题自己主动转移.这叫fail over(故障转移) 伸缩性:使用跨机器的通信(TCP) 另外不论什么网络 ...

  4. b2c项目基础架构分析(一)b2c 大型站点方案简述 已补充名词解释

    我最近一直在找适合将来用于公司大型bs,b2b b2c的基础架构. 实际情况是要建立一个bs架构b2b.b2c的网站,当然还包括wap站点.手机app站点. 一.现有公司技术人员现状: 1.熟悉asp ...

  5. .NET/ASP.NETMVC 大型站点架构设计—迁移Model元数据设置项(自定义元数据提供程序)

    阅读目录: 1.需求背景介绍(Model元数据设置项应该与View绑定而非ViewModel) 1.1.确定问题域范围(可以使用DSL管理问题域前提是锁定领域模型) 2.迁移ViewModel设置到外 ...

  6. 大型JavaScript应用程序架构模式

    11月中旬在伦敦举行的jQuery Summit顶级大会上有个session讲的是大型JavaScript应用程序架构,看完PPT以后觉得甚是不错,于是整理一下发给大家共勉. PDF版的PPT下载地址 ...

  7. .Net 大型分布式基础服务架构横向演变概述

    一. 业务背景 构建具备高可用,高扩展性,高性能,能承载高并发,大流量的分布式电子商务平台,支持用户,订单,采购,物流,配送,财务等多个项目的协作,便于后续运营报表,分析,便于运维及监控. 二. 基础 ...

  8. ASP.NET开发的大型网站有哪些架构方式

    谈谈用ASP.NET开发的大型网站有哪些架构方式(成本) 在上篇文章里(http://www.cnblogs.com/ms0017/archive/2011/07/26/2117676.html),列 ...

  9. .Net 大型分布式基础服务架构横向演变概述(转)

    一. 业务背景 构建具备高可用,高扩展性,高性能,能承载高并发,大流量的分布式电子商务平台,支持用户,订单,采购,物流,配送,财务等多个项目的协作,便于后续运营报表,分析,便于运维及监控. 二. 基础 ...

随机推荐

  1. js node.children与node.childNodes与node.firstChild,node,lastChild之间的关系

    博客搬迁,给你带来的不便,敬请谅解! http://www.suanliutudousi.com/2017/11/06/js-node-children%e4%b8%8enode-childnodes ...

  2. Linux下设置Core文件生成路径及文件名

    修改core dump文件路径:  方法1:临时修改: 修改/proc/sys/kernel/core_pattern文件/proc目录本身动态加载每次系统重启都会重新加载因此种方法只能作临时修改/p ...

  3. 函数的atguments

    在调用函数时,浏览器每次都会传递进两个隐含的参数: 1.函数的上下文对象this 2.封装实参的对象arguments arguments是一个类数组对象,它也可以用过索引来操作数据,也可以获取长度 ...

  4. layout(布局)组件

    一.依赖于 Panel(面 板)组件和 resizable(调整大小)组件. 二.class加载方式    <div id="box" class="easyui- ...

  5. Mysql中(@i:=@i+1)的作用

    Oracle中有一个伪列rownum,可以在生成查询结果表的时候生成一组递增的序列号.MySQL中没有这个伪列,但是有时候要用,可以用如下方法模拟生成一列自增序号. (1)sql示例:select ( ...

  6. POJ-1155 TELE 树形背包dp

    dp[u][i]代表以u为根的子树选i个叶子的最大收益 那么dp[u][i]=max(dp[u][i],dp[v][k]+dp[u][i-k]-len) (1=<k<=i) 细节看代码: ...

  7. Tensorflow的基础用法

    简介 Tensorflow是一个深度学习框架,它使用图(graph)来表示计算任务,使用tensor(张量)表示数据,图中的节点称为OP,在一个会话(Session)的上下文中执行运算,最终产生ten ...

  8. Sublime Text添加gcc编译器

    { "shell_cmd" : "gcc $file_name -o ${file_base_name}", "working_dir" : ...

  9. 【leetcode】328. Odd Even Linked List

    题目如下: Given a singly linked list, group all odd nodes together followed by the even nodes. Please no ...

  10. SQL 删除

    SQL Delete 语句(删除表中的记录) DELETE语句用于删除表中现有记录. SQL DELETE 语句 DELETE 语句用于删除表中的行. SQL DELETE 语法 DELETE FRO ...