《大型网站技术架构——核心原理与案例分析》 李智慧
读书笔记(1)
1. 技术演化
- 最初是应用程序、文件、数据库都在同一台服务器上完成最简单的网站结构。
- 为解决存储空间不足的问题,出现应用服务器、文件服务器、数据库服务器职责分开的情况。
- 应用服务器主要处理业务逻辑,需要更快更强的 CPU;
- 文件服务器需要存储用户上传的文件,需要更大的硬盘;
- 数据库服务器需要快速磁盘检索和数据缓存,所以需要更快的硬盘和更大的内存。
- 网站使用的缓存分为两种:应用服务器上的本地缓存(特点:响应快,但数据量小,可能跟程序争用内存资源)、缓存在分布式缓存服务器上的远程缓存(可采用集群的方式,不受内存容量限制)。
- 为提高并发处理能力,采用应用服务器集群的方式。
- 采用集群的方式,是改善负载压力的一种简单成熟的方式。【important】至此,应用服务器的负载压力不再是瓶颈了。
- 可以增加负载均衡调度服务器,进行请求分发的工作。
- 数据库读写负荷过大时,可以采用两台数据库主从热备的方式。
- 写数据时,访问主数据库,主数据库将数据更新同步到从数据库中。
- 读数据库,直接访问从数据库。
- 在应用服务器使用专门的数据访问模块,使得数据库的读写分离对应用透明。
- 数据库拆分的最终手段是:分布式数据库,而且是在单表数据规模非常庞大的时候才使用。网站更常用的是业务拆库,将不同业务的数据库部署在不同的物理服务器上。(采用超链接建立关系,比如网站首页的导航),也可以通过消息队列进行数据分发。
- 为缓解网络访问延迟的问题,可以采用 CDN 和反向代理的方式。
- CDN:推荐阅读:什么是 CDN。CDN 的缓存来自距离用户最近的网络提供商机房获取数据。
- 反向代理则部署在网站的中心机房,当用户请求到达中心机房后,首先访问的服务器是反向代理服务器,如果反向代理服务器中缓存着用户所请求的资源,那么将直接返回给用户。
- 效果:一方面加快用户访问速度、另一方面减轻后端服务器的负载压力。两种方式最常见的应用场景就是缓存静态资源。
- 为满足对数据存储和检索的需求,网站采用一些非关系型数据库如 NoSQL 和非数据库查询技术如搜索引擎等。
- 此时应用服务器最好使用一个统一数据访问模块访问各种数据,使诸多数据源的访问对应用程序透明。
2. 大型网站架构模式
2.1 横向分层
在大型网站架构中,将软件系统分成应用层(表示层)、服务层、数据层(持久层)。
分层的注意点:
- 必须合理规划层次边界和接口。
- 分层依据的是逻辑层次,不是物理层次。
- 虽然可以将三层安排在同一个物理机上,但是大型的网站上,三层一定会安排在独立的服务器上。
2.2 纵向分割
将功能和服务分割成高内聚低耦合的模块单元,
网站分割成“购物、论坛、搜索、广告”等;
购物继续分割成“机票酒店、3C、小商品”等;
小商品继续分割成“首页、搜索列表、商品详情”等
2.3 分布式
目的:实现高并发、大数据量的访问,服务更多的用户。
2.3.1 分布式的弊端
- 服务调用需要经过网络,可能对性能造成比较严重的影响;
- 服务器越多,宕机的概率越大,降低网站的可用性;
- 数据一致性、分布式事务很难保证;
- 网站依赖错综复杂、开发管理维护困难;
2.3.2 常用的分布式方案
- 分布式应用和服务
- 将分层、分割后的应用和服务模块分布式部署。
- 分布式静态资源
- 即动静分离。静态资源分布式部署,可以减轻应用服务器的负载压力;使用独立域名加快浏览器并发加载的速度。
- 分布式数据和存储
- 可对传统的 RDBMS 进行分布式部署,也可直接采用分布式产品如 NoSQL 等。
- 分布式计算
- 主要针对一些后台业务、包括搜索引擎的索引构建、数据仓库的数据分析统计等。
- 特点:移动计算(而不是移动数据),将计算程序分发到数据所在的位置以加速计算和分布式计算。
2.3.3 集群
使用分布式将已经分层和分割的模块独立部署了,但是对于用户访问集中的模块(比如首页),仍要将独立部署的服务器集群化,即多台服务器部署相同应用构成一个集群,再通过负载均衡服务设备共同对外提供服务。
- 重点关注:并发性和失效转移机制
- 即使访问量很小的分布式应用和服务,也至少部署两台服务器构成一个小的集群,目的就是提高系统的可用性。
2.3.4 缓存
除了上文介绍的 CDN、反向代理外,还有本地缓存、分布式缓存等形式。
- 本地缓存:在应用服务器的本地缓存热点数据。
- 分布式缓存:适用在大型网站中(因为缓存的数据量也很大),将数据缓存在一个专门的分布式缓存集群中,应用程序通过网络通信访问缓存数据。
缓存的前提条件:
1. 局部性原理;
2. 数据在某段时间内有效,不会很快过期。
2.3.5 异步
异步的使用场景举例(可以按照生产者消费者模式来理解):
- 单服务器内部通过多线程共享内存队列的方式实现异步。
- 前一个线程将输出写入队列中,后一个线程从队列中读取数据进行处理
- 分布式系统中,多个服务器集群通过分布式消息队列实现异步。
异步消息队列的特性:
1. 提高系统可用性;
2. 加快网站响应速度;
3. 消除并发访问高峰;
2.3.6 冗余
- 通过冗余实现服务高可用。
- 数据库除了冷备份(定期备份,存档保存)外,还需要热备份(数据库主从分离,实时同步)。
- 为了抵御地震等不可抗力导致的网络完全瘫痪,还要对整个数据中心进行备份,全球范围内部署灾备数据中心。
2.3.7 自动化
- 发布过程自动化。
- 自动化代码管理;
- 自动化测试;
- 自动化安全监测(安全攻击测试);
- 自动化部署。
- 线上生产环境进行自动化监控。
- 自动化报警(参数异常报警);
- 自动化失效转移(将失效的服务器从集群中隔离出去);
- 自动化失效恢复(故障消除后,服务重启,同步数据保持数据一致性);
- 自动化降级(当访问超负荷时,通过拒绝部分请求即关闭部分不重要的服务进行降负载);
- 自动化分配资源(将空闲资源分配给重要的服务)。
2.3.8 安全
关键词:密码和手机校验码、加密、过滤、风险控制。
3. 架构
架构的定义:最高层次的规划,难以改变的决定。
软件架构需要考虑性能、可用性、伸缩性、扩展性和安全性这五个要素。
3.1 性能
性能的评价指标有:响应时间、TPS、系统性能计数器等
3.2 可用性
当服务器宕机的时候,服务或应用依然可用。
主要手段:冗余。
3.3 伸缩性
伸缩性是指,通过不断向集群中加入服务器的手段来缓解不断上升的用户并发访问压力和不断增长的数据存储需求。
评价标准:是否可以用多台服务器构建集群,是否容易向集群中新增服务器,加入的新服务器是否可以提供跟原本服务器无差别的服务,集群中可容纳的服务器的总数是否有限制等。
Tips:大部分 NoSQL 数据库产品对伸缩性支持地很好。
3.4 扩展性
扩展性:主要指功能需求变化的适应能力。
衡量标准:网站新增业务时,是否对现有业务的产品透明性无影响,不需要任何改动或少量改动既有业务就可以上线新产品等。
主要手段:事件驱动架构和分布式服务。
3.5 安全性
针对现存和潜在的各种攻击和窃密手段,是否有可靠的应对策略。
4. 瞬时响应
4.1 开发人员看待网站性能
开发者关注:应用程序本身及其相关子系统的性能,包括响应延迟、系统吞吐量、并发处理能力、系统稳定性等技术指标。
优化手段:缓存加速、集群提高吞吐能力、异步消息加快响应及实现削峰、代码优化。
4.2 运维人员看待网络性能
运维者关注:基础设施性能和资源利用率,包括带宽、服务器配置等。
优化手段:建设优化骨干网、使用高性价比定制服务器,利用虚拟化技术优化资源利用等。
网站性能的主要指标有:响应时间、并发数、吞吐量、性能计数器(比如对象与线程数、内存使用、CPU 使用、磁盘/IO)等。
4.3 如何进行性能测试
手段:性能测试、负载测试、压力测试、稳定性测试。
专业用词:
- 系统最大负载点:随系统压力持续增加,系统处理能力最终到达的最大值。
- 系统的崩溃点:到达最大负载点后,如果继续增加压力,系统处理能力反而下降,直到资源消耗到达极限,此时就是系统的崩溃点。
4.4 如何对性能问题进行优化
主要分为 Web 前端性能优化、应用服务器性能优化、存储服务器性能优化。
4.4.1 Web 前端性能优化
4.4.1.1 浏览器访问优化
- 减少 HTTP 请求。因为 HTTP 请求开销昂贵,所以考虑合并 HTTP 请求,即将浏览器一次访问需要的 JavaScript、CSS、图片等合并成一个文件。
- 采用浏览器缓存。静态资源可缓存在浏览器中(数天或者几个月),在更新静态资源时可以通过更改文件名来实现,即生成一个新的 JS 文件,并更新 HTML 文件中的引用。
- 启用压缩。服务器端压缩文件、浏览器端解压缩文件。但压缩过程也有压力损耗,需权衡决定是否采用。
- CSS 放在页面最上面,JS 放在页面最下面。CSS 下完后才会开始渲染,而JS 会立即执行,可能会阻塞整个页面。
- 减少 Cookie 传输。每次请求和响应都有 Cookie,所以 Cookie 带的数据量要小;同时一些静态资源的访问中,Cookie 没有意义,可考虑静态资源使用独立域名访问,避免请求时发送 Cookie。
4.4.1.2 CDN 加速
CDN 缓存的多是静态资源。其他略。
4.4.1.3 反向代理
反向的理解:一般的代理都是在浏览器一侧,然而反向代理是放在网站机房的一侧。
反向代理服务器三个作用:安全、缓存、负载均衡。
1. 安全是指所有请求必须经过代理服务器,所以可当做安全屏障;
2. 缓存是指,一些静态资源(甚至部分热点动态资源)可以放在反向代理服务器中,加快 Web 的响应速度,减轻 Web 服务器的负载压力。
+ 如果动态内容发生变化,通过内部通知机制告知反向代理服务器缓存失效,反向代理会重新加载最新的动态内容再次缓存起来。
3. 负载均衡。略,不解释。
4.4.2 应用服务器性能优化
指处理业务的服务器的优化。
优化手段:缓存、集群、异步。
4.4.2.1 缓存
缓存的本质:一个内存 Hash 表。
Tips:缓存也有其可用性。因为一旦缓存服务崩溃时,数据库完全不能承受过大的压力而宕机,所以实践中有些网站会通过缓存热备的方式提高缓存可用性,但此举违背了缓存的初衷(缓存本就不是可靠地数据源)。
- 缓存预热:新启动的缓存系统要花很久建立缓存,所以可以在缓存系统启动时就把热点数据加载好。
- 缓存穿透:因为不恰单的业务或者恶意攻击,持续高并发地请求某一个不存在的数据,因为缓存没有保存该数据,所有的请求都落在数据库上,对数据库造成很大的压力,甚至崩溃。
- 解决办法是,将不存在的数据也缓存起来。
4.4.2.2 分布式缓存架构
定义:缓存部署在多个服务器组成的集群中,以集群的方式提供缓存服务。
一般有 JBoss Cache 和 Memcached 两种方式:
- JBoss Cache:缓存集群中的所有服务器中保存相同的缓存数据,当某一台出现数据更新时,会通知其他服务器更新缓存数据。
- 特点1:缓存与应用通常在同一台服务器上,应用程序可从本地快速获取缓存数据。
- 特点2:缓存数据总量受限于单台服务器的内存空间,而且如果集群规模较大,信息同步需要的代价太大,所以很少在大型网站中使用,一般是企业应用系统中(即专用系统,用户没那么多的情况)。
- Memcached:采用互不通信的分布式架构方式,缓存与应用分属不同的服务器,应用程序通过一致性 Hash 等路由算法选择缓存服务器并远程访问缓存数据。
- 特点1:缓存服务器间互不通信,可以理解为耦合度低,所以缓存集群可以很容易实现扩容,具有良好的可伸缩性。
- 特点2:使用 TCP 协议(UDP 也支持)通信。
- 特点3:Memcached 通信协议简单,可以发展出非常丰富的客户端程序,几乎支持所有主流的网站编程语言。
- 特点4:网络通信性能高。
- 特点5:内存管理高效。
4.4.2.3 异步操作
通过异步操作,将短时间高并发产生的事务消息存储在消息队列中,从而削平高峰期的并发事务。
任何可以晚点做的事情都应该晚点再做。
4.4.2.4 使用集群
使用负载均衡技术,使服务器的并发请求数据控制在最佳运行区间,获得最佳的访问请求延迟。
4.4.2.5 代码优化
- 使用多线程。
- 将对象设计为无状态对象:比如 servlet 就是无状态对象可以被并发调用;
- 使用局部对象;
- 并发访问资源时使用锁。
- 资源复用。
- 单例,比如 spring 容器管理的单例。
- 对象池,比如数据库连接池、线程池等。
- 善用数据结构。
- 比如尽力提高 HashCode 的随机性,可提高 Hash 表的读写性能。
- 垃圾回收,选择较优的垃圾回收策略。
4.4.3 存储性能优化
- 选择机械硬盘或者 SSD?
- 传统机械硬盘在数据随机访问时性能较差。
- 在 SSD 中,寻道一如往事不再~~
- 选择 B+ 树或者 LSM 树?推荐阅读:B+树与LSM树的区别与联系
- B+ 树广泛应用在 RDBMS 中,检索时从根开始查找数据所在的节点编号和磁盘位置,将其加载到内存中然后继续查找。
- LSM 树应该在非关系型数据库如 NoSQL 中,是一个 N 阶合并树。写操作都在内存中完成,增删改都会新建一个记录并在内存中成为排序树,只有等到数据量超过内存阈值后,将这颗排序树与磁盘上最新的排序树合并。
- 特点:写操作比使用 B+ 树快上 5~10 倍,读操作可能有所提升,也可能有所减弱。
- RAID 和 HDFS?扩展阅读:Hadoop 不用RAID 0的原因
- RAID 是廉价磁盘冗余阵列,在 RDBMS 和文件系统中应用较多。
- HDFS 在存储集群的多台服务器上进行数据并发和备份。