第一章 大型网站架构演化

大型网站软件系统的特点

  • 高并发,大流量
  • 高可用:7*24小时
  • 海量数据
  • 用户分布广泛,网络情况复杂
  • 安全环境恶劣
  • 需求快速变更,发布频繁
  • 渐进式发展

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

  1. 初始阶段的网络结构
    小型网站,应用程序、数据库、文件等所有资源都在一台服务器上。

  2. 应用服务和数据服务分离
    应用和数据分离,网站使用三台服务器:

  • 应用服务器:要处理大量业务逻辑,需要更快更强大的CPU
  • 数据库服务器:需要快速磁盘检索和数据缓存,需要更快的硬盘和更大的内存
  • 文件服务器:需要存储大量用户上传的文件,需要更大的硬盘
  1. 使用缓存改善网站性能
  • 二八定律,大部分业务访问集中在一小部分数据上,将这一小部分数据缓存在内存中
  • 网站使用的缓存有两种:
    • 缓存在应用服务器上的本地缓存:访问速度快,但内存有限,缓存数据量有限,可能会出现和应用程序争用内存的情况
    • 缓存在专门的分布式缓存服务器上的远程缓存:可以使用集群的方式
  1. 使用应用服务器集群改善网站的并发处理能力
  • 当一台服务器的处理能力、存储空间不足时,不要企图去换更强大的服务器,更恰当的做法是增加一台服务器分担原有服务器的访问及存储压力,从而实现系统的可伸缩性。
  • 通过负载均衡调度服务器,可将用户的访问请求分发到应用服务器集群中的任何一台服务器上。
  1. 数据库读写分离
  • 使用缓存后,仍然有有一部分读操作(缓存访问未命中、缓存过期)和全部的写操作,需要访问数据库
  • 数据库提供主从热备功能,配置两台数据库主从关系,将一台数据库服务器的数据更新同步到另一条服务器上,实现数据库读写分离,改善数据库负载压力。
  • 往从库中读数据,往主库中写数据,主库到从库之间主从复制,更新从库
  1. 使用反向代理和CDN加速网站响应
  • CDN和反向代理的基本原理都是缓存,目的都是尽早返回数据给用户
  • CDN:部署在网络提供商的机房,用户可以从距离自己最近的网络提供商机房获取数据
  • 反向代理:部署在网站的中心机房,用户请求到达中心机房时,首先访问的服务器是反向代理服务器,如果反向代理服务器中缓存着用户请求的资源,就将其直接返回给用户
  1. 使用分布式文件系统和分布式数据库系统
  • 分布式数据库:网站数据库拆分的最后手段,只有在单表数据规模非常庞大的时候才使用。不到不得已时,网站更常用的数据库拆分手段是业务分库,将不同业务的数据库部署在不同的物理服务器上。
  1. 使用NOSQL和搜索引擎
  • 网站需要采用一些非关系数据库技术(如NoSQL),和非数据库查询技术(如搜索引擎)。
  • 这些技术对可伸缩的分布式特性具有更好的支持。
  • 应用服务器通过一个统一数据访问模块访问各种数据,减轻应用程序管理多个数据源的麻烦。
  1. 业务拆分
  • 使用分而治之的手段将整个网站业务分成不同的产品线,分归不同的业务团队负责。
  • 技术也会根据产品线划分,每个应用独立部署维护,应用之间可以通过超链接建立关系,也可以通过消息队列进行数据分发,最多的还是通过访问同一个数据存储系统来构成一个关联的完整系统。
  1. 分布式服务
  • 各个应用系统都需要执行许多相同的业务操作,可以将这些共用的业务提取出来,独立部署。由这些可复用的业务连接数据库,提供共用业务服务,应用系统只需管理用户界面,通过分布式服务调用共用业务服务完成具体业务操作。

大型网站架构演化的价值观

  • 大型网站都是从小型网站发展而来,在网站还很小的时候就去追求网站的架构是舍本逐末,得不偿失的。小型网站最需要做的就是为用户提供好的服务来创造价值,得到用户的认可,活下去,野蛮生长。
  • 大型网站架构技术的核心价值是随网站所需灵活应对
  • 驱动大型网站技术发展的主要力量是网站的业务发展

网站架构设计误区

  • 一味追随大公司的解决方案
  • 为了技术而技术:不要脱离网站业务发展的实际,一味追求时髦的新技术
  • 企图用技术解决所有问题:技术用来解决业务问题的,业务的问题也可以通过业务的手段去解决。

第二章 大型网站架构模式

网站架构模式

1. 分层

  • 将系统在横向维度上切分成几个部分,每个部分负责一部分相对比较单一的职责,然后通过上层对下层的依赖和调用组成一个完整的系统。
  • 将网站软件系统分为应用层、服务层、数据层
  • 大的分层结构内部还可以继续分层:
    • 应用层:细分为视图层、业务逻辑层
    • 服务层:细分为数据接口层、逻辑处理层
    • 数据层

2. 分割

  • 纵向对软件进行切分
  • 将不同的功能和服务分割开来,包装成高内聚低耦合的模块单元,一方面有助于软件的开发和维护;另一方面便于不同模块的分布式部署,提高网站的并发处理能力和功能扩展能力

3. 分布式

  • 分层和分割的一个主要目的是为了切分后的模块便于分布式部署,即将不同模块部署在不同的服务器上,通过远程调用协同工作。
  • 分布式缺点:
    • 服务调用必须通过网络,可能影响性能
    • 服务器宕机的概率也增大
    • 一台服务器宕机造成服务不可用可能导致许多应用不可访问,网站可用性降低
    • 在分布式环境中保持数据一致性也非常困难,分布式事务也难以保证
    • 导致网站依赖错综复杂,开发管理维护困难
    • 因此不要为了分布式而分布式
  • 常用分布式方案:
  1. 分布式应用和服务
    将分层和分割后的应用和服务模块分布式部署,改善性能,提高并发性,减少数据库连接资源消耗,使不同应用复用共同的服务,便于业务功能扩展

  2. 分布式静态资源
    网站的静态资源(JS、CSS、Logo图片等)独立分布式部署,并采用独立的域名,即常说的动静分离。

  3. 分布式计算
    使用Hadoop及其MapReduce分布式计算框架进行批处理计算,特点是移动计算而不是移动数据,将计算程序分发到数据所在的位置以加速计算和分布式计算。

此外,还有可以支持网站线上服务器配置实时更新的分布式配置;分布式环境下实现并发和协同的分布式锁;支持云存储的分布式文件系统等。

4. 集群

  • 对于用户访问集中的模块(如网站首页),还需要将独立部署的服务器集群化,即多台服务器部署相同应用,构成一个集群,通过负载均衡设备共同对外提供服务。
  • 可以提高系统的可用性

5. 缓存

  • CDN:内容分发网络,部署在距离终端用户最近的网络服务商,在这里缓存网站的一些静态资源或较少变化的数据,可以就近以最快速度返回给用户,视频网站和门户网站会将用户访问量大的热点内容缓存在CDN
  • 反向代理:属于网站前端架构的一部分,部署在网站的前端,当用户请求到达网站的数据中心时,最先访问到的就是反向代理服务器,这里缓存网站的静态资源,无需将请求继续转发给应用服务器就能返回给用户
  • 本地缓存:应用服务器本地缓存热点数据,应用程序可以在本机内存中直接访问数据无需访问数据库
  • 分布式缓存:本地缓存内存空间有限,使用分布式缓存,将数据缓存在一个专门的分布式缓存集群中,应用程序通过网络通信访问缓存数据

使用缓存条件:

  1. 数据访问热点不均衡(冷、热数据)
  2. 数据在某个时间段内有效,不会很快过期,否则缓存的数据就会因失效而产生脏读,影响结果的正确性。

6. 异步

  • 将一个业务操作分成多个阶段,每个阶段之间通过共享数据的方式异步执行进行协作。
  • 在单一服务器内部可通过多线程共享内存队列的方式实现异步,处在业务操作前面的线程将输出写入队列,后面的线程从队列中读取数据进行处理。
  • 在分布式系统中,多个服务器集群通过分布式消息队列实现异步,分布式消息队列可以看做内存队列的分布式部署。
  • 异步架构是典型的生产者消费者模式,二者不存在直接调用。

7. 冗余

  • 服务器冗余运行,数据冗余备份,这样当某台服务器宕机时,可以将其上的服务和数据访问转移到其他机器上。
  • 访问和负载很小的服务也必须部署至少两台服务器构成一个集群,其目的就是通过冗余实现服务高可用。
  • 数据库除了定期备份,存档保存,实现冷备份外,为了保证在线业务高可用,还需要对数据库进行主从分离,实时同步实现热备份。
  • 为了抵御自然灾害等不可抗力导致的网站完全瘫痪,某些大型网站会对整个数据中心进行备份,全球范围内部署灾备数据中心,网站程序和数据实时同步到多个灾备数据中心。

8. 自动化

  • 目前大型网站的自动化架构设计主要集中在发布运维方面。
  • 发布过程自动化、自动化代码管理、自动化测试、自动化安全检测、自动化部署、自动化监控、自动化告警、自动化失效转义、自动化失效恢复、自动化降级、自动化分配资源

9. 安全

  • 密码、手机校验码进行身份认证
  • 登录、交易等操作需要对网络通信进行加密
  • 网站服务器上存储的敏感数据(如用户信息)等也进行加密处理
  • 为了防止机器人程序滥用网络资源攻击网站,网站使用验证码进行识别
  • 对于常见的用于攻击网站的XSS攻击、SQL注入、进行编码转换等响应处理
  • 对于垃圾信息、敏感信息进行过滤
  • 对交易转账等重要操作根据交易模式和交易信息进行风险控制

第三章 大型网站核心架构要素

  • 一般来说,除了系统功能需求外,软件架构还需要关注性能、可用性、伸缩性、扩展性和安全性这5个架构要素。

1. 性能

  • 从用户浏览器到数据库,影响用户请求的所有环节都可以进行性能优化
  1. 浏览器端:浏览器缓存、页面压缩、合理布局页面、减少Cookie传输、CDN(将网站静态内容分发至离用户最近的网络服务商机房,使用户通过最大UN访问路径获取数据)、在网站机房部署反向代理服务器(缓存热点文件,加快请求响应速度,减轻应用服务器负载压力)
  2. 应用服务器端:使用服务器本地缓存和分布式缓存(通过缓存在内存中的热点数据处理用户请求,加快请求处理过程,减轻数据库负载压力)、通过异步操作将用户请求发送至消息队列等待后续任务处理,当前请求直接返回响应给用户、将多台应用服务器组成一集群共同对外服务
  3. 在代码层面:通过使用多线程、改善内存管理等手段优化性能
  4. 数据库服务器端:索引、缓存、SQL优化、使用NoSQL等非关系型数据库(优化数据模型、存储结构、伸缩特性)

2. 可用性

  • 高可用设计的目标就是当服务器宕机的时候,服务或者应用依然可用
  • 网站高可用的主要手段是冗余,应用部署在多台服务器上同时提供访问,数据存储在多太服务器上互相备份,任何一台服务器宕机都不会影响应用的整体可用,也不会导致数据丢失
    • 应用服务器:多台应用服务器通过负载均衡设备组成一个集群共同对外提供服务
    • 存储服务器:需要对数据进行实时备份,当服务器宕机时需要将数据访问转移到可用的服务器上,并进行数据恢复
  • 除了运行环境,网站的高可用还需要软件开发过程的质量保证。

3. 伸缩性

  • 所谓伸缩性是指通过不断向集群中加入服务器的手段来缓解不断上升的用户并发访问压力和不断增长的数据存储需求
  • 衡量架构伸缩性的主要标准就是是否可以用多台服务器构建集群,是否容易向集群中添加新的服务器,加入新的服务器后是否可以提供和原来的服务器无差别的服务,集群中可容纳的总的服务器数量是否有限制
    • 对于应用服务器集群,只要服务器上不保存数据,所有服务器都是对等的,使用合适的负载均衡设备即可向集群中不断加入服务器
    • 对于缓存服务器集群,加入新的服务器可能导致缓存路由失效,进而导致集群中大部分缓存数据都无法访问,需要改进缓存路由算法保证缓存数据的可访问性。
    • 虽然关系数据库支持数据复制、主从热备等机制,但是难以做到大规模集群的可伸缩性,因此关系数据库的集群伸缩性方案必须在数据库之外实现,通过路由分区等手段将部署有多个数据库的服务器组成一个集群。
    • 对于大部分NoSQL数据库产品,先天就是为海量数据而生,可以做到在较少运维参与下实现集群规模的线性伸缩。

4. 扩展性

  • 网站的扩展性架构直接关注网站的功能需求
  • 网站可伸缩架构的主要手段是事件驱动架构和分布式服务
  • 事件驱动架构:通常利用消息队列实现,将用户请求和其他业务事件构造成消息发布到消息队列,消息的处理者作为消费者从消息队列中获取消息进行处理。
  • 分布式服务:将业务和可复用服务分离开来,通过分布式服务框架调用,新增产品可以通过调用可复用服务实现自身业务逻辑;可复用服务升级变更时,也可以通过提供多版本服务对应用实现透明升级,不需要强制应用同步变更
  • 吸引第三方开发者,使用大型网站提供的开发平台接口,使用网站数据开发周边产品,扩展网站业务

安全性

  • 网站的安全架构是保护网站不受恶意访问和攻击,保护网站的重要数据不被窃取

第四章 瞬时响应:网站的高性能架构

网站性能测试

网站性能测试指标

  1. 响应时间
  2. 并发数
  • 系统能够同时处理请求的数目,对网站而言,并发数即网站并发用户数,指同时提交请求的用户数目。
  • 为了真实模拟用户行为,测试程序并不是启动多线程然后不停地发送请求,而是在两次请求之间加入一个随机等待时间,这个时间被称作思考时间。
  1. 吞吐量
  • 指单位时间内系统处理的请求数量(请求数/秒、页面数/秒、访问人数/天、处理的业务数/小时等来衡量)
  1. 性能计数器
  • 描述服务器或操作系统性能的一些数据指标(System Load系统负载、对象与线程数、内存使用、CPU使用、磁盘与网络I/O等指标)
  • 对这些指标设置告警阈值,当监控系统发现性能计数器超过阈值时,及时告警

性能测试方法

  • 性能测试
  • 负载测试
  • 压力测试
  • 稳定性测试

性能优化策略

  1. 性能分析:检查请求处理的各个环节的日志,分析哪个环节响应时间不合理、超出预期;然后检查监控数据,分析影响性能的主要因素是内存、磁盘、网络还是CPU,是代码问题还是架构设计不合理,或者系统资源确实不足。
  2. 性能优化:Web前端性能优化、应用服务器性能优化、存储服务器性能优化

Web前端性能优化

Web前端指浏览器加载、网站视图模型、图片服务、CDN服务等,主要优化手段有优化浏览器访问、使用反向代理、CDN等

1. 浏览器访问优化

  • 减少http请求
    • 合并CSS、合并JS、合并图片,将浏览器一次访问需要的JS、CSS合并成一个文件,这样浏览器只需一次请求。合并图片时,如果每张图片都有不同的超链接,可通过CSS偏移响应鼠标点击操作,构造不同的URL
  • 使用浏览器缓存
    • 缓存CSS、JS、LOGO、图标等静态资源文件,通过设置HTTP头中Cache-Control和Expires的属性,可设定浏览器缓存及缓存时间。
    • 若静态资源文件变化需要及时应用到客户端浏览器,可通过改变文件名实现。即更新JS文件时不是更新JS文件内容,而是生成一个新的JS文件并更新HTML文件中的引用。
    • 更新静态资源时,应采用批量更新的方法,应一个文件一个文件逐步更新,并有一定的间隔时间,以免浏览器turnaround大量缓存失效,集中更新缓存,造成服务器负载骤增、网络堵塞等情况。
  • 启用压缩
    • 在服务器端对文件进行压缩,在浏览器端对文件解压缩,减少通信传输的数据量。(压缩HTML、CSS、JS等文件,但压缩对服务器和浏览器会产生一定压力,要对通信带宽和服务器资源权衡考虑)
  • 将CSS放在页面最上面,JS放在页面最下面
    • 浏览器会在下载完全部CSS之后才对整个页面进行渲染
    • 浏览器在加载JS后立即执行,有可能会阻塞整个页面,除非页面解析需要用到JS
  • 减少Cookie传输
    • Cookie会包含在每次请求和相应中,Cookie太大会影响数据传输,尽量减少Cookie中传输的数据量
    • 对于某些静态资源的访问,如CSS、JS等,发送Cookie没有意义,可以考虑静态资源使用独立域名访问,避免请求静态资源时发送Cookie,减少Cookie传输次数

2. CDN加速

  • CDN即内容分发网络,本质仍是一个缓存,
  • 网络访问第一跳,CDN部署在网络运营商的机房,将数据缓存在离用户最近的地方,最短路径返回响应,加快用户访问速度,减少数据中心负载压力。
  • CDN能够缓存的一般是静态资源,如图片、文件、CSS、Script脚本、静态网页等

3. 反向代理

  • 反向代理服务器位于网站机房一侧,代理网站Web服务器接收HTTP请求
  • 反向代理服务器也可以保护网站安全
  • 反向代理服务器也可以通过配置缓存功能加速Web请求。当用户第一次访问静态内容的时候,静态内容就被缓存在反向代理服务器上,这样当其他用户访问该静态内容时,就可以直接从反向代理服务器返回。
  • 有些网站会把动态内容也缓存在代理服务器上,当这些动态内容有变化时,通过内部通知机制通知反向代理缓存失效,反向代理会重新加载最新的动态内容并再次缓存起来。
  • 反向代理也可以实现负载均衡的功能,通过负载均衡构建的应用集群可以提高系统总体处理能力,改善网站高并发情况下的性能。

应用服务器性能优化

1. 分布式缓存

缓存的基本原理

  • 网站性能优化第一定律:优先考虑使用缓存优化性能
  • 缓存的本质是一个内存hash表,数据缓存以一对key-value的形式存储在内存hash表中,hash表数据读写的时间复杂度是O(1),hashcode可以理解为对象的唯一标识符
  • 缓存主要存放读写比很高、很少变化的数据,如商品的类目信息、热门词的搜索列表信息、热门商品信息等
  • 应用程序读取数据时,先到缓存中读取,如果读取不到或数据已失效,再访问数据库,并将数据写入缓存。
  • 二八定律:80%的访问落在20%的数据上,利用hash表和内存的高速访问特性,将这20%的数据缓存起来,可以很好的改善系统性能。

合理使用缓存

  • 不应缓存频繁修改的数据(读写比在2:1以上缓存才有意义)
  • 如果系统访问的数据没有热点,不遵循二八定律,即大部分数据访问没有集中在小部分数据上,缓存就没有意义,因为大部分数据还没有被再次访问就已经被挤出内存了
  • 数据不一致和脏读:
    • 缓存超过失效时间,从数据库中重新加载,有一定时间的数据不一致
    • 若数据更新时立即更新缓存,则也会带来更多系统开销和事务一致性的问题
  • 缓存可用性:
    • 缓存雪崩:当缓存服务崩溃时,数据库不能承受那么大压力而宕机,进而导致整个网站不可用
    • 分布式缓存服务器集群
  • 缓存预热:在缓存系统启动时预加载热点数据
  • 缓存穿透:持续高并发地请求某个不存在的数据,由于缓存中没有该数据,所有的请求都会落到数据库上,数据库压力很大,甚至崩溃。简单的对策是将不存在的数据也缓存起来(value值为null)

分布式缓存架构