传统的企业应用系统主要面对的技术挑战是处理复杂凌乱、千变万化的所谓业务逻辑,而大型网站主要面对的技术挑战是处理超大量的用户访问和海量的数据处理;前者的挑战来自功能性需求,后者的挑战来自非功能性需求;功能性需求也许还有“人月神话”聊以自慰,通过增加人手解决问题,而非功能需求大多是实实在在的技术难题,无论有多少工程师,做不到就是做不到。
“好的设计绝对不是模仿、不是生搬硬套某个模式,而是在对问题深刻理解之上的创造与创新,即使是‘微创新’,也是让人耳目一新的似曾相识。
京东促销不能购买的例子:
能够正常访问购物车,却不能成功购买,问题应该是出在订单系统,B 2C网站生成一个订单需要经历扣减库存、扣减促销资源、更新用户账户等一系列操作,这些操作大多是数据库事务操作,没有办法通过缓存等手段来减轻数据库服务器负载压力,如果事前没有设计好数据库伸缩性架构,那么京东的技术团队将遇到一个大麻烦。
如何打造一个高可用、高性能、易扩展、可伸缩且安全的网站?如何让网站随应用所需灵活变动,即使是山寨他人的产品,也可以山寨的更高、更快、更强,一年时间用户数从零过亿呢?
有以下特点:
1.高并发,大流量
2.高可用:系统24小时不间断服务
3.海量数据
4.用户分布广泛,网络情况复杂
5.安全环境恶劣
6.需求快速变更,发布频繁
7.渐进式发展
1.初始阶段的网站架构
应用程序,数据库,文件等所有的资源都在一台服务器上。
2.应用服务和数据服务分离
应用和数据分离后整个网站使用三台服务器:应用服务器,文件服务器和数据库服务器。如下图所示:
这三台服务器对硬件资源的要求各不相同:
1.应用服务器需要处理大量的业务逻辑,因此需要更快更强大的CPU
2.数据库服务器需要快速磁盘检索和数据缓存,因此需要更快的硬盘和更大的内存
3.文件服务器需要存储大量用户上传的文件,因此需要更大的磁盘
随着用户逐渐增多,网站又一次面临挑战:数据库压力太大导致访问延迟,进而影响整个网站的性能,用户体验受到影响。
3.访问缓存改善网站性能
网站访问特点和现实世界的财富分配一样遵循二八定律:80%的业务访问集中在20%的数据上。
网站使用的缓存可以分为两种:缓存在1.应用服务器上的本地缓存和缓存在专门的2.分布式缓存服务器上的远程缓存。本地缓存的访问速度更快一些,但是受应用服务器内存限制,其缓存数据量有限,而且会出现和应用程序争用内存的情况。远程分布式缓存可以使用集群的方式,部署大内存的服务器作为专门的缓存服务器,可以在理论上做到不受内存容量限制的缓存服务,如图:
使用缓存后,数据访问压力得到有效缓解,但是单一应用服务器能够处理的请求连接有限,在网站高峰期,应用服务器成为整个网站的瓶颈。
4.使用应用服务器集群改善网站的并发处理能力
使用集群是网站解决高并发、海量数据问题的常用手段。当一台服务器的处理能力、存储空间不足时,不要企图去换更强大的服务器,对大型网站而言,不管多么强大的服务器,都满足不了网站持续增长的业务需求。这种情况下,更恰当的做法是增加一台服务器分担原有服务器的访问及存储压力。架构如图:
5.数据库读写分离
目前大部分的主流数据库都提供主从热备功能,通过配置两台数据库主从关系,可以将一台数据库服务器的数据更新同步到另一台服务器上。网站利用数据库的这一功能,实现数据库读写分离,从而改善数据库负载压力。如图:
6.使用反向代理和CDN加速网站响应
CDN和反向代理的基本原理都是缓存,区别在于CDN部署在网络提供商的机房,使用户在请求网站服务时,可以从距离自己最近的网络提供商机房获取数据;而反向代理则部署在网站的中心机房,当用户请求到达中心机房后,首先访问的服务器是反向代理服务器,如果反向代理服务器中缓存着用户请求的资源,就将其直接返回给用户。架构如图:
使用CDN和反向代理的目的是尽早返回数据给用户,一方面加快用户访问速度,另一方面也减轻了后端服务器的负载压力。
7.使用分布式文件系统和分布式数据库系统
分布式数据库是网站数据库拆分的最后手段,只有在单表数据规模非常庞大的时候才使用。不到不得已时,网站更常用的数据库拆分手段是业务分库,将不同业务的数据库部署在不同的物理服务器上。
10.分布式服务
既然每一个应用系统都需要执行许多相同的业务操作,比如用户管理、商品管理等,那么可以将这些共用的业务提取出来,独立部署。由这些可复用的业务连接数据库,提供共用业务服务,而应用系统只需要管理用户界面,通过分布式服务调用共用业务服务完成具体业务操作,如图:
误区:
1.一味追随大公司的解决方案
2.为了技术而技术
3.企图用技术解决所有问题
比如说12306网站:
12306真正的问题其实不在于它的技术架构,而在于它的业务架构:12306根本就不应该在几亿中国人一票难求的情况下以窗口售票的模式在网上售票(零点开始出售若干天后的车票)。12306需要重构的不仅是它的技术架构,更重要的是它的业务架构:调整业务需求,换一种方式卖票,而不要去搞促销秒杀这种噱头式的游戏。
后来证明12306确实是朝这个方向发展的:在售票方式上引入了排队机制、整点售票调整为分时段售票。其实如果能控制住并发访问的量,很多棘手的技术问题也就不是什么问题了。
关于什么是模式,这个来自建筑学的词汇是这样定义的:“每一个模式描述了一个在我们周围不断重复发生的问题及该问题解决方案的核心。这样,你就能一次又一次地使用该方案而不必做重复工作”。模式的关键在于模式的可重复性,问题与场景的可重复性带来解决方案的可重复使用。
1.分层
分层是企业应用系统中最常见的一种架构模式,将系统在横向维度上切分成几个部分,每个部分负责一部分相对比较单一的职责,然后通过上层对下层的依赖和调用组成一个完整的系统。
分层结构在计算机世界中无处不在,网络的7层通信协议是一种分层结构;计算机硬件、操作系统、应用软件也可以看作是一种分层结构。在大型网站架构中也采用分层结构,将网站软件系统分为1.应用层、2.服务层、3.数据层,如表:
但是分层架构也有一些挑战,就是必须合理规划层次边界和接口,在开发过程中,严格遵循分层架构的约束,禁止跨层次的调用(应用层直接调用数据层)及逆向调用(数据层调用服务层,或者服务层调用应用层)。
2.分割
对软件进行纵向切分。
3.分布式
对于大型网站,分层和分割的一个主要目的是为了切分后的模块便于分布式部署,即将不同模块部署在不同的服务器上,通过远程调用协同工作。分布式意味着可以使用更多的计算机完成同样的功能,计算机越多,CPU、内存、存储资源也就越多,能够处理的并发访问和数据量就越大,进而能够为更多的用户提供服务。
在网站应用中,常用的分布式方案有如下几种:
1.分布式应用和服务
将分层和分割后的应用和服务模块分布式部署,除了可以改善网站性能和并发性、加快开发和发布速度、减少数据库连接资源消耗外;还可以使不同应用复用共同的服务,便于业务功能扩展。
2.分布式静态资源
网站的静态资源如JS, CSS, Logo图片等资源独立分布式部署,并采用独立的域名,即人们常说的动静分离。静态资源分布式部署可以减轻应用服务器的负载压力;通过使用独立域名加快浏览器并发加载的速度;由负责用户体验的团队进行开发维护有利于网站分工合作,使不同技术工种术业有专攻。
3.分布式数据和存储
大型网站需要处理以P为单位的海量数据,单台计算机无法提供如此大的存储空间,这些数据需要分布式存储。除了对传统的关系数据库进行分布式部署外,为网站应用而生的各种NoSQL产品几乎都是分布式的。
4.分布式计算
目前网站普遍使用Hadoop及其M apR educe分布式计算框架进行此类批处理计算,其特点是移动计算而不是移动数据,将计算程序分发到数据所在的位置以加速计算和分布式计算。
4.集群
5.缓存
缓存就是将数据存放在距离计算最近的位置以加快处理速度。缓存是改善软件性能的第一手段,现代CPU越来越快的一个重要因素就是使用了更多的缓存,在复杂的软件设计中,缓存几乎无处不在。大型网站架构设计在很多方面都使用了缓存设计。
使用缓存的例子:CDN,反向代理,本地缓存,分布式缓存。
使用缓存有两个前提条件:
1.数据访问热点不均衡。
2.数据在某个时间段内有效,不会很快过期,否则缓存的数据就会因已经失效而产生脏读,影响了结果的正确性。
6.异步
7.冗余
8.自动化
9.安全
新浪微博的架构在较短的时间内几经重构,最终形成了现在的架构:
系统分为三个层次,最下层是基础服务层,提供数据库,缓存,存储,搜索等数据服务,以及其他一些基础技术服务,这些服务支撑了整个新浪微博的海量数据和高并发访问,是整个系统的技术基础。
中间层是平台服务和应用服务层,新浪微博的核心服务是微博、关系和用户,它们是新浪微博业务大厦的支柱。这些服务被分割为独立的服务模块,通过依赖调用和共享基础数据构成新浪微博的业务基础。
最上层是API和新浪微博的业务层,各种客户端(包括Web网站)和第三方应用,通过调用API集成到新浪微博的系统中,共同组成一个生态系统。
在新浪微博的早期架构中,微博发布使用同步推模式,用户发表微博后系统会立即将这条微博插入到数据库所有粉丝的订阅列表中,当用户量比较大时,特别是明星用户发布微博时,会引起大量的数据库写操作,超出数据库负载,系统性能急剧下降,用户响应延迟加剧。后来新浪微博改用异步推拉结合的模式,用户发表微博后系统将微博写入消息队列后立即返回,用户响应迅速,消息队列消费者任务将微博推送给所有当前在线粉丝的订阅列表中,非在线用户登录后再根据关注列表拉取微博订阅列表。
关于什么是架构,一种比较通俗的说法是“最高层次的规划,难以改变的决定”,这些规划和决定奠定了事物未来发展的方向和最终的蓝图。
性能是网站的一个重要指标,除非是没得选择(比如只能到www.12306.cn这一个网站上买火车票),否则用户无法忍受一个响应缓慢的网站。一个打开缓慢的网站会导致严重的用户流失,很多时候网站性能问题是网站架构升级优化的触发器。可以说性能是网站架构设计的一个重要方面,任何软件架构设计方案都必须考虑可能会带来的性能问题。
也正是因为性能问题几乎无处不在,所以优化网站性能的手段也非常多,从用户浏览器到数据库,影响用户请求的所有环节都可以进行性能优化。
在浏览器端,可以通过浏览器缓存、使用页面压缩、合理布局页面、减少Cookie传输等手段改善性能。
还可以使用CDN,将网站静态内容分发至离用户最近的网络服务商机房,使用户通过最短访问路径获取数据。可以在网站机房部署反向代理服务器,缓存热点文件,加快请求响应速度,减轻应用服务器负载压力。
在应用服务器端,可以使用服务器本地缓存和分布式缓存,通过缓存在内存中的热点数据处理用户请求,加快请求处理过程,减轻数据库负载压力。
也可以通过异步操作将用户请求发送至消息队列等待后续任务处理,而当前请求直接返回响应给用户。
在网站有很多用户高并发请求的情况下,可以将多台应用服务器组成一个集群共同对外服务,提高整体处理能力,改善性能。
在代码层面,也可以通过使用多线程、改善内存管理等手段优化性能。
在数据库服务器端,索引、缓存、SQL优化等性能优化手段都已经比较成熟。而方兴未艾的NoSQL数据库通过优化数据模型、存储结构、伸缩特性等手段在性能方面的优势也日趋明显。
衡量网站性能有一系列指标,重要的有响应时间、TPS、系统性能计数器等,通过测试这些指标以确定系统设计是否达到目标。这些指标也是网站监控的重要参数,通过监控这些指标可以分析系统瓶颈,预测网站容量,并对异常指标进行报警,保障系统可用性。
网站高可用的主要手段是冗余,应用部署在多台服务器上同时提供访问,数据存储在多台服务器上互相备份,任何一台服务器宕机都不会影响应用的整体可用,也不会导致数据丢失。
对于应用服务器而言,多台应用服务器通过负载均衡设备组成一个集群共同对外提供服务,任何一台服务器宕机,只需把请求切换到其他服务器就可实现应用的高可用,但是一个前提条件是应用服务器上不能保存请求的会话信息。否则服务器宕机,会话丢失,即使将用户请求转发到其他服务器上也无法完成业务处理。
衡量架构伸缩性的主要标准就是是否可以用多台服务器构建集群,是否容易向集群中添加新的服务器。加入新的服务器后是否可以提供和原来的服务器无差别的服务。集群中可容纳的总的服务器数量是否有限制。
不同于其他架构要素主要关注非功能性需求,网站的扩展性架构直接关注网站的功能需求。网站快速发展,功能不断扩展,如何设计网站的架构使其能够快速响应需求变化,是网站可扩展架构主要的目的。
网站可伸缩架构的主要手段是事件驱动架构和分布式服务。
事件驱动架构在网站通常利用消息队列实现,将用户请求和其他业务事件构造成消息发布到消息队列,消息的处理者作为消费者从消息队列中获取消息进行处理。通过这种方式将消息产生和消息处理分离开来,可以透明地增加新的消息生产者任务或者新的消息消费者任务。
分布式服务则是将业务和可复用服务分离开来,通过分布式服务框架调用。新增产品可以通过调用可复用的服务实现自身的业务逻辑,而对现有产品没有任何影响。可复用服务升级变更的时候,也可以通过提供多版本服务对应用实现透明升级,不需要强制应用同步变更。
性能,可用性,伸缩性,扩展性和安全性是网站架构最核心的几个要素。
网站性能是客观的指标,可以具体体现到响应时间、吞吐量等技术指标,同时也是主观的感受,而感受则是一种与具体参与者相关的微妙的东西,用户的感受和工程师的感受不同,不同的用户感受也不同。
2.性能测试指标
主要指标有响应时间,并发数,吞吐量,性能计数器等:
1.响应时间
指应用执行一个操作需要的时间,包括从发出请求开始收到最后响应数据所需要的时间。响应时间是系统最重要的性能指标,直观地反映了系统的“快慢”。
2.并发数
指系统能够同时处理请求的数目,这个数字也反映了系统的负载特性。
注意厘清数量关系:
网站系统用户数>>网站在线用户数>>网站并发用户数
3.吞吐量
指单位时间内系统处理的请求数量,体现了系统的整体处理能力。TPS(每秒事务数)是吞吐量的一个常用量化指标,此外还有HPS(每秒HTTP请求数)、QPS(每秒查询数)等。
系统吞吐量和系统并发数,以及响应时间的关系可以形象地理解为高速公路的通行状况:
吞吐量是每天通过收费站的车辆数目(可以换算成收费站收取的高速费),并发数是高速公路上的正在行驶的车辆数目,响应时间是车速。
车辆很少时,车速很快,但是收到的高速费也相应较少;随着高速公路上车辆数目的增多,车速略受影响,但是收到的高速费增加很快;随着车辆的继续增加,车速变得越来越慢,高速公路越来越堵,收费不增反降;如果车流量继续增加,超过某个极限后,任何偶然因素都会导致高速全部瘫痪,车走不动,费当然也收不着,而高速公路成了停车场(资源耗尽)。
4.性能计数器
System Load即系统负载,指当前正在被CPU执行和等待被CPU执行的进程数目总和,是反映系统忙闲程度的重要指标。多核CPU的情况下,完美情况是所有CPU都在使用,没有进程在等待处理,所以Load的理想值是CPU的数目。当Load值低于CPU数目的时候,表示CPU有空闲,资源存在浪费;当Load值高于CPU数目的时候,表示进程在排队等待CPU调度,表示系统资源不足,影响应用程序的执行性能。在Linux系统中使用top命令查看,该值是三个浮点数,表示最近1分钟,10分钟,15分钟的运行队列平均进程数。
3.性能测试方法
性能测试是一个总称,具体可以细分为性能测试,负载测试,压力测试,稳定性测试。
4.性能优化方法
定位产生性能问题的具体原因后,就需要进行性能优化,根据网站分层架构,可分为1.Web前端性能优化、2.应用服务器性能优化、**3.存储服务器性能优化**3大类。
1.浏览器访问优化
1.减少http请求
HTTP协议是无状态的应用层协议,意味着每次HTTP请求都需要建立通信链路、进行数据传输,而在服务器端,每个HTTP都需要启动独立的线程去处理。这些通信和服务的开销都很昂贵,减少HTTP请求的数目可有效提高访问性能。
减少HTTP的主要手段是合并CSS、合并JavaScript、合并图片。将浏览器一次访问需要的JavaScript、CSS合并成一个文件,这样浏览器就只需要一次请求。图片也可以合并,多张图片合并成一张,如果每张图片都有不同的超链接,可通过CSS偏移响应鼠标点击操作,构造不同的URL。
2.使用浏览器缓存
对于一个网站而言,CSS,JS,logo,图标这些静态资源文件更新的频率都比较低,而这些文件又几乎是每次HTTP请求都需要的,如果将这些文件缓存在浏览器中,可以极好地改善性能。通过设置HTTP头中的Cache-Control和Expires的属性,可设定浏览器缓存,缓存时间可以是数天,甚至是几个月。
3.启用压缩
4.CSS放在页面最上面,JS放在页面最下面
5.减少Cookie传输
一方面,Cookie包含在每次请求和响应中,太大的C ookie会严重影响数据传输,因此哪些数据需要写入C ookie需要慎重考虑,尽量减少C ookie中传输的数据量。另一方面,对于某些静态资源的访问,如CSS、Script等,发送C ookie没有意义,可以考虑静态资源使用独立域名访问,避免请求静态资源时发送C ookie,减少C ookie传输的次数。
2.CDN加速
CDN能够缓存的一般是静态资源,如图片、文件、CSS、Script脚本、静态网页等,但是这些文件访问频度很高,将其缓存在CDN可极大改善网页的打开速度。
3.反向代理
应用服务器就是处理网站业务的服务器,网站的业务代码都部署在这里,是网站开发最复杂,变化最多的地方,优化手段主要是缓存,集群,异步等。
1.分布式缓存
缓存的基本原理:
缓存指将数据存储在相对较高访问速度的存储介质中,以供系统处理。一方面缓存访问速度快,可以减少数据访问的时间,另一方面如果缓存的数据是经过计算处理得到的,那么被缓存的数据无需重复计算即可直接使用,因此缓存还起到减少计算时间的作用。
不合理使用缓存的例子:
1.频繁修改的数据
一般来说,数据的读写比在2:1以上,即写入一次缓存,在数据更新前至少读取两次,缓存才有意义。在实践中,这个比例通常非常高,例如新浪热门微博,缓存以后可能会被读取数百万次。
2.没有热点的访问
3.数据不一致与脏读
一般会对缓存的数据设置失效时间,一旦超过失效时间,就要从数据库中重新加载。因此应用要容忍一定时间的数据不一致,如卖家已经编辑了商品属性,但是需要过一段时间才能被买家看到。在互联网应用中,这种延迟通常是可以接受的,但是具体应用仍需慎重对待。还有一种策略是数据更新时立即更新缓存,不过这也会带来更多系统开销和事务一致性的问题。
4.缓存可用性
通过分布式缓存服务器集群,将缓存数据分布到集群多台服务器上可在一定程度上改善缓存的可用性。当一台缓存服务器宕机的时候,只有部分缓存数据丢失,重新从数据库加载这部分数据不会对数据库产生很大影响。
5.缓存预热
缓存中存放的是热点数据,热点数据又是缓存系统利用LRU(最近最久未用算法)对不断访问的数据筛选淘汰出来的,这个过程需要花费较长的时间。新启动的缓存系统如果没有任何数据,在重建缓存数据的过程中,系统的性能和数据库负载都不太好,那么最好在缓存系统启动时就把热点数据加载好,这个缓存预加载手段叫作缓存预热(warm up)。对于一些元数据如城市地名列表、类目信息,可以在启动时加载数据库中全部数据到缓存进行预热。
6.缓存穿透
如果因为不恰当的业务、或者恶意攻击持续高并发地请求某个不存在的数据,由于缓存没有保存该数据,所有的请求都会落到数据库上,会对数据库造成很大压力,甚至崩溃。一个简单的对策是将不存在的数据也缓存起来(其value值为null)。
分布式缓存架构
分布式缓存指缓存部署在多个服务器组成的集群中,以集群方式提供缓存服务,其架构方式有两种,一种是以JBoss C ache为代表的需要更新同步的分布式缓存,一种是以Memcached为代表的不互相通信的分布式缓存。
Memcached
2.异步操作
需要注意的是,由于数据写入消息队列后立即返回给用户,数据在后续的业务校验、写数据库等操作可能失败,因此在使用消息队列进行业务异步处理后,需要适当修改业务流程进行配合,如订单提交后,订单数据写入消息队列,不能立即返回用户订单提交成功,需要在消息队列的订单消费者进程真正处理完该订单,甚至商品出库后,再通过电子邮件或SM S消息通知用户订单成功,以免交易纠纷。
任何可以晚点做的事情都应该晚点再做。保证数据的正确性
3.使用集群
4.代码优化
1.多线程
从资源利用的角度看,使用多线程的原因主要有两个:IO阻塞与多CPU。
网站的应用程序一般都被Web服务器容器管理,用户请求的多线程也通常被Web服务器容器管理,但不管是Web容器管理的线程,还是应用程序自己创建的线程,一台服务器上启动多少线程合适呢?
假设服务器上执行的都是相同类型任务,针对该类任务启动的线程数有个简化的估算公式可供参考:
启动线程数=[任务执行时间/(任务执行时间×IO等待时间)]×CPU内核数
最佳启动线程数和CPU内核数量成正比,和IO阻塞时间成反比。如果任务都是CPU计算型任务,那么线程数最多不超过CPU内核数,因为启动再多线程,CPU也来不及调度;相反如果是任务需要等待磁盘操作,网络响应,那么多启动线程有助于提高任务并发度,提高系统吞吐能力,改善系统性能。(看是CPU计算型还是磁盘操作!)
多线程需要注意线程安全的问题,这也是缺乏经验的网站工程师最容易犯错的地方,而线程安全B ug又难以测试和重现,网站故障中,许多所谓偶然发生的“灵异事件”都和多线程并发问题有关。对网站而言,不管有没有进行多线程编程,工程师写的每一行代码都会被多线程执行,因为用户请求是并发提交的,也就是说,所有的资源——对象、内存、文件、数据库,乃至另一个线程都可能被多线程并发访问。
2.资源复用
系统运行时,要尽量减少那些开销很大的系统资源的创建和销毁,比如数据库连接、网络通信连接、线程、复杂对象等。从编程角度,资源复用主要有两种模式:单例(Singleton)和对象池(Object Pool)。
单例虽然是GoF经典设计模式中较多被诟病的一个模式,但由于目前Web开发中主要使用贫血模式,从Service到D ao都是些无状态对象,无需重复创建,使用单例模式也就自然而然了。事实上,Java开发常用的对象容器Spring默认构造的对象都是单例(需要注意的是Spring的单例是Spring容器管理的单例,而不是用单例模式构造的单例)。
前面说过,对于每个Web请求(HTTP Request), Web应用服务器都需要创建一个独立的线程去处理,这方面,应用服务器也采用线程池(Thread Pool)的方式。这些所谓的连接池、线程池,本质上都是对象池,即连接、线程都是对象,池管理方式也基本相同。
1.机械硬盘VS固态硬盘
机械硬盘是目前最常用的一种硬盘,通过马达驱动磁头臂,带动磁头到指定的磁盘位置访问数据,由于每次访问数据都需要移动磁头臂,因此机械硬盘在数据连续访问(要访问的数据存储在连续的磁盘空间上)和随机访问(要访问的数据存储在不连续的磁盘空间)时,由于移动磁头臂的次数相差巨大,性能表现差别也非常大。
2.B+树.VS.LSM树
本书前面提到,由于传统的机械磁盘具有快速顺序读写、慢速随机读写的访问特性,这个特性对磁盘存储结构和算法的选择影响甚大。
通常会对数据排序后存储,加快数据检索速度,这就需要保证数据在不断更新、插入、删除后依然有序,传统关系数据库的做法是使用B+树。
目前许多NoSQL产品采用LSM树作为主要数据结构。
3.RAID.VS.HDFS
RAID技术可以通过硬件实现,比如专用的RAID卡或者主板直接支持,也可以通过软件实现。RAID技术在传统关系数据库及文件系统中应用比较广泛,但是在大型网站比较喜欢使用的NoSQL,以及分布式文件系统中,RAID技术却遭到冷落。
现在一般用HDFS,HDFS配合M apR educe等并行计算框架进行大数据处理时,可以在整个集群上并发读写访问所有的磁盘,无需RAID支持。
网站的页面能完整呈现在最终用户面前,需要经过很多个环节,任何一个环节出了问题,都可能导致网站页面不可访问。DNS会被劫持、CDN服务可能会挂掉、网站服务器可能会宕机、网络交换机可能会失效、硬盘会损坏、网卡会松掉、甚至机房会停电、空调会失灵、程序会有B ug、黑客会攻击、促销会引来大量访问、第三方合作伙伴的服务会不可用……要保证一个网站永远完全可用几乎是一件不可能完成的使命。
典型的分层模型是三层,即应用层、服务层、数据层;各层之间具有相对独立性,应用层主要负责具体业务逻辑处理;服务层负责提供可复用的服务;数据层负责数据的存储与访问。中小型网站在具体部署时,通常将应用层和服务层部署在一起,而数据层则另外部署,如图5.3所示(事实上,这也是网站架构演化的第一步)。
在复杂的大型网站架构中,划分的粒度会更小,更详细,结构更加复杂,但通常还是可以将服务器划分到这三层中。
应用层:
位于应用层的服务器通常为了应对高并发的访问请求,会通过负载均衡设备将一组服务器组成一个集群共同对外提供服务,当负载均衡设备通过心跳检测等手段监控到某台应用服务器不可用时,就将其从集群列表中剔除,并将请求分发到集群中其他可用的服务器上,使整个集群保持可用,从而实现应用高可用。
服务层:
位于服务层的服务器情况和应用层的服务器类似,也是通过集群方式实现高可用,只是这些服务器被应用层通过分布式服务调用框架访问,分布式服务调用框架会在应用层客户端程序中实现软件负载均衡,并通过服务注册中心对提供服务的服务器进行心跳检测,发现有服务不可用,立即通知客户端程序修改服务访问列表,剔除不可用的服务器。
数据层:
位于数据层的服务器情况比较特殊,数据服务器上存储着数据,为了保证服务器宕机时数据不丢失,数据访问服务不中断,需要在数据写入时进行数据同步复制,将数据写入多台服务器上,实现数据冗余备份。当数据服务器宕机时,应用程序将访问切换到有备份数据的服务器上。
应用层主要处理网站应用的业务逻辑,因此有时也称作业务逻辑层,应用的一个显著特点是应用的无状态性。
所谓无状态的应用是指应用服务器不保存业务的上下文信息,而仅根据每次请求提交的数据进行相应的业务逻辑处理,多个服务实例(服务器)之间完全对等,请求提交到任意服务器,处理结果都是完全一样的。
1.通过负载均衡进行无状态服务的失效转移
2.应用服务器集群的Session管理
应用服务器的高可用架构设计主要基于服务无状态这一特性,但是事实上,业务总是有状态的,在交易类的电子商务网站,需要有购物车记录用户的购买信息,用户每次购买请求都是向购物车中增加商品;在社交类的网站中,需要记录用户的当前登录状态、最新发布的消息及好友状态等,用户每次刷新页面都需要更新这些信息。
Web应用中将这些多次请求修改使用的上下文对象称作会话(Session),单机情况下,Session可由部署在服务器上的Web容器(如JBoss)管理。在使用负载均衡的集群环境中,由于负载均衡服务器可能会将请求分发到集群任何一台应用服务器上,所以保证每次请求依然能够获得正确的Session比单机时要复杂很多。
集群环境下,Session管理主要有以下几种手段。
1.Session复制
原理很简单,在集群中的几台服务器之间同步Session对象,使得每台服务器上都保存有用户的Session信息,这样任何一台服务器宕机,都可以在其他服务器上找到Session。
缺点是,大量用户访问的情况下,会出现服务器内存不够Session使用的情况。
而大型网站的核心应用集群就是数千台服务器,同时在线用户可达千万,因此并不适用这种方案。
2.Session绑定
Session绑定可以利用负载均衡的源地址Hash算法实现,负载均衡服务器总是将来自同一IP的请求分发到同一台服务器上,这种方法又被称作为会话粘滞。
但Session绑定的方案不符合我们的要求,如果一台服务器宕机,那么该服务器上的Session将不存在,用户请求切换后无法完成业务。
因此虽然大部分负载均衡服务器都提供源地址负载均衡算法,但很少有网站利用这个算法进行Session管理。
3.利用Cookie记录Session
利用Cookie记录Session也有缺点,比如受Cookie大小限制,能记录的信息有限,每次请求响应都需要传输Cookie,影响性能;如果用户关闭C ookie,访问就会不正常。但是由于C ookie的简单易用,可用性高,支持应用服务器的线性伸缩,而大部分应用需要记录的Session信息又比较小。因此事实上,许多网站都或多或少地使用C ookie记录Session。
4.Session服务器
那么有没有可用性高、伸缩性好、性能也不错,对信息大小又没有限制的服务器集群Session管理方案呢?
答案就是Session服务器。利用独立部署的Session服务器(集群)统一管理S ession,应用服务器每次读写Session时,都访问Session服务器,如图所示。
这种解决方案事实上是将应用服务器的状态分离,分为无状态的应用服务器和有状态的Session服务器,然后针对这两种服务器的不同特性分别设计其架构。
对于有状态的Session服务器,一种比较简单的方法是利用分布式缓存、数据库等,在这些产品的基础上进行包装,使其符合Session的存储和访问要求。如果业务场景对Session管理有比较高的要求,比如利用Session服务集成单点登录(SSO)、用户服务等功能,则需要开发专门的Session服务管理平台。
保证数据存储高可用的手段主要是1.数据备份和2.失效转移机制。数据备份是保证数据有多个副本,任意副本的失效都不会导致数据的永久丢失,从而实现数据完全的持久化。而失效转移机制则保证当一个数据副本不可访问时,可以快速切换访问数据的其他副本,保证系统可用。
关于缓存服务的高可用,在实践中争议很大,一种观点认为缓存已经成为网站数据服务的重要组成部分,事实上承担了业务中绝大多数的数据读取访问服务,缓存服务失效可能会导致数据库负载过高而宕机,进而影响整个网站的可用性,因此缓存服务需要实现和数据存储服务同样的高可用。
另一种观点认为,缓存服务不是数据存储服务,缓存服务器宕机引起缓存数据丢失导致服务器负载压力过高应该通过其他手段解决,而不是提高缓存服务本身的高可用。
笔者持后一种观点,对于缓存服务器集群中的单机宕机,如果缓存服务器集群规模较大,那么单机宕机引起的缓存数据丢失比例和数据库负载压力变化都较小,对整个系统影响也较小。扩大缓存服务器集群规模的一个简单手段就是整个网站共享同一个分布式缓存集群,单独的应用和产品不需要部署自己的缓存服务器,只需要向共享缓存集群申请缓存资源即可。并且通过逻辑或物理分区的方式将每个应用的缓存部署在多台服务器上,任何一台服务器宕机引起的缓存失效都只影响应用缓存数据的一小部分,不会对应用性能和数据库负载造成太大影响。
C AP原理:
在讨论高可用数据服务架构之前,必须先讨论的一个话题是,为了保证数据的高可用,网站通常会牺牲另一个也很重要的指标:数据一致性。也就是说,数据的高可用性跟数据的一致性不可兼得。
高可用的数据有如下几个层面的含义。
1.数据持久性
2.数据的可访问性
3.数据一致性
CAP原理认为,一个提供数据服务的存储系统无法同时满足数据一致性(C onsistency)、数据可用性(A vailib ility)、分区耐受性(Patition Tolerance,系统具有跨网络分区的伸缩性)这三个条件,如图。
在大型网站中,通常会选择强化分布式存储系统的可用性(A)和伸缩性(P),而在某种程度上放弃一致性(C)。
数据一致性可以分为如下几点:
1.数据强一致
各个副本的数据在物理存储中总是一致的,数据更新操作结果和操作响应总是一致的,即操作响应通知更新失败,那么数据一定没有被更新,而不是处于不确定状态。
2.数据用户一致
数据在物理存储中的各个副本的数据可能是不一致的,但是终端用户访问时,通过纠错和校验机制,可以确定一个一致的且正确的数据返回给用户。
3.数据最终一致
这是数据一致性中较弱的一种,即物理存储的数据可能是不一致的,终端用户访问到的数据可能也是不一致的(同一用户连续访问,结果不同;或者不同用户同时访问,结果不同),但系统经过一段时间(通常是一个比较短的时间段)的自我恢复和修正,数据最终会达到一致。
关系数据库热备机制就是通常所说的M aster-S lave同步机制。M aster-S lave机制不但解决了数据备份问题,还改善了数据库系统的性能,实践中,通常使用读写分离的方法访问S lave和M aster数据库,写操作只访问M aster数据库,读操作只访问S lave数据库。
关于数据的失效转移:
失效转移操作主要由三部分组成:1.失效确认,2.失效转移,3.数据恢复
1.失效确认
判断服务器宕机是系统进行失效转移的第一步,系统确认一台服务器是否宕机的手段有两种:1.心跳检测和2.应用程序访问失败报告,如图。
2.访问转移
3.数据恢复
网站发布的流程:
网站发布毕竟是一次提前预知的服务器宕机,所以过程可以更柔和,对用户影响更小。通常使用发布脚本来完成发布,其流程如图。
目前大部分网站都采用Web自动化测试技术,使用自动测试工具或脚本完成测试。比较流行的Web自动化测试工具是ThoughtW orks开发的Selenium。Selenium运行在浏览器中,模拟用户操作进行测试,因此Selenium可以同时完成Web功能测试和浏览器兼容测试。
在网站发布时,并不是把测试通过的代码包直接发布到线上服务器,而是先发布到预发布机器上,开发工程师和测试工程师在预发布服务器上进行预发布验证,执行一些典型的业务流程,确认系统没有问题后才正式发布。
所谓网站的伸缩性是指不需要改变网站的软硬件设计,仅仅通过改变部署服务器数量就可以扩大或者缩小网站的服务处理能力。
回顾网站架构发展历程, 网站架构发展史就是一部不断向网站添加服务器的历史。只要工程师能向网站的服务器集群中添加新的机器,只要新添加的服务器能线性提高网站的整体服务处理能力,网站就无需为不断增长的用户和访问而焦虑。
实现负载均衡的主要算法:
这种负载均衡方案的优点是比较简单。缺点是浏览器需要两次请求服务器才能完成一次访问,性能较差;重定向服务器自身的处理能力有可能成为瓶颈,整个集群的伸缩性规模有限;使用HTTP302响应码重定向,有可能使搜索引擎判断为SEO作弊,降低搜索排名。因此实践中使用这种方案进行负载均衡的案例并不多见。
在DNS服务器中配置多个A记录,如:www.m ysite.com IN A 114.100.80.1、www.m ysite.com IN A 114.100.80.2、www.m ysite.com IN A 114.100.80.3。
每次域名解析请求都会根据负载均衡算法计算一个不同的IP地址返回,这样A记录中配置的多个服务器就构成一个集群,并可以实现负载均衡。
DNS域名解析负载均衡的优点是将负载均衡的工作转交给DNS,省掉了网站管理维护负载均衡服务器的麻烦,同时许多DNS还支持基于地理位置的域名解析,即会将域名解析成距离用户地理最近的一个服务器地址,这样可加快用户访问速度,改善性能。但是DNS域名解析负载均衡也有缺点,就是1.目前的DNS是多级解析,每一级DNS都可能缓存A记录,当下线某台服务器后,即使修改了DNS的A记录,要使其生效也需要较长时间,这段时间,DNS依然会将域名解析到已经下线的服务器,导致用户访问失败;而且2.DNS负载均衡的控制权在域名服务商那里,网站无法对其做更多改善和更强大的管理。
事实上,大型网站总是部分使用DNS域名解析,利用域名解析作为第一级负载均衡手段,即域名解析得到的一组服务器并不是实际提供Web服务的物理服务器,而是同样提供负载均衡服务的内部服务器,这组内部负载均衡服务器再进行负载均衡,将请求分发到真实的Web服务器上。
大型网站利用DNS域名解析作为第一级的负载均衡手段。
前面我们提到利用反向代理缓存资源,以改善网站性能。实际上,在部署位置上,反向代理服务器处于Web服务器前面(这样才可能缓存Web响应,加速访问),这个位置也正好是负载均衡服务器的位置,所以大多数反向代理服务器同时提供负载均衡的功能,管理一组Web服务器,将请求根据负载均衡算法转发到不同Web服务器上。Web服务器处理完成的响应也需要通过反向代理服务器返回给用户。由于Web服务器不直接对外提供访问,因此Web服务器不需要使用外部IP地址,而反向代理服务器则需要配置双网卡和内部外部两套IP地址。
由于反向代理服务器转发请求在HTTP协议层面,因此也叫应用层负载均衡。其优点是和反向代理服务器功能集成在一起,部署简单。缺点是反向代理服务器是所有请求和响应的中转站,其性能可能会成为瓶颈。
4.IP负载均衡
5.数据链路层负载均衡
顾名思义,数据链路层负载均衡是指在通信协议的数据链路层修改mac地址进行负载均衡。
这种数据传输方式又称作三角传输模式,负载均衡数据分发过程中不修改IP地址,只修改目的m ac地址,通过配置真实物理服务器集群所有机器虚拟IP和负载均衡服务器IP地址一致,从而达到不修改数据包的源地址和目的地址就可以进行数据分发的目的,由于实际处理请求的真实物理服务器IP和数据请求目的IP一致,不需要通过负载均衡服务器进行地址转换,可将响应数据包直接返回给用户浏览器,避免负载均衡服务器网卡带宽成为瓶颈。这种负载均衡方式又称作直接路由方式(DR)。
使用三角传输模式的链路层负载均衡是目前大型网站使用最广的一种负载均衡手段。在Linux平台上最好的链路层负载均衡开源产品是LVS(Linux V irtual Server)。
6.负载均衡算法
负载均衡服务器的实现分成两个部分:
1.根据负载均衡算法和Web服务器列表计算得到集群中一台Web服务器的地址。
2.将请求数据发送到该地址对应的Web服务器上。
前面描述了如何将请求数据发送到Web服务器上,而具体的负载均衡算法通常有如下几种:
1.轮询(RR)
2.加权轮询(WRR)
3.随机(Random)
4.最少连接(Least Connections)
记录每个应用服务器正在处理的连接数(请求数),将新到的请求分发到最少连接的服务器上,应该说,这是最符合负载均衡定义的算法。同样,最小连接算法也可以实现加权最少连接。
5.源地址散列(Source Hashing)
我们在本书第4章讨论过分布式缓存,不同于应用服务器集群的伸缩性设计,分布式缓存集群的伸缩性不能使用简单的负载均衡手段来实现。
必须让新上线的缓存服务器对整个分布式缓存集群影响最小,也就是说新加入缓存服务器后应使整个缓存服务器集群中已经缓存的数据尽可能还被访问到,这是分布式缓存集群伸缩性设计的最主要目标。
1.Memcached分布式缓存集群的访问模型
如果使用朴素的Hash路由算法,将会出现问题。本来加入新的缓存服务器是为了降低数据库的负载压力,但是操作不当却导致了数据库的崩溃。如果不对问题和解决方案有透彻了解,网站技术总有想不到的陷阱让架构师一脚踩空。遇到这种情况,用某网站一位资深架构师的话说,就是“一股寒气从脚底板窜到了脑门心”。
能不能通过改进路由算法,使得新加入的服务器不影响大部分缓存数据的正确命中呢?目前比较流行的算法是一致性Hash算法。
一致性Hash算法也有小问题。
计算机领域有句话:计算机的任何问题都可以通过增加一个虚拟层来解决。计算机硬件、计算机网络、计算机软件都莫不如此。计算机网络的7层协议,每一层都可以看作是下一层的虚拟层;计算机操作系统可以看作是计算机硬件的虚拟层;Java虚拟机可以看作是操作系统的虚拟层;分层的计算机软件架构事实上也是利用虚拟层的概念。
解决上述一致性Hash算法带来的负载不均衡问题,也可以通过使用虚拟层的手段:将每台物理缓存服务器虚拟为一组虚拟缓存服务器,将虚拟服务器的Hash值放置在Hash环上,KEY在环上先找到虚拟服务器节点,再得到物理服务器的信息。
1.关系性数据库集群的伸缩性设计
目前网站在线业务应用中比较成熟的支持数据分片的分布式关系数据库产品主要有Cobar。其架构图如下。
前端通信模块负责和应用程序通信,接收到SQL请求(select * from users where userid in (12,22,23))后转交给SQL解析模块,SQL解析模块解析获得SQL中的路由规则查询条件(userid in(12,22,23))再转交给SQL路由模块,SQL路由模块根据路由规则配置(userid为偶数路由至数据库A, userid为奇数路由至数据库B)将应用程序提交的SQL分解成两条SQ L(select * from users w here userid in (12,22);select * from users w here userid in (23);)转交给SQL执行代理模块,发送至数据库A和数据库B分别执行。
数据库A和数据库B的执行结果返回至SQL执行模块,通过结果合并模块将两个返回结果集合并成一个结果集,最终返回给应用程序,完成在分布式数据库中的一次访问请求。
那么Cobar如何做集群的伸缩呢?
Cobar的伸缩有两种:1.Cobar服务器集群的伸缩和2.MySQL服务器集群的伸缩。
2.NoSQL数据库的伸缩性设计
大型网站遇到了关系数据库难以克服的缺陷——糟糕的海量数据处理能力及僵硬的设计约束,局面才有所改善。为了解决上述问题,NoSQL这一概念被提了出来,以弥补关系数据库的不足。
NoSQL,主要指非关系的、分布式的数据库设计模式。也有许多专家将NoSQL解读为N ot O nly SQ L,表示NoSQL只是关系数据库的补充,而不是替代方案。一般而言,NoSQL数据库产品都放弃了关系数据库的两大重要基础:以关系代数为基础的结构化查询语言(SQL)和事务一致性保证(ACID)。而强化其他一些大型网站更关注的特性:高可用性和可伸缩性。
开源社区有各种N oSQL产品,其支持的数据结构和伸缩特性也各不相同,目前看来,应用最广泛的是Apache HBase。
高手定律:
这个世界只有遇不到的问题,没有解决不了的问题,高手之所以成为高手,是因为他们遇到了常人很难遇到的问题,并解决了。所以百度有很多广告搜索的高手,淘宝有很多海量数据的高手,Q Q有很多高并发业务的高手,原因大抵如此。一个100万用户的网站,不会遇到1亿用户同时在线的问题;一个拥有100万件商品网站的工程师,可能无法理解一个拥有10亿件商品网站的架构。
救世主定律:
遇到问题,分析问题,最后总能解决问题。如果遇到问题就急匆匆地从外面挖一个高手,然后指望高手如探囊取物般轻松搞定,最后怕是只有彼此抱怨和伤害。许多问题只是看起来一样,具体问题总是要具体对待的,没有银弹,没有救世主。所以这个定律准确地说应该是“没有救世主定律”。
网站扩展性架构设计:对现有系统影响最小的情况下,系统功能可持续扩展及提升的能力。
首先厘清容易混淆的两个概念:
1.扩展性(Extensibility):
指对现有系统影响最小的情况下,系统功能可持续扩展或提升的能力。表现在系统基础设施稳定不需要经常变更,应用之间较少依赖和耦合,对需求变更可以敏捷响应。它是系统架构设计层面的开闭原则(对扩展开放,对修改关闭),架构设计考虑未来功能扩展,当系统增加新功能时,不需要对现有系统的结构和代码进行修改。
2.伸缩性(Scalability):
指系统能够通过增加(减少)自身资源规模的方式增强(减少)自己计算处理事务的能力。如果这种增减是成比例的,就被称作线性伸缩性。在网站架构中,通常指利用集群的方式增加服务器数量、提高系统的整体事务吞吐能力。
如果模块之间不存在直接调用,那么新增模块或者修改模块就对其他模块影响最小,这样系统的可扩展性无疑更好一些。
1.事件驱动架构:
事件驱动架构(Event Driven Architecture):通过在低耦合的模块之间传输事件消息,以保持模块的松散耦合,并借助事件消息的通信完成模块间合作,典型的EDA架构就是操作系统中常见的生产者消费者模式。在大型网站架构中,具体实现手段有很多,最常用的是分布式消息队列,如图所示。
目前开源的和商业的分布式消息队列产品有很多,比较著名的如Apache ActiveMQ等,这些产品除了实现分布式消息队列的一般功能,在可用性、伸缩性、数据一致性、性能和可管理性方面也做了很多改善。
巨无霸的应用系统会带来很多问题:
1.编译,部署困难
2.代码分支管理困难
3.数据库连接耗尽
4.新增业务困难
解决方案就是拆分,将模块独立部署,降低系统耦合性。拆分可以分为纵向拆分和横向拆分两种。
纵向拆分:将一个大应用拆分为多个小应用,如果新增业务较为独立,那么就直接将其设计部署为一个独立的Web应用系统。
横向拆分:将复用的业务拆分出来,独立部署为分布式服务,新增业务只需要调用这些分布式服务,不需要依赖具体的模块代码,即可快速搭建一个应用系统,而模块内业务逻辑变化的时候,只要接口保持一致就不会影响业务程序和其他模块。
1.Web Service与企业级分布式服务
2.大型网站分布式服务的需求和特点
对于大型网站,除了Web Services所提供的服务注册与发现,服务调用等标准功能,还需要分布式服务框架能够支持如下功能。
1.负载均衡
2.失效转移
3.高效的远程通信
4.整合异构系统
5.对应用最少侵入
6.版本管理
7.实时监控
3.分布式服务框架设计
例如Facebook的Thrift。
服务消费者程序通过服务接口使用服务,而服务接口通过代理加载具体服务,具体服务可以是本地的代码模块,也可以是远程的服务,因此对应用较少侵入:应用程序只需要调用服务接口,服务框架根据配置自动调用本地或远程实现。
服务框架客户端模块通过服务注册中心加载服务提供者列表(服务提供者启动后自动向服务注册中心注册自己可提供的服务接口列表),查找需要的服务接口,并根据配置的负载均衡策略将服务调用请求发送到某台服务提供者服务器。如果服务调用失败,客户端模块会自动从服务提供者列表选择一个可提供同样服务的另一台服务器重新请求服务,实现服务的自动失效转移,保证服务高可用。
开放平台是网站内部和外部交互的接口,外部需要面对众多的第三方开发者,内部需要面对网站内诸多的业务服务。虽然每个网站的业务场景和需求都各不相同,但是开放平台的架构设计却大同小异,如图所示。
API接口:是开放平台暴露给开发者使用的一组API,其形式可以是RESTful、WebService、RPC等各种形式。
协议转换:将各种API输入转换成内部服务可以识别的形式,并将内部服务的返回封装成API的格式。
安全:除了一般应用需要的身份识别、权限控制等安全手段,开放平台还需要分级的访问带宽限制,保证平台资源被第三方应用公平合理使用,也保护网站内部服务不会被外部应用拖垮。
审计:记录第三方应用的访问情况,并进行监控、计费等。
路由:将开放平台的各种访问路由映射到具体的内部服务。
流程:将一组离散的服务组织成一个上下文相关的新服务,隐藏服务细节,提供统一接口供开发者调用。
既然我们知道网站不停上新产品是其生存的本能,谁能更快更好地推出更多的新产品,谁就活得更滋润,那么工程师就要做好准备应付这种局面。马克思的劳动价值理论告诉我们,产品的内在价值在于劳动的时间,劳动的时间不在于个体付出的劳动时间,而在于行业一般劳动时间,资本家只会为行业一般劳动时间买单,如果你的效率低于行业一般劳动时间,对不起,请你自愿加班。反之,如果你有一个更具有扩展性的网站架构,可以更快速地开发新产品,也许你也享受不了只上半天班的福利,但是至少在这个全行业加班的互联网领域,你能够按时下班,陪陪家人,看看星星。
Wikipedia架构的主要组成部分如下。
GeoDNS:基于开源域名服务器软件BIND(Berkeley Internet Name Domain)的增强版本,可将域名解析到离用户最近的服务器。
LVS:基于Linux的开源负载均衡服务器。
Squid:基于Linux的开源反向代理服务器。
Lighttpd:开源的应用服务器,较主流的Apache服务器更轻量、更快速。实践中,有许多网站使用L ighttpd作为图片服务器。
PHP:免费的Web应用程序开发语言,最流行的网站建站语言。
Memcached:无中心高性能的开源分布式缓存系统,稳定、可靠、历久弥新,是网站分布式缓存服务必备的。
Lucene:由Apache出品,Java开发的开源全文搜索引擎。
MySQL:开源的关系数据库管理系统,虽被Oracle收购,但开源社区将其继续开源发展的决心不动摇。
关于故障:
在讨论解决方案之前,我们先对故障进行分类,针对不同故障情况分别对待。对于一个分布式存储系统而言,影响系统整体可用性的故障可以分成以下三类。
× 瞬时故障:引起这类故障的主要原因是网络通信瞬时中断、服务器内存垃圾回收或后台线程繁忙停止数据访问操作响应。其特点是故障时间短,在秒级甚至毫秒级系统即可自行恢复正常响应。
× 临时故障:引起这类故障的主要原因是交换机宕机、网卡松动等导致的网络通信中断;系统升级、停机维护等一般运维活动引起的服务关闭;内存损坏、CPU过热等硬件原因导致的服务器宕机;这类故障的主要特点是需要人工干预(更换硬件、重启机器等)才能恢复正常。通常持续时间需要几十分钟甚至几小时。故障时间可分为两个阶段:临时故障期间,临时故障恢复期间。
× 永久故障:引起这类故障的主要原因只有一个:硬盘损坏,数据丢失。虽然损坏硬盘和损坏内存一样,可以通过更换硬盘来重新启动机器,但是丢失的数据却永远找不回来了,因此其处理策略也和前面两种故障完全不同,恢复系统到正常状态也需要更长的时间。故障时间可分为两个阶段:永久故障期间和永久故障恢复期间。
1.对现有网站业务造成冲击
2.高并发下的应用,数据库负载
3.突然增加的网络及服务器带宽
4.直接下单
1.秒杀系统独立部署
2.秒杀商品页面静态化
3.租借秒杀活动网络带宽
4.动态生成随机下单页面URL
故障现象:某应用服务器不定时地因为响应超时而报警,但是很快又超时解除,恢复正常,如此反复,让运维人员非常苦恼。
原因分析:程序中某个单例对象(singleton object)中多处使用了synchronized(this),由于this对象只有一个,所有的并发请求都要排队获得这唯一的一把锁。一般情况下,都是一些简单操作,获得锁,迅速完成操作,释放锁,不会引起线程排队。但是某个需要远程调用的操作也被加了synchronized(this),这个操作只是偶尔会被执行,但是每次执行都需要较长的时间才能完成,这段时间锁被占用,所有的用户线程都要等待,响应超时,这个操作执行完后释放锁,其他线程迅速执行,超时解除。
经验教训:
× 使用锁操作要谨慎。