读书_大型网站技术架构02_李智慧

第四章

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

4.1 网站性能测试

不同视角下的网站性能

1
2
3
1. 用户视角:用户在浏览器上直观感受到的网站相应速度,包括用户计算机和网站服务器通信的速度、网站服务器处理的速度、用户计算机浏览器构造请求解析响应数据的速度。 
2. 开发人员视角:应用程序本身及其相关子系统的性能,包括响应延迟、系统吞吐量、并发处理能力、系统稳定性等技术指标。
3. 运维人员视角:基础设施性能和资源利用率,如网络运营商的带宽、服务器硬件的配置、数据中心网络架构、服务器和网络带宽的资源利用率等。

性能指标:响应时间,并发数,吞吐量
性能测试,细分为:

1
2
3
4
a) 性能测试:以系统设计初期规划的性能指标为预期目标,不断施加压力(增加并发请求),验证系统在资源可接受范围,可否达到预期。
b) 负载测试:不断施加压力(增加并发请求),直到某项或多项性能指标达到安全临界值(比如资源已饱和)。此时继续加压,系统处理能力会下降。
c) 压力测试:超过安全负载情况下,不断施加压力(增加并发请求),直到系统崩溃或无法处理任何请求,依此获得系统最大压力承受能力。
d) 稳定性测试:被测试系统在特定硬件、软件、网络环境下,加载一定业务压力(模拟生产环境不同时间点、不均匀请求,呈波浪特性)运行一段较长时间,以此检测系统是否稳定。

性能测试曲线:横坐标为消耗的系统资源,纵坐标为吞吐量。a~b为网站日常运行区间,c为系统最大负载点,d为系统崩溃点。

访问等待时间

性能测试报告

性能优化策略

  1. 性能分析
    检查请求处理的各个环节的日志,分析哪个环节响应时间不合理、超过预期。
    检查监控数据,分析影响性能的主要因素是内存、磁盘、网络、还是CPU,是代码问题还是架构设计不合理,或者系统资源确实不足。

  2. 性能优化
    Web前端性能优化
    应用服务器性能优化
    存储服务器性能优化

4.2 Web前端性能优化

浏览器访问优化

1
2
3
4
5
1. 减少HTTP请求:合并CSS、合并JavaScript、合并图片。
2. 使用浏览器缓存:CSS、JavaScript、Logo、图标等静态资源文件更新频率较低,通过HTTP头Cache-Control和Expires设置缓存数天,甚至几个月。更新此类文件时,不更新内容,而是修改文件名,生成新文件并更新HTML引用。当有一批此类文件要更新时,不宜一次全部更新,而是逐个更新,并有时间间隔,以免浏览器大量缓存失效,集中更新缓存,服务器负载剧增。
3. 启用压缩:文本文件(如HTML、CSS、JavaScript)GZip压缩率可达80%以上,有效减少通信传输数据量。但服务器、浏览器压力上升,所以要权衡。
4. CSS放在页面最上面,JavaScript放在页面最下面:浏览器下载全部CSS后才渲染页面,而在加载JavaScript后立即执行,可能会阻塞页面,渲染缓慢。
5. 减少Cookie传输:每次请求和响应都会包含Cookie,影响数据传输;静态资源访问(如CSS、JavaScript)发送Cookie无意义。可静态资源使用独立域名,避免请求静态资源时发送Cookie。

CDN加速

反向代理

4.3 应用服务器性能优化

分布式缓存

1
2
3
1. 网站性能优化第一定律:优先考虑使用缓存优化性能。
2. 缓存优点:缓存访问速度快,减少数据访问时间;如果缓存的数据是经过计算得到的,则此类数据无需重复计算可直接使用。
3. 缓存本质:以一对Key、Value形式存储在内存的Hash表,读写时间复杂度O(1)。

注意事项。

1
2
3
4
5
6
a) 频繁修改的数据:如果缓存频繁修改的数据,会造成写入缓存后来不及读取已失效。一般数据读写比应在2:1以上,甚至更高。
b) 没有热点的访问:缓存使用内存,资源宝贵,应遵循二八定律,即缓存20%热点数据。
c) 数据不一致与脏读:一般设置缓存失效时间,失效后从数据库加载,因此要容忍一定时间的数据不一致。也可数据更新时立即更新缓存,但会带来更多系统开销和事务一致性问题。
d) 缓存可用性:为避免缓存雪崩(缓存不可用造成数据库无法承受压力而宕机),可将缓存数据分布到集群多台服务器,宕机时只有部分缓存数据丢失。
e) 缓存预热(warn up):热点数据是通过LRU(最近最久未用算法)淘汰生成的,需较长时间。
f) 缓存穿透:缓存不存在的数据(其值为null),避免不恰当业务或恶意攻击高并发请求某个不存在数据,造成数据库压力而崩溃。

异步操作
使用原则就是,任何可以晚点做的事情都应该晚点再做。

在使用消息队列进行业务异步处理后,需要适当修改业务流程进行配合,如订单提交后,订单数据写入消息队列,不能立即返回用户订单提交成功,需要在消息队列的订单消费者进程真正处理完该订单,甚至商品出库后,再通过电子邮件或 SMS消息通知用户订单成功,以免交易纠纷。

使用集群

代码优化

  1. 多线程
    1
    2
    a) 目的:利用多线程IO阻塞与执行交替进行,最大限度利用CPU资源;多线程最大限度利用多核CPU。
    b) Web容器线程数设置:如果都是CPU计算型任务,则线程数最多不超过CPU内核数(更多线程CPU来不及调度);如果都是等待磁盘IO、网络IO的任务,则多启动线程有助于提高任务并发度,提高吞吐能力。
  2. 资源复用:单例(Singleton)、对象池(Object Pool)。
  3. 数据结构。
  4. 垃圾回收:即优化JVM。

4.4 存储性能优化(不常用,略)

机械硬盘 VS 固态硬盘
B+树 VS LSM树
RAID VS HDFS

4.5 小结

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

5.1 网站可用性的度量与考核

度量

1
2
3
4
1. 业界通常用多少个9来衡量网站可用性。  
2. 网站不可用也称网站故障。
3. 网站不可用时间公式:网站不可用时间(故障时间)= 故障修复时间点-故障发现(报告)时间点
4. 网站年度可用性指标公式:网站年度可用性指标 =(1-网站不可用时间/年度总时间)×100%

考核

5.2 高可用的网站架构

实现高可用架构主要手段:数据和服务的冗余备份及失效转移
应用层高可用:通过负载均衡设备将一组服务器组成一个集群对外处理高并发请求,负载均衡设备通过心跳检测等手段监控到应用服务器不可用时,将其从集群列表剔除,请求分发到集群其他可用服务器上。
服务层高可用:也是通过集群实现高可用。服务层被应用层通过分布式服务调用框架访问,分布式服务调用框架在应用层客户端中实现负载均衡,服务注册中心获取服务层服务器心跳检测,发现不可用服务器,立即通知客户端修改服务层访问列表,剔除不可用服务器(说的就是Dubbo)。
数据层高可用:比较特殊,数据服务器存储了数据。数据写入时同步复制数据到多台服务器上,实现数据冗余备份;数据服务器宕机时,数据访问切换到备份数据服务器上。
网站升级发布可能引起故障。

5.3 高可用的应用

通过负载均衡进行无状态服务失效转移
无状态应用:应用服务器不保存业务的上下文信息,而仅根据每次请求提交的数据处理业务逻辑,多台服务器之间完全对等,请求提交到任意服务器结果一样。是应用层高可用的基础。

应用服务器集群的Session管理
事实上业务总是有状态的(Session),负载均衡集群环境下,负载均衡服务器可能会将请求分发到集群任何依他应用服务器上,所以每次请求获取正确的Session要比单机复杂。几种手段:

1
2
3
4
1. Session复制:集群各台服务器间同步Session对象,每台服务器都保存所有用户的Session信息。服务器内存无法保存大量Session,不适合大型网站。
2. Session绑定:利用负载均衡的源地址Hash算法,负载均衡服务器总是将源于同一IP的请求分发到同一服务器。服务器宕机Session丢失,无法高可用,不适合大型网站。
3. 利用Cookie记录Session:Cookie大小限制;每次请求响应都传输Cookie,影响性能;用户关闭Cookie将不正常。Cookie简单易用,可用性高,支持应用服务器线性伸缩,许多网站或多或少都使用Cookie记录Session。
4. Session服务器:利用分布式缓存、数据库等存取Session,实现应用服务器的状态分离。可用性高、伸缩性好、性能不错,适合大型网站。

5.4 高可用的服务

  1. 分级管理。
    1
    2
    a) 核心应用和服务优先使用更好的硬件和更快的运维响应速度。
    b) 部署隔离,避免故障连锁反应:低优先级服务启动不同线程或部署在不同虚拟机上隔离;高优先级服务部署在不同物理机上;核心服务和数据甚至部署在不同地域的数据中心。
  2. 超时设置:在应用程序设置服务调用超时时间,超时后通信框架抛出异常,避免因服务器宕机、线程死锁导致应用程序对服务端调用失去响应,进而用户请求长时间得不到响应,同时占用应用程序资源。
  3. 异步调用:前面章节已说明,不再赘述。
  4. 服务降级:有两种手段。
    1
    2
    a) 拒绝服务:拒绝低优先级应用的调用,减少并发数,确保核心应用正常调用;随机拒绝部分请求调用,让另一部分请求成功,避免大家一起死的餐具。
    b) 关闭服务:关闭部分不重要服务或服务内部关闭部分不重要功能,节约开销。
  5. 幂等性设计:应用层只要未收到调用成功的响应,都认为调用服务失败,并重试服务调用,因此服务层必须保证服务重复调用和调用一次的结果相同,即服务具有幂等性。

5.5 高可用的数据

CAP原理

  1. 数据高可用含义。
    1
    2
    3
    a) 数据持久性:在各种情况下都不会出现数据丢失问题。
    b) 数据可访问性:多数据副本分别存放在不同存储设备情况下,失效转移能很快完成(终端用户几乎没有感知)。
    c) 数据一致性:多数据副本情况下,各副本之间数据一致。
  2. CAP原理:一个提供数据服务的存储系统无法同时满足数据一致性(Consistency)、数据可用性(Availability)、分区耐受性(Partition Tolerance)这三个条件。
  3. 大型网站实践:通常选择强化分布式存储系统的可用性(A)和伸缩性(P),而在某种程度上放弃一致性(C)。一般数据不一致出现在系统高并发写操作或集群状态不稳定(故障恢复、集群扩容等)时,应用系统要对分布式数据处理系统的数据不一致性有了解并进行某种意义上的补偿和纠错,以保证最终一致性

数据备份

  1. 冷备。
    1
    2
    3
    a) 优点:简单、廉价,成本和技术难度都较低。
    b) 缺点:无法保证数据一致性(备份设备中的数据比系统中的数据陈旧)。
    c) 现状:作为传统的数据保护手段依然在运维中使用。
  2. 热备。
    1
    2
    a) 异步热备:多份数据副本的写入操作异步完成,即应用程序收到数据服务系统的写操作成功响应时,只写成功了一份,存储系统将异步地写其他副本(该过程可能失败)。
    b) 同步热备:多份数据副本的写入操作同步完成,即应用程序收到数据服务系统的写成功响应时,多份数据都已经写操作成功。
  3. 同步热备优化:应用程序客户端并发向多个存储服务器同时写入数据,所有写操作成功响应后,再通知应用程序成功。优点:存储服务器无主从之分,完全对等,便于管理维护;并发写操作意味着多份数据的总写操作延时是响应最慢的那台存储服务响应。
  4. 实际:通常使用读写分离,写操作只访问Master数据库,读操作只访问Slave数据库。

失效转移

  1. 失效确认:有心跳检测和应用程序访问失败报告两种手段。对于后者,控制中心还要再一次发送心跳检测确认,以免错误判断服务器宕机。
  2. 访问转移:将数据读写访问重新路由到其他服务器上。
  3. 数据恢复:数据副本数目已减少,必须将副本数目恢复到系统设定的值,否则再有宕机可能无法访问转移(所有副本服务器宕机)。

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

自动化测试
预发布验证
代码控制
自动化发布
灰度发布

5.7 网站运行监控

监控数据采集

  1. 用户行为日志收集:用户在浏览器上的所有操作及其操作环境,包括操作系统、浏览器版本、IP地址、页面访问路径、网页停留时间等,对统计网站PV/UV、分析用户行为、优化网站设计、个性营销与推荐非常重要。
  2. 服务器性能监控:收集服务器性能指标,如系统Load、内存占用、磁盘IO、网络IO等。

监控管理

  1. 系统预警:超过预设阀值意味着可能出现故障,此时通过邮件、短信等方式报警。
  2. 失效转移:除应用程序访问时失效转移,监控系统在发现故障时主动通知应用失效转移。
  3. 自动降级:关闭次要服务,保证核心服务。

    5.8 小结

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

6.1 网站架构的伸缩性设计

不同功能物理分离实现伸缩:主要是分层、分割后的业务和模块独立部署

1
2
纵向分离,将业务处理上的不同部分分离部署;
横向分离,将不同的业务模块分离部署。

单一功能通过集群实现伸缩:将单一服务集群部署提供服务

6.2 应用服务器集群的伸缩性设计

主要是通过负载均衡实现集群的伸缩。
负载均衡技术:

1
2
3
4
5
http重定向
DNS解析
反向代理
IP负载
数据链路层负载

负载均衡算法:

1
2
3
4
5
1. 轮询(Round Robin,RR):所有请求依次分发到每台服务器,适合所有服务器硬件都相同的场景。
2. 加权轮询(Weight Round Robin,WRR):轮询基础上,按照配置的权重将请求分发到每台服务器,高性能的服务器分配更多请求。
3. 随机(Random):请求随机分发到每台服务器,也可加权随机。
4. 最少连接(Least Connections):记录每台服务器正在处理请求(连接)数,将新请求分发到最少连接服务器,最符合负载均衡定义,也可加权最少连接。
5. 源地址散列(Source Hashing):根据请求来源IP地址的Hash值,得到服务器,同一IP地址请求总在一台服务器上处理。

6.3 分布式缓存集群的伸缩性设计

  1. 分布式缓存集群特点:集群中各服务器数据不同,缓存访问请求不可以在任意一台处理,必须先找到有缓存数据的服务器才能访问。
  2. 分布式缓存集群访问原理:以写缓存Memcached为例,应用程序输入数据<’BEIJING’,DATA>,API将KEY(‘BEIJING’)输入路由算法模块,路由算法根据KEY和集群服务器列表计算得到一台服务器编号NODE1和IP地址、端口;API调用通信模块将数据写入服务器NODE1。
  3. 分布式缓存的一致性Hash算法:可解决伸缩性问题,但算法介绍Memcached且复杂,可能会使用Redis代替,以后再看。

    6.4 数据存储服务器集群的伸缩性设计

关系数据库集群的伸缩性设计

  1. 主从复制:利用关系数据库数据复制功能,进行简单伸缩。
  2. 分库:不同业务数据表部署在不同数据库集群上。制约条件是跨库不能join操作。
  3. 分片:对某些单表数据量大的表(如Facebook用户表、淘宝商品表),将一张表拆分存储在多个数据库。
    1
    2
    3
    a) 比较成熟的支持数据分片的开源分布式关系数据库产品:Amoeba、Cobar。
    b) 分布式关系数据库特点:限制了关系数据库某些功能;海量数据压力不得不利用分布式关系数据库伸缩。
    c) 分布式关系数据库注意:避免事务或利用事务补偿机制代替数据库事务;分解数据访问逻辑避免join操作。

NoSQL数据库集群的伸缩性设计
NoSQL特点:放弃了关系数据库的以关系代数为基础的结构化查询语言(SQL)和事务一致性保证(ACID),而强化大型网站关注的高可用性和可伸缩性。

6.5 小结

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

扩展性与伸缩性

  1. 扩展性(Extensibility):对现有系统影响最小的情况下,系统功能可持续扩展或提升的能力。
  2. 伸缩性(Scalability):系统能够通过增加(减少)自身资源规模的方式增强(减少)自己计算处理事务的能力。

构建可扩展的网站架构

  1. 设计网站可扩展架构的核心思想是模块化,并在此基础上降低模块间的耦合性,提高模块复用性。
  2. 模块化的重要手段:分层和分割,分层、分割为若干个低耦合的独立组件模块(模块可分布式部署,从物理上分离模块间耦合),各模块以消息传递及依赖调用方式聚合成完整系统。

利用分布式消息队列降低系统耦合性

  1. 事件驱动架构(Event Driven Architecture):通过在低耦合的模块之间传输事件消息,以保持模块的松散耦合,并借助事件消息的通信完成模块间合作。典型的EDA架构就是生产者消费者模式。大型网站最常见是分布式消息队列,利用发布/订阅模式工作。
  2. 分布式消息队列。
    1
    2
    3
    4
    a) 原理:前面章节已说明,不再赘述。
    b) 伸缩性:新服务器加入消息队列集群事,修改生产者服务器的消息队列服务器列表即可。
    c) 可用性:为避免消费者进程处理缓慢、消息队列服务器内存不足等问题,如果内存队列已满,消息会被写入磁盘;为避免消息队列服务器宕机,生产者服务器会保存消息直至消息真正被消费者服务器处理后才删除,如果消息队列服务器宕机,生产者服务器会选择分布式消息队列集群中其他服务器发送。
    d) 开源Apache ActiveMQ实现了可用性、伸缩性、数据一致性、性能和可管理性等。

利用分布式服务打造可复用的业务平台

  1. 纵向拆分:将一个大应用拆分为多个小应用,如果新增业务较为独立,那么直接部署为一个独立的Web应用。
  2. 横向拆分:将复用的业务拆分,独立部署为分布式服务,新增业务只需要调用这些分布式服务,无需依赖具体模块代码。

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

1
2
3
4
5
6
7
8
a) 注册与发现;
b) 负载均衡
c) 失效转移;
d) 高效的远程通信:核心服务每天调用次数数以亿计;
e) 整合异构系统:服务可能使用不同语言开发并部署不同平台;
f) 对应用最小侵入;
g) 版本管理:支持服务接口的多版本发布,方便服务调用者使用未升级的旧接口;
h) 实时监控。

开源分布式服务框架:阿里巴巴Dubbo、Facebook Thrift。

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

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×