高并发网站架构设计(转)

所谓高并发,指的是同一时间能够处理大量的WEB请求,这个指标用来衡量一个架构的体量和性能。这里的大量如何评估呢?1000算不算?10000算不算?css

对于中小型的站点来讲,可能并发100多就很不错了,但对于像淘宝这样的大型站点,单凭一个接口调用的量就有可能达到百万的并发。在双11这样的大型活动场景里,淘宝的并发请求数都能达到上亿次,这样的体量不管是在国内仍是在国际都是排在前列的。而本章节要讲述的内容是如何设计一个能够承载巨量并发请求的架构。html

要想设计一个高并发的架构,首先要搞清楚架构的分层,由于每个层面都有可能形成影响高并发的瓶颈点。找到瓶颈点后,只要把瓶颈点解除,天然会提高整个架构的并发处理能力。咱们先来看一个综合分层的架构图:前端

在这里插入图片描述


1. CDN

对于大型网站来讲增长CDN这一层是很是有必要的,CDN(Content Delivery Network,内容分发网络),它属于网络范畴的一个技术,它依靠部署在各个区域的边缘服务器,实现负载均衡、内容分发调度等功能。它使得用户就近获取内容,下降网络堵塞,提供用户访问响应速度。算法

来举一个通俗点的例子:小明公司作了了一个针对全国用户的业务,服务器放在了北京,可是深圳用户在访问网站的时候很是卡顿,有时候甚至访问不到。经排查,形成该问题的缘由是深圳用户所在网络到北京的机房延迟很是大。小明想到了一个办法,他在深圳的某机房假设了一台服务器,把北京服务器上的文件传输到深圳的服务器上,当深圳用户访问网站时,让该用户直接去访问深圳的服务器,而不是访问北京的服务器。同理,其余城市也效仿深圳假设了相似的服务器,这样全国各地的用户访问公司业务都很顺畅了。数据库

例子中的解决方案其实就是CDN实现原理,固然,真正的CDN技术要复杂得多,要考虑不少问题,好比边缘服务器的分布、机房的网络、带宽、服务器的存储、智能DNS解析、边缘服务器到真实服务器之间的网络优化、静态和动态资源的区分、缓存的优化、压缩、SSL等等问题。关于这些细节技术我不作过多解释,但但愿你们能经过个人描述了解CDN在架构中存在的意义。后端

CDN是处于整个架构体系中最前端的一层,它是直接面对用户的,CDN会把静态的请求(图片、js、css等)直接消化掉,而后把动态的请求日后传递。实际上,一个网站(好比,淘宝网)超过80%的请求都是静态的请求,那也就意味若是前端架设了CDN,即便并发1亿,也只有2000万到了后端的WEB上。那么你可能会问,CDN能支持8000万的并发吗?这个主要取决于CDN厂商的实力,若是他们搞10000个节点(即边缘服务器),每一个节点上消化8000并发,若是搞10万个节点,每一个节点只须要消
化800个并发而已。然而,一台普通的Nginx服务器(配置2核CPU4G内存)轻松处理5万个并发(前提是作过优化,而且处理的请求是静态请求、或者只是转发请求)。缓存


2. 负载均衡

这一层,其实就是一个反向代理(或者叫作分发器),它的主要做用是把用户的请求按照预设的算法发送给它后面的WEB服务器。该层在实现上大体分为两类:四层和七层(网络OSI七层模型),Nginx的负载均衡就属于七层,而LVS属于四层。从吞吐量上来分析,四层的负载均衡更有优点。服务器

因此,要想实现高并发,负载均衡这一层必需要使用四层技术,其中LVS就是一款不错的开源负载均衡软件。LVS有三种实现模式:网络

1)基于iptables的NAT模式

在这里插入图片描述

在这种模式下,负载均衡器上有设置iptables nat表的规则,实现了把用户的请求数据包转发到后端的Real Server(即WEB
Server)上,并且还要把WEB Server的响应数据传递给用户,这样负载均衡器很容易成为一个瓶颈,当并发量很大时,必定会
影响整个架构的性能。数据结构

2)DR模式

在这里插入图片描述

LVS的DR模式和NAT不同,负载均衡器只须要分发用户的请求,而WEB Server的返回数据并不经过负载均衡器传递,数据直
接由WEB Server本身处理。这样就解决了NAT模式的瓶颈问题。可是,DR模式有一个要求:负载均衡器和WEB Server必须在同一个内部网络(要求在相同的广播域内),这是由于DR模式下,数据包的目的MAC地址被修改成了WEB Server的MAC地址。

3)IP Tunnel模式

在这里插入图片描述

LVS的IP Tunnel模式和DR模式相似,负载均衡器只须要分发用户的请求,而WEB Server的返回数据并不经过负载均衡器传递,数据直接由WEB Server本身处理。这样就解决了NAT模式的瓶颈问题。和DR模式不一样的是,IP Tunnel模式不须要保证分发器和Real Server在同一个网络环境,由于这种模式下,它会把数据包的目的IP地址更改成Real Server的IP地址。这种模式,能够实现跨机房、跨地域的负载均衡。

对于以上三种模式来讲,IP Tunnl模式更适合用在高并发的场景下。但有一点须要注意,这台做为负载均衡器的服务器不管是自身的网卡性能,仍是它所处的网络环境里的网络设备都有很高的要求。

可能你会有疑问,这台负载均衡器终究只是一个入口,一台机器顶多支撑10万并发,对于1000万、2000万的并发怎么实现?答案是:叠加!一台10万,100台就是1000万,200台就是2000万……

还有个问题,如何让一个域名(如,www.google.com)访问这200台负载均衡器?请思考一下上一小节的CDN技术,它就可让一个域名指向到成千上万的边缘服务器上。没错,智能DNS解析能够把全国甚至世界各地的请求智能地解析到最优的边缘服务器上。固然,DNS也能够不用智能,大不了直接添加几百条A记录呗,最终也会把用户的请求均衡地分发到这几百个节点上。


3. WEB层

若是最前端使用了CDN,那么在WEB这一层处理的请求绝大多数为动态的请求。什么是动态的请求?除了静态的就是动态的,那什么是静态的?前面提到过的图片、js、css、html、音频、视频等等都属于静态资源,固然另外还有太多,你们能够参考第一篇文章《HTTP扫盲》的MIME Type。

再来讲这个动态,你能够这样理解:凡是涉及到数据库存取操做的请求都属于动态请求。好比,一个网站须要注册用户才能够正常访问里面的内容,你注册的用户信息(用户名、密码、手机号、邮箱等)存入到了数据库里,每次你登陆该网站,都须要到数据库里查询用户名和密码,来验证你输入的是不是正确的。

若是到了WEB这一层全都是动态的请求的话,那么并发量的多少主要取决于WEB层后端的DB层或者Cache层。也就是说要想提高WEB层服务器的并发性能,必须首先要提高DB层或者Cache层的并发性能。

咱们不妨来一个假设:要求架构能支撑1000万并发(动态),假设单台WEB Server支撑1000并发,则须要1万台服务器。实际生产环境中,单台机器支撑1000并发已经很是厉害啦,至少在个人运维生涯里,单台WEB Server最大动态并发量并无达到过这么大。

我提供一组数据,你天然就能够估算出并发量。在这我拿PHP的应用举例:一个PHP的网站,单个PHP-FPM进程耗费内存在2M-20M(假设耗费内存10M),1000个并发也就意味着同时有1000个PHP-FPM进程,耗费内存为1000*10M=10G,再加上留给系统1G内存,因此1000并发至少须要11G内存。

按照上面的估算,2000并发则须要21G内存,10000并发则须要101G内存,这个仅仅是理论值。实际上,并发量不只跟内存有关系,跟CPU一样也有关系。若是服务器有4核CPU,则理论上仅仅支持4个进程同时占用CPU计算,也就是说仅能支持4个并发。固然,CPU计算那么快,进程会来回切换排队占用CPU,这样可以实现即便只有4核CPU,依然可以支持几百甚至上千的并发。但不管如何,CPU的核数越大,该服务器能支撑的并发也就越大。

对于高并发的架构,WEB Server必然会作负载均衡集群,单台WEB Server的配置一般会选择4核8G这样的配置(这个配置,最好是根据本身业务的特性选择合适的,毕竟如今大多企业都使用公有云或者私有云,服务器的配置能够定制),而后由这样的机器来组成一个大型集群,最终实现高并发的需求。

在这里插入图片描述


4. Cache层

增长这一层的目的是为了减轻DB层的压力,Cache层有一个特色:数据的读写发生在内存里,跟磁盘并无关系。正是由于这个特色,保证了数据的读写速度很是快。假如没有Cache层,并发1000万的动态请求意味着这1000万会直接透传到DB层(如MySQL),1000万的并发就会形成1000万对磁盘的读写操做。我想你们都明白,磁盘的读写速度远远低于内存的读写速度,要想支撑1000万并发读写是不现实的。

固然,Cache层主要针对读操做,并且它仅仅是缓存一部分DB层的热数据(频繁读取的那部分数据)。举一个下例子:有一次公司的某个业务临时作了一个推广活动,结果致使访问量暴涨10倍,本来的服务器架构并不能支撑这么大的量,结果可想而知。当时,咱们的解决方案是:把查询量很是大的数据缓存到Memcached里面,而后在没有增长硬件的状况下顺利抗了过去。可见这一
个Cache层所起到的做用是多么关键。

能够做为Cache的角色一般是NoSQL,如Memcached、Redis等。在第3章《常见WEB集群架构》中我曾提到过Memcached,架构图以下:

在这里插入图片描述

做为Cache角色时,Redis和Memcached用法基本一致。其实,抛开这个Cache角色,NoSQL也能够独立做为DB层,这主要取决于业务逻辑是否支持拿NoSQL做为数据存储引擎,毕竟NoSQL的数据结构和关系型数据库比仍是比较简单的,有些复杂场景没法实现。但为了实现高并发,咱们能够尝试同时使用传统的关系型数据库和NoSQL数据库存储数据。

既然Memcached和Redis均可以做为Cache角色,那么到底用哪个能够支撑更大的并发量呢?其实这二者各有千秋,不能盲目地下结论说哪一个更快或者更好。得根据你的业务选择适合的服务。因为Redis属于单线程,故只能使用单核,而Memcached属于多线程的,从而可使用多核,因此在比较上,平均每个核上Redis在存储小数据时比Memcached性能更高。而在100k以
上的数据中,Memcached性能要高于Redis,虽然Redis最近也在存储大数据的性能上进行优化,可是比起Memcached,仍是稍有逊色。若是不考虑存储数据大小,确定Memcached性能更好,毕竟它是多线程的。

另外你须要了解,Memcached的数据只能存内存,不能存到磁盘,而Redis支持把内存的数据镜像一份到磁盘上,并且还能够记录日志(经过这个日志来获取数据)。Memcached只能存简单的K-V格式的数据,而Redis支持更多的数据类型(如,list、hash)。

不管你用哪种做为Cache,咱们都须要为其作一个高可用负载均衡集群,这样才能够知足高并发的需求。

在这里插入图片描述


5. DB层

能够说DB层是整个架构体系中很是关键的一层,也是瓶颈所在。缘由无他,只因它涉及到对磁盘的读写。因此,为了提高性能,对服务器磁盘要求很高,至少是15000r/m的SAS硬盘并且须要作RAID10,若是选择SSD盘更优。

最简单暴力提高并发数量的办法是服务器的堆积(即,作负载均衡集群),但DB层跟WEB层不同,它涉及到数据存储到磁盘
里,服务器能够累加,可是磁盘在累加的同时,如何保证全部的服务器能读写同一份数据?这是一个很大的问题,因此单纯的服务器堆积只适合小规模的业务,对于并发上千万的业务并不适用。并发量大的站点,意味着数据量也是很是大的(如,TB级别),若是单个数据库上TB,那必定是一个灾难,不管是读写仍是备份都将是极大的问题。

那如何解决这个问题呢?既然大了不行,那就将大的库切割成小的库便可。你可不要把这个切割单纯地想象成切割文件。咱们能够从两个维度来实现切割。

1)将业务划分为多个业务模块

大型网站为了应对日益复杂的业务场景,经过使用分而治之的手段将整个网站业务分红不一样的产品线,如大型购物网站就会将首页、商铺、订单、买家、卖家、仓储、物流、售后服务等拆分红不一样的产品项,这样数据库天然也拆分为了多个数据库,原来TB级的数据,变成了GB级。若是以为还不够细化,咱们能够继续把商铺进一步拆分,好比我的类的、企业类的、明星类的、普通类的等等。总之,你能够根据业务特性想到几百种拆分方法,最终一块大蛋糕变成了几十甚至几百块小蛋糕,吃起来就简单多了。

在这里插入图片描述

2)将数据库分库分表

业务拆分是产品经理设计的,可是这个分库分表只能是DBA操刀。若是一个几千GB的大库读写很慢的话,但分红1000个几GB的小库后,读写速度必定是有质的飞跃。同理,表也是能够像库那样划分的。分库分表须要借助数据库中间件来完成。好比MySQL分库分表比较好的中间件MyCAT就不错。

在这里插入图片描述

有了以上两个拆分原则,不管多大的库,咱们均可以划分为比较小的库,这样即便使用传统的架构依然能够轻松应付。最终的DB层架构就成了蜂窝状的一组一组的小单元,每个单元独立作高可用以及负载均衡集群。

在这里插入图片描述


6. 消息队列层

一个大型的网站,必定少不了消息队列这一层。在前面第3章《常见WEB集群架构》一文中就提到过它,它主要解决的问题是:解耦合、异步处理、流量削峰等。如下三个应用场景曾在第3章出现过,也许你如今看会有更深层次的体会。

1)解耦合应用场景示例

用户上传图片到服务器,要求人脸识别系统识别该上传图片,传统的作法是:用户上传图片 → 服务接收到图片开始识别图片 → 系统判断图片是否合法 → 反馈给用户是否成功。这个要涉及两个系统:

在这里插入图片描述

而使用消息队列,流程会变成这样:

在这里插入图片描述

用户上传图片后,图片上传系统将图片信息写入消息队列,直接返回成功;而人脸识别系统则定时从消息队列中取数据,完成对新增图片的识别。

此时图片上传系统并不须要关心人脸识别系统是否对这些图片信息的处理、以及什么时候对这些图片信息进行处理。事实上,因为用户并不须要当即知道人脸识别结果,人脸识别系统能够选择不一样的调度策略,按照闲时、忙时、正常时间,对队列中的图片信息进行处理。

2)异步处理应用场景示例

用户到一个网站注册帐号,系统须要发送注册邮件并验证短信。传统的处理流程以下:

在这里插入图片描述

这种方式下,须要最终发送短信验证后再返回给客户端。

另一种方式就是异步处理,即注册邮件和短信同时发送,流程以下:

在这里插入图片描述

当用户填写完注册信息并成功写入消息队列后,就能够反回成功的信息给客户端,从而客户端不须要再等待系统发邮件和发短信,不只客户端不用等,并且处理客户端请求的那个工做进程也不须要等(这个特性很是重要,它是实现高并发的一个重要手段),这个就是异步处理的优点。

3)流量削峰应用场景示例

很典型的应用就是购物网站秒杀活动,通常因为瞬时访问量过大,服务器接收过大,会致使流量暴增,相关系统没法处理请求甚至崩溃。而加入消息队列后,系统能够从消息队列中取数据,至关于消息队列作了一次缓冲。

在这里插入图片描述

该方法可让请求先入消息队列,而不是由业务处理系统直接处理,极大地减小了业务处理系统的压力。另外队列长度能够作限制,好比队列长度为100,则该系统只能有100人能够秒杀到商品,排在100名后的用户没法秒杀到商品,而返回活动已结束或商品已售完的信息。

总之,消息队列的引入极大提高了整个架构的并发能力。从WEB层接收到动态的请求后,Cache层过滤掉一部分,而后请求逐一地发送到DB层,在这个过程当中,查询时间很长的请求能够单独摘出来,把它搞到消息队列里,这样WEB层和DB层只处理那种快速有结果的查询,并发量天然很大。而消息队列会慢慢消化掉这些特殊的查询,或许你有疑问,这种查询慢的请求也不少怎么
办?不也一样影响到并发量吗?毕竟最终的查询到了DB层。不要忘记消息队列自己就有削峰的能力,若是有大量的这种查询,那么就让它们排好队列,慢慢消化,总之不让它们影响到DB层的正常查询。

能够提供消息队列的服务有那么多(RabitMQ、ActiveMQ、Kafka、ZeroMQ、MetaMQ、Beanstalk、Redis等等),到底选择哪种?最好是让研发同事来定吧,只有研发团队最了解本身代码的逻辑架构,适合本身的才是最好的。事实上,不管你用哪种消息队列服务,它都不会成为整个架构的瓶颈点。固然,你最好作一个分布式的集群,这样可以保证它的横向扩容或者缩容。


7. 存储层

关于存储,目前的解决方案我归类为如下几种:

1)服务器本地存储

就是服务器自身的磁盘,对于像DB层这样关键的角色,咱们一般会用高性能磁盘作RAID10。特色:方便维护、稳定、性能很是好、容量有限、扩容不方便。

2)专业的存储设备

主要有三类:NAS、SAN、DAS。

NAS:相似Linux系统作的NFS服务,它是创建在操做系统层面上的一种共享存储解决方案,它是一种商业产品。NAS比较适合小规模网站。特色:容量大、扩容不方便、吞吐量通常(受网络环境影响)、稳定性好、成本高。

SAN:也是一种商业的共享存储解决方案,支持普通网络或者光纤接入,比NAS更加底层。特色:容量大、扩容不方便、性能好(比NAS强不少)、稳定性好、成本高昂。

DAS:磁盘阵列,支持RAID,商业的存储。特色:容量大、扩容不方便、不支持共享、性能好、稳定性好。

3)分布式共享存储

随着云计算、大数据技术的日益流行,分布式共享存储技术愈来愈成熟,不管是商业的仍是开源的都有很多优秀的解决方案。好比,开源的有HDFS、FastDFS、MFS、GlusterFS、Ceph、Swift等。这类存储有一些共同特色:方便扩容、容量能够无限大、性能通常(网络会成为瓶颈)、成本低、稳定性好。

本节的存储层我也归类为三大类:WEB层面的存储(好比存储代码、图片、js、css、视频、音频等静态文件)、日志、DB层面的存储(即数据库的数据存储)。

这三类存储,最要命的是DB层的存储,前面我也提到过DB层很关键,而决定DB层性能的因素中这个数据存储(磁盘)性能起到决定性做用。解决方案我也提到了,就是“大变小,一变多,本身管本身”。正常状况下巨量的数据库必然会使用大容量存储设备,这样最终的结果是—慢!因此,咱们须要分模块、分库分表,最终单台机器的本地磁盘就能够支撑这些巨量的数据,读写速度不会被网络等因素影响。

日志类和WEB层静态文件的存储能够选择分布式共享存储解决方案,由于这类的存储不须要过高的吞吐量,它们所占用的空间比较大,并且会愈来愈大。


总结

当你看完以上内容后,可能你的心中仍是没有一个完整的答案,因此这个总结很关键!

1)高并发网站必定会使用CDN,并且须要把静态文件存储在边缘服务器上。

2)负载均衡必定要使用四层的,好比LVS,若是是LVS,选择IP Tunnel模式。

3)WEB层把静态的请求交给CDN处理,因此只处理动态的请求,要支持横向扩容,能够方便地经过加机器来增长并发量。

4)增长Cache层,把热数据搞到这一层,减小对DB层地压力。对这一层作分布式集群架构设计,方便扩容。

5)增长消息队列,实现解耦合、流量削峰,从而提高整个架构地并发能力。

6)DB层要经过拆分业务、分库分表来实现大变小、一变多,对单独模块作高可用负载均衡集群,从而提高并发能力。

7)DB层的存储使用本地磁盘,日志类、静态文件类使用分布式文件存储。

相关文章
相关标签/搜索