瞬时响应:网站的高性能架构
网站的性能是客观的指标,可以具体到响应时间、吞吐量等技术指标;也可以是主观感受。
性能测试
不同视角下的网站性能
1. 用户视角的网站性能
网站性能就是用户在浏览器上直观感受到的网站响应速度是快还是慢。
主要优化手段:前端架构优化技术。如:优化HTML、浏览器缓存、使用CDN、反向代理技术、浏览器的并发和异步等等。
2. 开发人员视角的网站性能
开发人员关注的网站性能就是程序本身及其子系统的性能,包括响应延迟、系统吞吐量、并发处理能力、系统稳定性等技术指标。
主要优化手段:缓存加速数据读取,使用集群提高吞吐能力,使用异步消息加快请求响应及实现削峰,使用代码优化手段改善程序性能。
3. 运维人员视角的网站性能
运维人员更关注基础设施性能和资源利用率。如:网络运营商的带宽能力、服务器硬件配置、数据中心网络架构、服务器和网络带宽的资源利用率等。
主要优化手段:建设优化骨干网络、使用性价比定制服务器、利用虚拟化技术优化资源利用等。
性能测试指标
网站性能测试的主要指标有响应时间、并发数、吞吐量、性能计数器等。
响应时间
指应用执行一个操作需要的时间,包括从发出请求开始到收到最后响应数据所需要的时间。响应时间是系统最重要的性能指标,直接反映了系统的“快慢”。
一些性能指标可以参考:Latency Numbers Every Programmer Should Know
并发数
指系统能够同时处理请求的数目,这个数字也反映了系统的负载特性。对于网站而言,并发数即网站并发用户数,指同时提交请求的用户数目。
网站系统用户数 >> 网站在线用户数 >> 网站并发用户数
测试程序通过多线程模式并发用户的办法来测试系统的并发处理能力,为了真实模拟用户行为,测试程序并不是启动多线程然后不停地发送请求,而是在两次请求之间加入一个随机等待时间,这个时间被称为思考时间。
吞吐量
指单位时间内系统处理的请求数量,体现系统的整理处理能力。对于网站来说,可以用“请求数/秒”、“页面数/秒”、“访问人数/天”、“处理的业务数/小时”等来衡量。
- TPS:每秒处理的事务数
- HPS:每秒处理HTTP请求数
- QPS:每秒处理查询数
ps:一个很生动的高速公路上汽车、收费站的例子说明了并发数、吞吐量和响应时间的关系。
性能计数器
它是描述服务器或操作系统性能的一些数据指标。
System Load:即系统负载,指当前正在被CPU执行和等待被CPU执行的进程数目总和,是反映系统忙闲程度的重要指标。
性能测试
性能测试是一个总称,具体可细分为性能测试、负载测试、压力测试、稳定性测试。
性能测试时一个不断对系统增加访问压力,以获得系统性能指标、最大负载能力、最大压力承受能力的过程。增加访问压力指,在系统测试环境中,就是不断增加测试程序的并发请求数。
如上图:横坐标表示消耗的系统资源,纵坐标表示系统处理能力(吞吐量)。
在开始阶段,随着并发请求数目的增加,系统使用较少的资源就达到较好的处理能力(a~b段),这一段是网站的日常运行区间,网站的绝大部分访问负载压力都集中在这一段区间,被称作性能测试,测试目标是评估系统性能是否符合需求及设计目标;
随着压力的持续增加,系统处理能力增加变缓,直到达到一个最大值(c点),这是系统的最大负载点,这一段被称作负载测试*。测试目标是评估当系统因为突发事件超出日常访问压力的情况下,保证系统正常运行情况下能够承受的最大访问负载压力;*
超过这个点后,再增加压力,系统的处理能力反而下降,而资源消耗却更多,直到资源消耗达到极限(d点),这个点可以看作是系统的崩溃点,超过这个点继续加大并发请求数目,系统不能再处理任何请求,这一段被称作压力测试**,测试目标是评估可能导致系统崩溃的最大访问负载压力。
性能测试反应的是系统在实际生产环境中使用时,随着用户并发访问数量的增加,系统的处理能力。与性能曲线相对应的是用户访问的等待时间(系统响应时间)
性能优化策略
性能分析:检查请求处理的各个环节的日志,分析哪个环节响应时间不合理、超过预期;然后检查监控数据,分析影响性能的主要因素是内存、磁盘、网络、还是CPU,是代码问题还是架构设计不合理,或者系统资源确实不足。
性能优化:根据网站分层架构,可分为Web前端性能优化、应用服务器性能优化、存储服务器性能优化3大类。
Web前端性能优化
主要手段有:优化浏览器访问、使用CDN加速、使用反向代理。
优化浏览器访问
- 减少HTTP请求。主要手段,合并CSS、合并JavaScript、合并图片、尽可能合并数据请求。
- 使用浏览器缓存。通过设置HTTP头中Cache-Control和Expires的属性。
- 启用压缩。压缩HTML、CSS、JavaScript。
- CSS放在页面最上面、JavaScript放在页面最下面。
- 减少Cookie传输。
使用CDN加速
CDN能够缓存对的一般是静态资源,如图片、文件、CSS、Script脚本、静态网页等。
使用反向代理
- 具有保护网络安全的作用。
- 可以配置缓存功能加速Web请求。
- 实现负载均衡的功能。
应用服务器性能优化
主要优化手段:缓存、集群、异步等。
缓存
优先考虑使用缓存优化性能
缓存主要是为了存放那些读写比很高、很少变化的数据。
缓存使用中遇到的问题:
- 对频繁修改的数据使用缓存。(这个是极不合理的)
- 没有热点的访问。(这是在浪费缓存资源)
- 数据不一致与脏读。(这个要根据具体的业务分析)
- 缓存雪崩。(缓存的可用性很重要,通过分布式缓存可以解决)
- 缓存预热。(缓存系统启动的时候就把热点数据加载好)
- 缓存穿透。(大量访问不存在数据,缓存中不会存在,访问数据库)
分布式缓存架构
- 以JBoss Cache为代表的需要更新同步的分布式缓存
- 以Memcached为代表的不互相通信的分布式缓存
异步操作
可以使用消息队列进行异步操作
使用集群
使用负载均衡技术为一个应用构建一个由多台服务器组成的服务器集群。
代码优化
多线程
使用多线程的原因主要由两个:IO阻塞和多CPU。
一台服务器启动多少线程合适呢?一般公式如下:
启动线程数 = [任务执行时间/(任务执行时间 - IO等待时间)] * CPU内核数
最佳启动线程数和CPU内核数量成正比,和IO阻塞时间成反比。如果任务都是CPU计算型任务,那么多线程最多不超过CPU内核数;如果任务需要等待磁盘操作,网络响应,那么多启动线程有助于提高任务并发度,提高系统吞吐能力,改善系统性能。
资源复用
从编程角度,资源复用的方式主要有两种模式:单例和对象池。
数据结构
垃圾回收
存储服务器性能优化
- 使用固态硬盘
- 关系型数据库主要使用B+树;NoSQL主要使用LSM树
- RAID(廉价磁盘冗余阵列);HDFS(Hadoop分布式文件系统)
万无一失:网站的高可用架构
网站的可用性(Availability)描述网站可有效访问的特性。
网站的可用性的度量与考核
网站可用性度量
网站不可用也被称作网站故障,业界通常用多少个9来衡量网站的可用性。
网站不可用时间(故障时间) = 故障修复时间点 - 故障发现(报告)时间点
网站年度可用性指标 = (1 - 网站不可用时间/年度总时间) * 100%
网站可用性考核
可用性指标是网站架构设计的重要指标,对外是服务承若,对内是考核指标。可以用故障分对工程师进行考核。
故障分是指对网站故障进行分类加权计算故障责任的方法。
故障分 = 故障时间(分钟) * 故障权重。
ps:不同的故障类别设置不同的权重值。
高可用的网站架构
网站的高可用架构设计的主要目的就是保证服务器硬件故障时服务依然可用、数据依然保存并能够被访问。
主要手段是数据和服务的冗余备份及失效转移。
分层模:应用层、服务层、数据层。应用层主要负责具体业务逻辑处理;服务层负责提供可复用的服务;数据层负责数据的存储于访问。
ps:个人理解。这里的分层和代码中的分层有相似的地方,但又有不同的地方。在代码中应用层(Controller)只是作为跳转,很少去处理业务逻辑。很高兴的是,本书提供了一张图说明了此处分层的意思:
高可用的应用
应用层主要处理网站应用的业务逻辑,因此有时也称为“业务逻辑层”,应用的一个显著特点是应用的无状态性。
无状态的应用是指应用服务器不保存业务的上下文信息,而仅根据每次请求提交的数据进行相应的业务逻辑处理,每个服务实例(服务器)之间完全对等,请求提交到任意服务器,处理结构都是完全一样的。
通过负载均衡进行无状态服务的失效转移
应用服务器集群的Session管理
- Session复制。在集群规模小的时候使用。
- Session绑定。将同一个IP源的请求,发给一台服务器。
- 利用Cookie记录Session。
- Session服务器。
高可用的服务
可复用的服务模块为业务产品提供基础公共服务,大型网站中这些服务通常都独立分布式部署,被具体应用远程调用。
- 分级管理
- 超时设置
- 异步调用
- 服务降级:拒绝服务和关闭服务
- 幂等性设计
高可用的数据
保证数据存储高可用的手段是数据备份和失效转移机制。
CAP原理
高可用的数据有如下几个层面的含义:
- 数据持久性
- 数据可访问性
- 数据一致性
CAP原理认为,一个提供数据服务的存储系统无法同时满足数据一致性(Consistency)、数据可用性(Availibility)、分区耐受性(Partition Tolerance,系统具有跨网络分区的伸缩性)这三个条件。
在大型网站中,通常会选择强化分布式存储系统的可用性(A)和伸缩性(P),而在某种程度上放弃一致性(C)。
数据一致性分为:数据强一致性、数据用户一致、数据最终一致。
数据备份
冷备份
热备份
异步热备方式
应用程序将数据写入主存储服务器(Master),然后再通过异步现场将操作数据同步到从存储服务器(Slave)。通常使用读写分离的方法访问Slave和Master数据库,写操作只访问Master数据库,读操作只访问Slave数据库。
同步热备方式
应用程序同时将操作数据写入各个村粗服务器。没有主从之分。
失效转移
如果数据服务器集群中任何一台服务器宕机,那么应用程序针对这台服务器的所有读写操作都需要重新路由到其他服务器,保证数据访问不会失败,这个过程叫做失效转移。
失效转移操作由三部分组成:
- 失效确认:心跳检测和应用程序访问失败报告
- 访问转移
- 数据恢复
高可用网站的软件质量保证
网站发布
自动化测试
预发布验证
预发布服务器和生产服务器的唯一不同就是没有配置在负载均衡服务器上,外部用户不能访问。
预处理服务器和线上正式服务器都部署在相同的环境下,可能使用的数据库也是相同的。
ps:怎么处理数据问题?难道不是应该部署在不同的数据环境下么?
代码控制
trunk分支可以用来发布预生产和生产
dev分支可以用来发布测试和压测等。
自动化发布
灰度发布
可立即回滚的发布。
网站运行监控
不允许没有监控的系统上线。
监控数据采集
用户行为日志收集
包括用户操作系统与浏览器版本信息、IP地址、页面访问路径、页面停留时间等
- 服务器日志收集
- 客户端浏览器日志收集
服务器性能监控
收集服务器性能指标,如系统Load、内存占用、磁盘IO、网络IO等。
运行数据报告
如缓存命中率、平均响应延迟时间、待处理的任务数等
监控管理
系统报警
失效转移
自动优雅降级
永无止境:网站的伸缩性架构
网站的伸缩性是指不需要改变网站的软硬件设计,仅仅通过改变部署的服务器数量就可以扩大或者缩小网站的服务处理能力。
网站架构的伸缩性设计
网站架构的伸缩性设计可分为两类,一类是根据功能进行物理分离实现伸缩,一类是单一功能通过集群实现伸缩。前者是不同的服务器部署不同的服务,提供不同的功能;后者是集群内的多台服务器部署相同的服务,提供相同的功能。
不同功能进行物理分离实现伸缩
- 纵向分离(分层后分离):将业务处理流程上的不同部分分离部署,实现系统伸缩性。
- 横向分离(业务分割后分离):将不同的业务模块分离部署,实现系统伸缩性。
单一功能通过集群规模实现伸缩
集群伸缩性又可分为应用服务器集群伸缩性和数据库服务器集群伸缩性。这两种集群由于对数据状态管理的不同,技术实现也有非常大的区别。而数据服务器集群也可分为缓存服务器集群和存储数据服务器集群,这两种集群的伸缩性设计也不大相同。
应用服务器集群的伸缩性设计
负载均衡服务器:HTTP请求分发装置。
HTTP重定向负载均衡
HTTP重定向服务器是一台普通的应用服务器,其唯一的功能就是根据用户的HTTP请求计算一台真实的Web服务器地址,并将该Web服务器地址写入HTTP重定向响应中(状态码302)返回给用户浏览器。
- 优点:比较简单。
- 缺点:浏览器需呀两次请求服务器才能完成一次访问,性能较差;重定向服务器可能成为集群的瓶颈;搜索引擎对302状态码不友好。
DNS域名解析负载均衡
每次域名解析请求都会根据负载均衡算法计算一个不同的IP地址返回(DNS服务器中有对一个域名配置多个IP地址)。这样一个域名记录中配置的多个服务器就构成一个集群,并可以实现负载均衡。
- 优点:将负载均衡的工作交给DNS,省去了网站管理维护负载均衡服务器的麻烦;DNS还支持基于地理位置的域名解析,改善性能。
- 缺点:DNS的多级解析,可能会存在域名、IP缓存问题;DNS在供应商那边,无法做更多的改善和更强大的管理。
反向代理负载均衡
反向代理服务器可以同时提供负载均衡的功能。
管理一组Web服务器,将请求根据负载均衡算法转发到不同Web服务器上。Web服务器处理完成的响应也需要通过代理服务器返回给用户。由于Web服务器不直接对外提供服务,因此Web服务器不需要使用外部IO地址,而反向代理服务器则需要配置双网卡和内部外部两套IP地址。
- 优点:和反向代理服务器功能集成在一起,部署简单;
- 缺点:反向代理服务器是所有请求和响应的中转站,其性能可能成为瓶颈。
IP负载均衡
关键在于真实物理Web服务器响应数据包如何返回给负载均衡服务器。一种方案是负载均衡服务器在修改目的IP地址的同时修改元地址,将数据包源地址设为自身IP,即源地址转换(SNAT),这样Web服务器的响应会再回到负载均衡服务器;另一种方案是将负载均衡服务器作为真实物理服务器集群的网关服务器,这样所有的响应数据都会到达负载均衡服务器。
数据链路层负载均衡
数据链路层负载均衡是指在通信协议的数据链路层修改mac地址进行负载均衡。
这是目前大型网站使用最广的一种负载均衡手段。在Linux平台上最好的负载均衡开源产品是LVS(Linux Virtual Server)。
负载均衡算法
负载均衡服务器的实现可以分为两个部分:
1、根据负载均衡算法和Web服务器列表计算得到集群中一台Web服务器的地址。
2、将请求数据发送到该地址对应的Web服务器上。
负载均衡算法:
轮询(Round Robin,RR)
所有请求被依次分发到每台应用服务器上,即每台服务器需要处理的请求数目都相同,适合于所有服务器硬件都相同的场景。加权轮询(Weighted Round Robin,WRR)
根据应用服务器硬件性能的情况,在轮询的基础上,按照配置的权重将请求分发到每个服务器,高性能的服务器能分配更多请求。随机(Random)
请求被随机分配到各个应用服务器。因为随机算法本身很均衡,在服务器性能不同的情况下也可以加权,所以这种方案简单实用。最少连接(Least Connections)
记录每个应用服务器正在处理的连接数(请求数),将新到的请求分发到最少连接的服务器上。这是最符合负载均衡定义的算法。源地址散列(Source Hashing)
根据请求来源的IP地址进行Hash计算,得到应用服务器,这样来自同一个IP地址的请求总在同一个服务器上处理,该请求的上下文信息可以存储在这台服务器上,在一个会话周期内重复使用,从而实现会话黏滞。
分布式缓存服务器集群的伸缩性设计
分布式缓存服务器集群中不同服务器中缓存的数据各不相同,缓存访问请求不可以在缓存服务器集群中的任意一台处理,必须先找到缓存有需要数据的服务器,然后才能访问。
新加入缓存服务器后应使整个缓存服务器集群中已经缓存的数据尽可能还被访问到,这是分布式缓存集群伸缩性设计的最主要目标。
Memcached分布式缓存集群的访问模型
其中路由算法负责根据应用程序输入的缓存数据KEY计算得到应该讲数据写入到Memcached的哪台服务器(写缓存)或应该从哪台服务器读取数据(读缓存)。
Memcached分布式缓存集群的伸缩性挑战
在缓存服务器扩容的时候,缓存不能被命中的问题是个很棘手的挑战。
一种办法是在网站访问量最少的时候扩容缓存服务器集群,然后模拟请求的方法逐渐预热缓存。
另一种方法是一致性Hash算法。
分布式缓存的一致性Hash算法
一次性Hash算法通过一个叫作一致性Hash环的数据结构实现KEY到缓存服务器的Hash映射。
数据存储服务器集群的伸缩性设计
数据存储服务器集群的伸缩性对数据的持久性和可用性提出了更高的要求。
关系数据库集群的伸缩性设计
如上图,数据写操作都在主服务器上,由主服务器将数据同步到集群中其他从服务器,数据读操作以及数据分析等离线操作在从服务器上进行。
同时我们也可以根据业务进行分库,比如将数据量很大的库拆分成多个库,分别存储。
支持数据分片的分布式关系型数据库解决方案产品有Amoeba和Cobar。
由于各类分布式关系型数据库解决方案都是很简陋,限制了关系型数据库的一些功能(比如事务)。所以,我们必须在业务上回避分布式关系型数据库的各种特点:避免事务或利用事务补偿机制代替数据库事务;分解数据访问逻辑避免JOIN操作等。
NoSQL数据库集群的伸缩性设计
NoSQL数据库产品都放弃了关系型数据库的两大重要基础:以关系代数为基础的结构化查询语句(SQL)和事务一致性保证(ACID)。而强化了高可用性和可伸缩性。
随需应变:网站的可扩展架构
扩展性(Extensibility):对现有系统影响最小的情况下,系统功能可持续扩展或提升的能力。表现在系统基础设施稳定不需要经常变更,应用之间较少依赖和耦合,对需求变更可以敏捷响应。
伸缩性(Scalability):指系统能够通过增加(减少)自身资源规模的方式增强(减少)自己计算处理事务的能力。
构建可扩展的网站架构
设计网站可扩展架构的核心思想是模块化,并在此基础上,降低模块间的耦合性,提高模块的复用性。
利用分布式消息队列降低系统耦合性
如果模块之间不存在直接调用,那么新模块或者修改模块就对其他模块影响最小,这样系统的可扩展性无疑是更好一些的。
事件驱动架构
事件驱动架构(Event Driven Architecture):通过在低耦合的模块之间传输事件消息,以保持模块的松散耦合,并借助事件消息的通信完成模块间合作,典型的EDA架构就是操作系统中常见的生产者消费者模式。具体的实现如:分布式消息队列等。
分布式消息队列
分布式消息队列可以看做是将先进先出的数据结构部署到独立的服务器上,应用程序可以通过远程访问接口使用分布式消息队列,进行消息存取操作,进而实现分布式的异步调用。
消息生产者应用程序通过远程访问接口将消息推送给消息队列服务器,消息队列服务器将消息写入本地内存队列后立即返回成功响应给消息生产者。消息队列服务器根据消息订阅列表查找订阅消息的消息消费者应用程序,将消息队列中的消息按照先进先出的原则将消息通过远程通信接口发送给消息消费者程序。
利用分布式服务打造可复用的业务平台
使用分布式服务是减低系统耦合性的另一个重要手段。
解决巨无霸系统的方案就是拆分。将模块独立部署,降低系统耦合性。拆分可分为纵向拆分和横向拆分两种。
纵向拆分:将一个大应用拆分为多个小应用。如果新增业务较为独立,那么就直接将其设计部署为一个独立的Web应用系统。
横向拆分:将复用的业务拆分出来,独立部署为分布式服务,新增业务只需要调用这些分布式服务,不需要依赖具体的模块代码,即可快速搭建一个应用系统,而模块内业务逻辑变化的时候,只要接口保持一致就不会影响业务程序和其他模块。
纵向拆分相对比较简单,通过梳理业务,将较少相关的业务剥离,使其成为独立的Web应用。而对横向拆分,不但需要识别可复用的业务,设计服务接口,规范服务依赖关系,还需要完善的分布式服务管理框架。
ps:横向拆分和现在流行的微服务架构很类似。
WebServer与企业级分布式服务
服务提供者通过WSDL(Web Services Description language,Web服务描述语言)向注册中心(Service Broker)描述自身提供的服务接口属性,注册中心使用UDDI(Universal Description,Discovery,and Integration,统一描述、发现和集成)发布服务提供者提供的服务,服务请求者从注册中心检索到服务信息后,通过SOAP(Simple Object Access Protocol,简单对象访问协议)和服务提供者通信,使用相关服务。
大型网站分布式服务的需求与特点
- 负载均衡
- 失效转移
- 高效的远程通信
- 整合异构系统
- 对应用最少侵入
- 版本管理
- 实时监控
分布式服务框架设计
可以参见Facebook的Thrift、淘宝的Dubbo等
可扩展的数据结构
可以使用NoSQL,做到可扩展数据结构设计。
利用开放平台建设网站生态圈
开放平台是网站内部和外部交互的接口,外部需要面对众多的第三方开发者,内部需要面对网站内诸多的业务服务。
- API接口
- 协议转换
- 安全
- 审计
- 路由
- 流程
固若金汤:网站的安全架构
网站应用攻击与防御
常见的攻击有XSS攻击、SQL注入攻击、CSRF攻击、Session劫持等手段。
XSS攻击
XSS攻击即跨站点脚本攻击(Cross Site Script),指黑客通过篡改网页,注入恶意HTML脚本,在用户浏览网页时,控制用户浏览器进行恶意操作的一种攻击方式。
常见的XSS攻击类型:
- 反射型,攻击者诱使用户点击一个嵌入恶意脚本的链接,达到攻击的目的。
- 持久型,黑客提交含有恶意脚本的请求,保存在被攻击的Web站点的数据库中,用户浏览网页时,恶意脚本被包含在正常页面中,达到攻击的目的。
防范手段:
- 过滤,转换输入
- HttpOnly
注入攻击
- SQL注入
- OS注入
CSRF攻击
CSRF(Cross Site Request Forgery,跨站点请求伪造),攻击者通过跨站请求,以合法用户的身份进行非法操作。CSRF的主要手段是利用跨站请求,在用户不知情的情况下,以用户的身份伪造请求。其核心是利用了浏览器Cookie或服务器Session策略,盗取用户身份。
其他攻击和漏洞
- Error Code
- HTML注释
- 文件上传
- 路径遍历
Web应用防火墙
ModSecurity是一个开源的Web应用防火墙,探测攻击并保护Web应用程序,既可以嵌入到Web应用服务器中,也可以作为一个独立的应用程序启动。
网站安全漏洞扫描
信息加密技术及密钥安全管理
信息加密技术可分为三种:单项散列加密、对称加密和非对称加密。
单项散列加密
如:MD5、SHA等
对称加密
如:DES算法、RC算法等
非对称加密
如:RSA算法等
密钥安全管理
- 将密钥和算法放在一台单独的服务器上,其他系统通过调用该系统的服务进行加解密。
- 加密算法放在应用系统中,密钥则放在独立服务器上。
信息过滤与反垃圾
常见的信息过滤与反垃圾手段有以下几种。
文本匹配
文本匹配主要解决敏感词过滤的问题。
分类算法
比较简单实用的分类算法有贝叶斯分类算法。