温斯顿吴的个人博客 woojean.com

《大型网站技术架构》读书笔记

2017-04-05

网站架构其实并不难,真正能解决问题的技术一定是简单的。

1 大型网站架构演化

大型互联网应用系统有以下特点:

  1. 高并发,大流量:需要面对高并发用户,大流量访问。
  2. 高可用:系统7×24小时不间断服务。
  3. 海量数据。
  4. 用户分布广泛,网络情况复杂。
  5. 安全环境恶劣。
  6. 需求快速变更,发布频繁。
  7. 渐进式发展。好的互联网产品都是慢慢运营出来的,不是一开始就开发好的,这也正好与网站架构的发展演化过程对应。

大型网站架构演化发展历程:

  1. 初始阶段的网站架构:应用程序、数据库、文件等所有的资源都在一台服务器上。
  2. 应用服务和数据服务分离:使用三台服务器:应用服务器、文件服务器和数据库服务器。这三台服务器对硬件资源的要求各不相同。
  3. 使用缓存改善网站性能:缓存在应用服务器上的本地缓存或缓存在专门的分布式缓存服务器上的远程缓存。
  4. 使用应用服务器集群改善网站的并发处理能力:对网站架构而言,只要能通过增加一台服务器的方式改善负载压力,就可以以同样的方式持续增加服务器不断改善系统性能,从而实现系统的可伸缩性。
  5. 数据库读写分离;
  6. 使用反向代理和CDN加速网站响应:基本原理都是缓存,区别在于CDN部署在网络提供商的机房,使用户在请求网站服务时,可以从距离自己最近的网络提供商机房获取数据;而反向代理则部署在网站的中心机房,当用户请求到达中心机房后,首先访问的服务器是反向代理服务器,如果反向代理服务器中缓存着用户请求的资源,就将其直接返回给用户。
  7. 使用分布式文件系统和分布式数据库系统:分布式数据库是网站数据库拆分的最后手段,只有在单表数据规模非常庞大的时候才使用。不到不得已时,网站更常用的数据库拆分手段是业务分库。
  8. 使用NoSQL和搜索引擎;(主要用于优化数据搜索)
  9. 业务拆分:根据产品线划分,将一个网站拆分成许多不同的应用,每个应用独立部署维护。
  10. 分布式服务:将共用的业务提取出来(比如用户模块),独立部署。由这些可复用的业务去连接数据库,提供共用业务服务,而应用系统只需要通过分布式服务调用共用业务服务完成具体业务操作。

在网站还很小的时候就去追求网站的架构是舍本逐末,得不偿失的。小型网站最需要做的就是为用户提供好的服务来创造价值,得到用户的认可,活下去,野蛮生长。

大型网站架构技术的核心价值不是从无到有搭建一个大型网站,而是能够伴随小型网站业务的逐步发展,慢慢地演化成一个大型网站。驱动大型网站技术发展的主要力量是网站的业务发展。

网站架构设计误区:

  1. 一味追随大公司的解决方案;
  2. 为了技术而技术;
  3. 企图用技术解决所有问题;技术是用来解决业务问题的,而业务的问题,也可以通过业务的手段去解决。

2 大型网站架构模式

  1. 分层:将系统在横向维度上切分成几个部分(为应用层、服务层、数据层),每个部分负责一部分相对比较单一的职责,然后通过上层对下层的依赖和调用组成一个完整的系统。 在开发过程中,严格遵循分层架构的约束,禁止跨层次的调用及逆向调用。
  2. 分割:分割就是在纵向方面对软件进行切分。将不同的功能和服务分割开来,包装成高内聚低耦合的模块单元,一方面有助于软件的开发和维护;另一方面,便于不同模块的分布式部署,提高网站的并发处理能力和功能扩展能力。
  3. 分布式:分层和分割的一个主要目的是为了切分后的模块便于分布式部署,即将不同模块部署在不同的服务器上,通过远程调用协同工作。常用的分布式方案有以下几种:
    • (1)分布式应用和服务;
    • (2)分布式静态资源;
    • (3)分布式数据和存储;
    • (4)分布式计算;
  4. 集群:对于用户访问集中的模块(比如网站的首页),还需要将独立部署的服务器集群化,即多台服务器部署相同应用构成一个集群,通过负载均衡设备共同对外提供服务。可以提供更好的并发特性,扩展性和可用性。
  5. 缓存:大型网站架构设计在很多方面都使用了缓存设计:
    • (1)CDN;
    • (2)反向代理;
    • (3)本地缓存;
    • (4)分布式缓存;
  6. 异步:业务之间的消息传递不是同步调用,而是将一个业务操作分成多个阶段,每个阶段之间通过共享数据的方式异步执行进行协作。
  7. 冗余:需要一定程度的服务器冗余运行,数据冗余备份,这样当某台服务器宕机时,可以将其上的服务和数据访问转移到其他机器上,从而提高可用性。
  8. 自动化:目前大型网站的自动化架构设计主要集中在运维发布和监控方面。网站需要对线上生产环境进行自动化监控,对服务器进行心跳检测,并监控其各项性能指标和应用程序的关键数据指标。
  9. 安全;

架构模式在新浪微博的应用,略。

3 大型网站核心架构要素

  1. 性能:从用户浏览器到数据库,影响用户请求的所有环节都可以进行性能优化。
  2. 可用性:主要手段是冗余。
  3. 伸缩性:伸缩性是指通过不断向集群中加入服务器的手段来缓解不断上升的用户并发访问压力和不断增长的数据存储需求。
  4. 扩展性:,网站的扩展性架构直接关注网站的功能需求。网站快速发展,功能不断扩展,如何设计网站的架构使其能够快速响应需求变化,是网站可扩展架构主要的目的。
  5. 安全性;

4 瞬时响应:网站的高性能架构

性能测试指标:

  1. 响应时间;
  2. 并发数;
  3. 吞吐量;在系统并发数由小逐渐增大的过程中,系统吞吐量先是逐渐增加,达到一个极限后,随着并发数的增加反而下降,达到系统崩溃点后,系统资源耗尽,吞吐量为零。
  4. 性能计数器:描述服务器或操作系统性能的一些数据指标。包括Sys-tem Load、对象与线程数、内存使用、CPU使用、磁盘与网络I/O等指标。

性能测试方法:

  1. 性能测试:对系统不断施加压力,验证系统在资源可接受范围内,是否能达到性能预期。
  2. 负载测试:对系统不断地增加并发请求以增加系统压力,直到系统的某项或多项性能指标达到安全临界值(而非上限值);
  3. 压力测试:超过安全负载的情况下,对系统继续施加压力,直到系统崩溃或不能再处理任何请求,以此获得系统最大压力承受能力。
  4. 稳定性测试:被测试系统在特定硬件、软件、网络环境条件下,给系统加载一定业务压力,使系统运行一段较长时间,以此检测系统是否稳定。

Web前端性能优化:

  1. 浏览器访问优化:合并文件减少请求、使用浏览器缓存、启用压缩等等。
  2. CDN(Content Distribute Network,内容分发网络)加速的本质仍然是一个缓存,而且将数据缓存在离用户最近的地方,使用户以最快速度获取数据,即所谓网络访问第一跳。
  3. 反向代理,略。

应用服务器性能优化:

  1. 分布式缓存;
  2. 异步操作;消息队列具有很好的削峰作用——即通过异步处理,将短时间高并发产生的事务消息存储在消息队列中,从而削平高峰期的并发事务。
  3. 使用集群;
  4. 代码优化;

存储性能优化:

  1. 固态硬盘;
  2. B+树vs.LSM树;在LSM树上进行一次数据更新不需要磁盘访问,在内存即可完成,速度远快于B+树。当数据访问以写操作为主,而读操作则集中在最近写入的数据上时,使用LSM树可以极大程度地减少磁盘的访问次数,加快访问速度。
  3. RAID vs. HDFS;

5 万无一失:网站的高可用架构

网站可用性度量:业界通常用多少个9来衡量网站的可用性,如QQ的可用性是4个9,即QQ服务99.99%可用,这意味着QQ服务要保证其在所有运行时间中,只有0.01%的时间不可用,也就是一年中大约最多53分钟不可用。

高可用的网站架构:主要手段是数据和服务的冗余备份及失效转移。

高可用的应用:通过负载均衡进行无状态服务的失效转移; 集群环境下,Session管理主要有以下几种手段:

  1. Session复制:应用服务器开启Web容器的Session复制功能,在集群中的几台服务器之间同步Session对象,使得每台服务器上都保存所有用户的Session信息;(只能使用在集群规模比较小的情况下)
  2. Session绑定:负载均衡服务器总是将来源于同一IP的请求分发到同一台服务器上(也可以根据Cookie信息将同一个用户的请求总是分发到同一台服务器上),这种方法又被称作会话黏滞。该方案显然不符合系统高可用的需求。
  3. 利用Cookie记录Session;
  4. Session服务器;

高可用的服务:

  1. 分级管理:运维上将服务器进行分级管理,核心应用和服务优先使用更好的硬件,在运维响应速度上也格外迅速。
  2. 超时设置:在应用程序中设置服务调用的超时时间,一旦超时,通信框架就抛出异常,应用程序根据服务调度策略,可选择继续重试或将请求转移到提供相同服务的其他服务器上。
  3. 异步调用;
  4. 服务降级:在网站访问高峰期,服务可能因为大量的并发调用而性能下降,严重时可能会导致服务宕机。为了保证核心应用和功能的正常运行,需要对服务进行降级。降级有两种手段:拒绝服务及关闭服务。
  5. 幂等性设计:服务重复调用是无法避免的,应用层也不需要关心服务是否真的失败,只要没有收到调用成功的响应,就可以认为调用失败,并重试服务调用。因此必须在服务层保证服务重复调用和调用一次产生的结果相同,即服务具有幂等性。

高可用的数据:主要手段是数据备份和失效转移机制。 为了保证数据的高可用,网站通常会牺牲另一个也很重要的指标:数据一致性。 CAP原理:一个提供数据服务的存储系统无法同时满足数据一致性(Consistency)、数据可用性(Availibility)、分区耐受性(Patition Tolerance,系统具有跨网络分区的伸缩性)这三个条件。 失效转移操作由三部分组成:失效确认、访问转移、数据恢复。

高可用网站的软件质量保证:

  1. 网站发布:发布过程中,每次关闭的服务器都是集群中的一小部分,并在发布完成后立即可以访问,因此整个发布过程不影响用户使用。
  2. 自动化测试:Selenium;
  3. 预发布验证;
  4. 代码控制:网站代码控制的核心问题是如何进行代码管理,既能保证代码发布版本的稳定正确,同时又能保证不同团队的开发互不影响。
  5. 自动化发布:
  6. 灰度发布:将集群服务器分成若干部分,每天只发布一部分服务器,观察运行稳定没有故障,第二天继续发布一部分服务器,持续几天才把整个集群全部发布完毕,期间如果发现问题,只需要回滚已发布的一部分服务器即可。

网站运行监控:不允许没有监控的系统上线。 监控数据采集:

  1. 用户行为日志收集:用户操作系统与浏览器版本信息,IP地址、页面访问路径、页面停留时间等;(Web服务器日志、页面嵌入JavaScript脚本)
  2. 服务器性能监控:如系统Load、内存占用、磁盘IO、网络IO等;
  3. 运行数据报告:比如缓冲命中率、平均响应延迟时间、每分钟发送邮件数目、待处理的任务总数等。

监控管理:系统报警、失效转移、自动优雅降级; 淘宝每年一次的“双十一”促销活动主动关闭“评价”、“确认收货”等非核心功能,以保证交易功能的正常进行,就可以看作是一种优雅降级。

6 永无止境:网站的伸缩性架构

所谓网站的伸缩性是指不需要改变网站的软硬件设计,仅仅通过改变部署的服务器数量就可以扩大或者缩小网站的服务处理能力。

不同功能进行物理分离实现伸缩:每次分离都会有更多的服务器加入网站,使用新增的服务器处理某种特定服务。

单一功能通过集群规模实现伸缩:

应用服务器集群的伸缩性设计:应用服务器应该设计成无状态的。

实现负载均衡的基础技术不外以下几种:

  1. HTTP重定向负载均衡:HTTP重定向服务器,根据用户的HTTP请求计算一台真实的Web服务器地址,并将该Web服务器地址写入HTTP重定向响应中(响应状态码302)返回给用户浏览器。
  2. DNS域名解析负载均衡:在DNS服务器中配置多个A记录。
  3. 反向代理负载均衡:需要配置双网卡和内部外部两套IP地址。由于反向代理服务器转发请求在HTTP协议层面,因此也叫应用层负载均衡。
  4. IP负载均衡:在网络层通过修改请求目标地址进行负载均衡。
  5. 数据链路层负载均衡:在通信协议的数据链路层修改mac地址进行负载均衡。(又称作三角传输模式)。通过配置真实物理服务器集群所有机器虚拟IP和负载均衡服务器IP地址一致,从而达到不修改数据包的源地址和目的地址就可以进行数据分发的目的,由于实际处理请求的真实物理服务器IP和数据请求目的IP一致,不需要通过负载均衡服务器进行地址转换,可将响应数据包直接返回给用户浏览器,避免负载均衡服务器网卡带宽成为瓶颈。这种负载均衡方式又称作直接路由方式(DR)。

负载均衡算法:

  1. 轮询(Round Robin,RR);
  2. 加权轮询(Weighted Round Robin,WRR);
  3. 随机(Random);
  4. 最少连接(Least Connections);
  5. 源地址散列(Source Hashing);

分布式缓存集群的伸缩性设计:和所有服务器都部署相同应用的应用服务器集群不同,分布式缓存服务器集群中不同服务器中缓存的数据各不相同,缓存访问请求不可以在缓存服务器集群中的任意一台处理,必须先找到缓存有需要数据的服务器,然后才能访问。 必须让新上线的缓存服务器对整个分布式缓存集群影响最小,也就是说新加入缓存服务器后应使整个缓存服务器集群中已经缓存的数据尽可能还被访问到,这是分布式缓存集群伸缩性设计的最主要目标。(路由算法至关重要)

分布式缓存的一致性Hash算法:一致性Hash算法通过一个叫作一致性Hash环的数据结构实现KEY到缓存服务器的Hash映射。具体算法过程为:先构造一个长度为0~2的整数环(这个环被称作一致性Hash环),根据节点名称的Hash值(其分布范围同样为0~232)将缓存服务器节点放置在这个Hash环上。然后根据需要缓存的数据的KEY值计算得到其Hash值(其分布范围也同样为0~232),然后在Hash环上顺时针查找距离这个KEY的Hash值最近的缓存服务器节点,完成KEY到服务器的Hash映射查找。当缓存服务器集群需要扩容的时候,只需要将新加入的节点名称(NODE3)的Hash值放入一致性Hash环中,由于KEY是顺时针查找距离其最近的节点,因此新加入的节点只影响整个环中的一小段。100台服务器扩容增加1台服务器,继续命中的概率是99%。虽然仍有小部分数据缓存在服务器中不能被读到,但是这个比例足够小,通过访问数据库获取也不会对数据库造成致命的负载压力。 具体应用中,这个长度为2的一致性Hash环通常使用二叉查找树实现,Hash查找过程实际上是在二叉查找树中查找不小于查找数的最小数值。当然这个二叉树的最右边叶子节点和最左边的叶子节点相连接,构成环。 详略。

数据存储服务器集群的伸缩性设计:而数据存储服务器必须保证数据的可靠存储,任何情况下都必须保证数据的可用性和正确性。因此缓存服务器集群的伸缩性架构方案不能直接适用于数据库等存储服务器。

  1. 关系数据库集群的伸缩性设计:数据写操作都在主服务器上,由主服务器将数据同步到集群中其他从服务器,数据读操作及数据分析等离线操作在从服务器上进行。
  2. NoSQL数据库的伸缩性设计:。一般而言,NoSQL数据库产品都放弃了关系数据库的两大重要基础:以关系代数为基础的结构化查询语言(SQL)和事务一致性保证(ACID)。而强化其他一些大型网站更关注的特性:高可用性和可伸缩性。 详略。

7 随需应变:网站的可扩展架构

,软件架构师最大的价值不在于掌握多少先进的技术,而在于具有将一个大系统切分成N个低耦合的子模块的能力,这些子模块包含横向的业务模块,也包含纵向的基础技术模块。这种能力一部分源自专业的技术和经验,还有一部分源自架构师对业务场景的理解、对人性的把握、甚至对世界的认知。

利用分布式消息队列降低系统耦合性: 通过在低耦合的模块之间传输事件消息,以保持模块的松散耦合,并借助事件消息的通信完成模块间合作。最常用的是分布式消息队列。

利用分布式服务打造可复用的业务平台: 如果说分布式消息队列通过消息对象分解系统耦合性,不同子系统处理同一个消息;那么分布式服务则通过接口分解系统耦合性,不同子系统通过相同的接口描述进行服务调用。

Web Service与企业级分布式服务:略。

大型网站分布式服务的需求与特点:

  1. 负载均衡;
  2. 失效转移;
  3. 高效的远程通信;
  4. 整合异构系统;
  5. 对应用最少侵入;
  6. 版本管理;
  7. 实时监控;

分布式服务框架设计,Thrift,Dubbo,略。

可扩展的数据结构:NoSQL;

利用开放平台建设网站生态圈:略。

8 固若金汤:网站的安全架构

  1. XSS攻击:即跨站点脚本攻击(Cross Site Script),指黑客通过篡改网页,注入恶意HTML脚本,在用户浏览网页时,控制用户浏览器进行恶意操作的一种攻击方式。(反射型、持久型,详略)
  2. 注入攻击:主要有两种形式,SQL注入攻击和OS注入攻击。
  3. CSRF攻击:CSRF(Cross Site Request Forgery,跨站点请求伪造),攻击者通过跨站请求,以合法用户的身份进行非法操作。其核心是利用了浏览器Cookie或服务器Session策略,盗取用户身份。 其他攻击和漏洞:错误回显、HTML注释、文件上传、路径遍历;

Web应用防火墙:ModSecurity;

网站安全漏洞扫描:网站安全漏洞扫描工具是根据内置规则,构造具有攻击性的URL请求,模拟黑客攻击行为,用以发现网站安全漏洞的工具。

信息加密技术:

  1. 单向散列加密:通过对不同输入长度的信息进行散列计算,得到固定长度的输出,这个散列计算过程是单向的;
  2. 对称加密:加密和解密使用的密钥是同一个密钥(或者可以互相推算);
  3. 非对称加密:加密和解密使用的密钥不是同一密钥,其中一个对外界公开,被称作公钥,另一个只有所有者知道,被称作私钥。用公钥加密的信息必须用私钥才能解开,反之,用私钥加密的信息只有用公钥才能解开。

密钥安全管理:

  1. 把密钥和算法放在一个独立的服务器上,甚至做成一个专用的硬件设施,对外提供加密和解密服务,应用系统通过调用这个服务,实现数据的加解密。
  2. 将加解密算法放在应用系统中,密钥则放在独立服务器中,为了提高密钥的安全性,实际存储时,密钥被切分成数片,加密后分别保存在不同存储介质中,兼顾密钥安全性的同时又改善了性能。

信息过滤与反垃圾:

  1. 文本匹配:主要解决敏感词过滤的问题。如果敏感词比较少,用户提交信息文本长度也较短,可直接使用正则表达式匹配。当敏感词很多,用户发布的信息也很长,网站并发量较高时基本上都是Trie树的变种算法。
  2. 分类算法:样本统计,贝叶斯分类算法,略;
  3. 黑名单:hash、布隆过滤器;

电子商务风险控制:略。

9 淘宝网的架构演化案例分析

没有飞速发展的淘宝业务,就不会有今天让技术界艳羡的淘宝技术,可以说,是业务驱动着技术不得不往前走。 2003年,在马云家里,用一个买来的C2C交易软件(PHP)稍作修改就成了最初的淘宝网。。 2004年,PHP换成了Java;

PHP易开发、难维护。 详略。

10 维基百科的高性能架构设计分析

略。

11 海量分布式存储系统Doris的高可用架构设计分析

略。

12 网购秒杀系统架构设计案例分析

略。

13 大型网站典型故障案例分析

  1. 写日志也会引发故障 现象:某应用服务器集群发布后不久就出现多台服务器相继报警,硬盘可用空间低于警戒值,并且很快有服务器宕机。登录到线上服务器,发现log文件夹里的文件迅速增加,不断消耗磁盘空间。 原因:开发人员将log输出的level全局配置为Debug。

  2. 高并发访问数据库引发的故障 现象:数据库Load居高不下,远超过正常水平,持续报警。 原因:发现报警是因为某条SQL引起的,这条SQL是一条简单的有索引的数据查询,不应该引发报警。继续检查,发现这条SQL执行频率非常高,远远超过正常水平。追查这条SQL,发现被网站首页应用调用,首页是被访问最频繁的网页,这条SQL被首页调用,也就被频繁执行了。

  3. 高并发情况下锁引发的故障 现象:某应用服务器不定时地因为响应超时而报警,但是很快又超时解除,恢复正常,如此反复,让运维人员非常苦恼。 原因:程序中某个单例对象(singleton object)中多处使用了synchronized(this),由于this对象只有一个,所有的并发请求都要排队获得这唯一的一把锁。一般情况下,都是一些简单操作,获得锁,迅速完成操作,释放锁,不会引起线程排队。但是某个需要远程调用的操作也被加了synchronized(this),这个操作只是偶尔会被执行,但是每次执行都需要较长的时间才能完成,这段时间锁被占用,所有的用户线程都要等待,响应超时,这个操作执行完后释放锁,其他线程迅速执行,超时解除。

  4. 缓存引发的故障 现象:没有新应用发布,但是数据库服务器突然Load飙升,并很快失去响应。DBA将数据库访问切换到备机,Load也很快飙升,并失去响应。最终引发网站全部瘫痪。 原因:一个缺乏经验的工程师关闭了缓存服务器集群中全部的十几台Memcached服务器,导致了网站全部瘫痪的重大事故。

  5. 应用启动不同步引发的故障 现象:某应用发布后,服务器立即崩溃。 原因:应用程序Web环境使用Apache.JBoss的模式,用户请求通过Apache转发JBoss。在发布时,Apache和JBoss同时启动,由于JBoss启动时需要加载很多应用并初始化,花费时间较长,结果JBoss还没有完全启动,Apache就已经启动完毕开始接收用户请求,大量请求阻塞在JBoss进程中,最终导致JBoss崩溃。除了这种Apache和JBoss启动不同步的情况,网站还有很多类似的场景,都需要后台服务准备好,前台应用才能启动,否则就会导致故障。这种情况被内部人戏称作“姑娘们还没穿好衣服,老鸨就开门迎客了”。

  6. 大文件读写独占磁盘引发的故障 现象:某应用主要功能是管理用户图片,接到部分用户投诉,表示上传图片非常慢,原来只需要一两秒,现在需要几十秒,有时等半天结果浏览器显示服务器超时。 原因:图片需要使用存储,最有可能出错的地方是存储服务器。检查存储服务器,发现大部分文件只有几百KB,而有几个文件非常大,有数百兆,读写这些大文件一次需要几十秒,这段时间,磁盘基本被这个文件操作独占,导致其他用户的文件操作缓慢。

  7. 滥用生产环境引发的故障 现象:监控发现某个时段内,某些应用突然变慢,内部网络访问延迟非常厉害。 原因:原来有工程师在线上生产环境进行性能压力测试,占用了大部分交换机带宽。

  8. 不规范的流程引发的故障 现象:某应用发布后,数据库Load迅速飙升,超过报警值,回滚发布后报警消除。 原因:发现该应用发布后出现大量数据库读操作,而这些数据本来应该从分布式缓存读取。检查缓存,发现数据已经被缓存了。检查代码,发现访问缓存的那行代码被注释掉了。原来工程师在开发的时候,为了测试方便,特意注释掉读取缓存的代码,结果开发完成后忘记把注释去掉,直接提交到代码库被发布到线上环境。

  9. 不好的编程习惯引发的故障 现象:某应用更新某功能后,有少量用户投诉无法正常访问该功能,一点击就显示出错信息。 原因:分析这些用户,都是第一次使用该功能,检查代码,发现程序根据历史使用记录构造一个对象,如果该对象为null,就会导致NullPointException。

14 架构师领导艺术

以人为本。 略。

15 网站架构师职场攻略

略。

16 漫话网站架构师

略。

附录

略。


文章目录