第四章 瞬时响应:网站的高性能架构
4.1 网站性能测试
性能测试是性能优化的前提和基础,也是性能优化结果的检查和度量标准。
性能测试的指标有:响应时间、并发数、吞吐量、性能计数器。
网站性能优化的目的,除了改善用户体验的响应时间,还要尽量提升系统吞吐量,最大限度利用服务器资源。
4.2 Web 前端性能优化
主要手段有优化浏览器访问、使用反向代理、CDN加速等。
4.2.1 浏览器访问优化
- 减少http请求:合并、压缩CSS、JS,合并图片,使用Ajax局部刷新页面。
- 使用浏览器缓存: Expires:告诉缓存器:相关副本在多长时间内是新鲜的。过了这个时间,缓存器就会向源服务器发送请求,检查文档是否被修改。 Cache-Control:
- > * max-age=[秒] — 执行缓存被认为是最新的最长时间。这个参数是基于请求时间的相对时间间隔,而不是绝对过期时间,[秒]是一个数字,单位是秒:从请求时间 开始到过期时间之间的秒数。
- > * s-maxage=[秒] — 类似于max-age属性,除了他应用于共享(如:代理服务器)缓存
- > * public — 标记认证内容也可以被缓存,一般来说: 经过HTTP认证才能访问的内容,输出是自动不可以缓存的;
- > * no-cache — 强制每次请求直接发送给源服务器,而不经过本地缓存版本的校验。这对于需要确认认证应用很有用(可以和public结合使用),或者严格要求使用最新数据 的应用(不惜牺牲使用缓存的所有好处);
- > * no-store — 强制缓存在任何情况下都不要保留任何副本
- > * must-revalidate — 告诉缓存必须遵循所有你给予副本的新鲜度的,HTTP允许缓存在某些特定情况下返回过期数据,指定了这个属性,你高速缓存,你希望严格的遵循你的规则。
- > * proxy-revalidate — 和 must-revalidate类似,除了他只对缓存代理服务器起作用。 Last-Modified/If-Modified-Since:第一次请求资源时,服务器在响应头里设置 Last-Modified 为资源的最后修改时间,浏览器第二次请求资源时,在请求头里带上上次响应的 Last-Modified 值,服务器检测到资源自此值后没有修改,则仅返回 304 响应头。 ETag/If-None-Match:服务器发送你所请求的数据的同时,发送数据的某种 hash (在 ETag 头信息中给出)。hash 的确定完全取决于服务器。当第二次请求相同的数据时,你需要在 If-None-Match 头信息中包含 ETag hash,如果数据没有改变,服务器将仅返回 304 状态代码。
- 服务端启用GZip压缩
- CSS 放在页面最上面,JS放在页面最下面:浏览器在下载完全部CSS之后才开始对整个页面进行渲染;在加载JS后立即执行,可能会阻塞页面,造成页面显示缓慢。
- 减少Cookie传输:Cookie包含在每次请求和响应中,太大的Cookie会影响数据传输;对于静态资源,发送Cookie没有意义,可以对静态资源使用独立域名。
- 对不同的静态资源使用独立域名:浏览器对同一个域同时访问的连接数是有限制的,增加不同的域可以加快资源加载。
4.3 应用服务器性能优化
主要手段有缓存、集群、异步等。
网站性能优化第一定律:优先考虑使用缓存优化性能。
缓存主要用来存放那些读写比很高、很少变化的数据。
任何可以晚点做的事情都应该晚点再做。
代码优化:
- 多线程:启动线程数=[任务执行时间/(任务执行时间-IO等待时间)]*CPU内核数。解决线程安全的主要手段:将对象设计为无状态对象、使用局部变量、并发访问资源时使用锁。
- 资源复用
- 恰当的数据结构
- 关注垃圾回收:
4.5 小结
网站性能优化的主要工作是改善高并发下情况下的网站响应速度。
网站性能对最终用户而言是一种主观感受,性能优化的最终目的就是改善用户的体验,使他们感觉网站很快。离开这个目的,追求技术上的所谓高性能,是舍本逐末,没有多大意义。而用户体验的快或慢,可以通过技术手段改善,也可以通过优化交互体验改善。
第五章 万无一失:网站的高可用架构
5.2 高可用的网站架构
完整的高可用架构设计的主要目的是保证服务器硬件故障时服务依然可用、数据依然保存并能够被访问。
实现上述高可用架构的主要手段是数据和服务的冗余备份以及失效转移。
位于应用层和服务层的服务器为了应对高并发的访问请求,会通过负载均衡设备将一组服务器组成一个集群共同对外提供服务。
位于数据层的服务器需要在数据写入时进行数据同步复制,将数据写入多台服务器上,实现数据冗余备份。
5.3 高可用的应用
通过负载均衡进行无状态服务的失效转移。
Session 管理
- Session 复制:简单,占用服务器内存、带宽资源。
- Session 绑定:将同一IP或Cookie信息转发到特定的服务器,不满足高可用。
- 利用Cookie 记录Session:简单可靠性高,支持应用服务器线性伸缩;受cookie大小限制,每次请求要传输cookie,影响性能,如果用户关闭cookie,访问会不正常。
- Session 服务器:这种解决方案将应用服务器的状态分离,分为无状态的应用服务器和有状态的 session 服务器;应用服务器每次读写 sission,都访问 session 服务器。
5.4 高可用的服务
也是通过负载均衡和失效转移机制失效。
- 分级管理:对服务进行分级管理,确保优先级高的服务;在部署上进行隔离,避免故障的连锁反应。
- 超时设置:可避免请求长时间不能得到响应。
- 异步调用:应用对服务的调用通过消息队列等异步方式完成,避免一个服务失败导致整个应用请求失败的情况。
- 服务降级:有两种手段:拒绝服务和关闭关闭服务。 拒绝服务:拒绝低优先级应用的调用,减少服务调用的并发数,确保核心应用正常使用;或者随机拒绝部分请求调用,节约资源,让一部分请求成功,避免要死大家一起死的惨剧。 关闭服务:关闭部分不重要的服务,或者服务内部关闭部分不重要的功能,以节约系统开销,为重要的服务和功能让出资源。
- 幂等性设计:服务层保证重复调用和调用一次产生的结果相同,即服务具有幂等性。服务重复调用是无法避免的。
5.5 高可用的数据
保证数据高可用的手段主要是数据备份和失效转移机制。
CAP 原理
CAP 原理认为一个提供数据服务的存储系统无法同时满足数据一致性(Consistency)、数据可用性(Availability)、分区耐受性(Partition Tolerence,系统具有跨网络分区的伸缩性)。
在大型网站中,通常会选择强化分布式系统的可用性(A)和伸缩性(P),在某种程度上放弃一致性(C)。
数据一致性又分为:
- 数据强一致性:各个副本的数据在物理存储中总是一致的。
- 数据用户一致性:各个副本的数据可能是不一致的,终端用户访问时,通过纠错和校验机制,可以确定一个一致的且正确的数据返回给用户。
- 数据最终一致:物理存储的数据可能是不一致的,终端用户访问到的结果可能也是不一致的,但系统经过一段时间的自我修复和修正,数据最终会达到一致。
数据备份
数据备份分为冷备份和热备份,热备份又分为异步热备份和同步热备份。
在异步写入方式下,存储服务器分为主存储服务器(Master)和从存储服务器(Slave),应用程序通常只连接 Master,数据写入时,由 Master 的写代理操作模块将数据写入本机存储系统后立即返回写操作成功响应,然后通过异步线程将写操作数据同步到 Slave。
同步方式是指多份数据副本的写入操作同步完成,即应用程序收到数据服务系统的写成功响应时,多份数据的都已经写操作成功。
失效转移
失效转移操作由三个部分组成:失效确认、访问转移、数据恢复。
失效确认主要通过心跳检测和应用程序访问失败报告。
5.6 高可用网站的软件质量保证
- 网站发布
- 自动化测试
- 预发布验证
- 代码控制
- 自动化发布
- 灰度发布
5.7 网站运行监控
不允许没有监控的系统上线。
监控数据采集
用户行为日志:
服务器性能监控。
运行数据报告。
监控管理
系统报警、失效转移、自动优雅降级。
第六章 永无止境:网站的伸缩性架构
6.1 网站架构的伸缩性设计
网站的伸缩性架构可分成两类:一类是根据功能进行物理分离实现伸缩,一类是单一功能通过集群实现伸缩。
当一头牛拉不动车的时候,不要去找一头更强壮的牛,而是用两头牛去拉车。
负载均衡的基础技术
- HTTP 重定向负载均衡:采用 HTTP 重定向服务器,根据用户 HTTP 请求计算一台真实的 web 服务器地址,将该服务器地址写入 HTTP 重定向响应中返回给用户浏览器。需要两次访问才能完成一次请求,重定向服务器自身的处理能力有可能称为瓶颈。
- DNS 域名解析负载均衡:在DNS 服务器中配置多个 A 记录,每次域名解析请求都会根据负载均衡算法计算一个不同的 IP 地址返回,这样 A 记录中配置的多个服务器就构成一个集群,并可以实现负载均衡。DNS 的解析有延迟。
- 反向代理负载均衡:反向代理服务器需要配置双网卡和内部外部两套 IP 地址,工作在 HTTP 协议层,也叫应用层负载均衡。
- IP 层负载均衡:在网络层通过修改请求目标的地址进行负责均衡。
- 数据链路层负载均衡:在数据链路层修改 mac 地址进行负载均衡。在分发过程中不修改 IP 地址,只修改目的 mac 地址,通过配置真实物理服务器集群所有机器虚拟 IP 和负载均衡服务器 IP 地址一致,从而达到不修改数据包的源地址和目的地址就可以进行数据分发的目的。也称作直接路由(DR)。
负载均衡算法
- 轮询(Round Robin,RR):所有请求被依次分发到每台应用服务器上。
- 加权轮询(Weighted Round Robin,WRR):在轮询的基础上,按配置的权重将请求分发到每台服务器上。
- 随机(Random):请求被随机分发到各个应用服务器上。
- 最少连接(Least Connection):记录每个应用服务器正在处理的连接数,将新到的请求分发到最少连接的服务器上。
- 源地址算列(Source Hashing):根据请求来源的 IP 地址进行分发请求,同一个 IP 总是分发到同一台服务器上。
第七章 随需应变:网站的可扩展性
- 扩展性(Extensibility):指对现有系统影响最小的情况下,系统功能可持续扩展或提升的能力。表现在基础设施稳定不需要经常变更,应用之间少依赖和耦合,对需求变更可以敏捷响应。
- 伸缩性(Scalability):指系统能够通过增加(减少)自身资源规模的方式增强(减少)自己计算处理事务的能力。这种增减是成比例的,就被称作线性伸缩。
设计网站可扩展架构的核心思想是模块化,并在此基础之上,降低模块间的耦合性,提供模块的复用性。
分层和分割是模块化设计的重要手段,模块之间以消息传递和依赖调用的方式聚合成一个完整的系统。
模块分布式部署以后具体的聚合方式主要有分布式消息队列和分布式服务。
大型网站分布式服务的需求与特点:
- 服务的注册与发现
- 服务调用
- 负载均衡
- 失效转移
- 高效的远程通信
- 整合异构系统
- 对应用最少入侵
- 版本管理
- 实时监控
第八章 固若金汤:网站的安全架构