《大型网站技术架构:核心原理与案例分析》笔记
大型网站软件系统的特点
- 高可用,大流量(海量 数据)
- 用户分布广泛,网络情况复杂
- 安全环境恶劣
- 需求快速变更、发布频繁
- 渐进式发展
大型网站架构演化发展历程
1、初始阶段
大型网站都是从小型网站发展而来,网站架构也一样,服务器一台。应用程序、数据库、文件等所有的资源都在一台服务器上。通常服务器操作系统使用linux,应用程序使用php开发,然后部署在Apache上,数据库使用mysql
2、应用服务和数据服务分离
应用和数据分离后整个网站使用三台服务器:应用服务器、文件服务器和数据库服务器
随着用户及数据量增多,数据库压力太大导致访问延迟
3、使用缓存缓存改善网站性能
网站使用的缓存可分为两种:缓存在应用服务器上的本地缓存和缓存在专门的分布式缓存服务器上的远程缓存。本地缓存的访问速度更快一些,但是受应用服务器内存限制,其缓存数据量邮箱,而且会出现和应用程序争用内存的情况。远程分布式缓存可以使用集群的方式,部署大内存的服务器作为专门的缓存服务器,可以使用集群的方式,部署大内存的服务器作为专门的缓存服务器,可已在理论上做到不受内存容量限制的缓存服务
使用缓存后,数据访问压力得到有效缓解,但是单一应用服务器能够处理的请求连接有限,在网站访问高峰期,应用服务器称为整个网站的瓶颈
4、使用应用服务器集群改善网站的并发处理能力
使用集群是网站解决高并发、海量数据问题的常用手段。当一台服务器的处理能力了、存储空间不足时,不要企图去换更强大的服务器。应该增加一台服务器分担原有的服务器的访问及存储压力。持续增加服务器不断改善系统性能,从而实现系统的可伸缩性。应用服务器实现集群是网站可伸缩集群架构设计中较为简单成熟的一种
通过负载均衡调度服务器,可将来自用户浏览器的访问分发到应用服务器集群中的任何一台服务器上,如果有更多的用户,就在集群中加入更多的应用服务其,使应用服务其的负载压力不再成为整个网站的瓶颈
5、数据库读写分离
目前大部分的主流数据库都提供主从热备功能,通过配置两台数据库主从关系,可以将一台数据库服务器的数据更新同步到另一台服务器上。网站利用数据库的这一功能,实现数据库读写分离,从而改善数据库负载压力
应用服务器在写数据的时候,访问主数据库,主数据库通过主从复制机制将数据更新同步到从数据库,这样当应用服务器读数据的时候,就可以通过从数据库获取数据。为了便于应用程序访问读写分离后的数据库,通常在应用服务器端使用专门的数据访问模块,使数据库读写分离对应用透明
6、使用反向代理和CDN加速网站响应
cdn和反向代理的基本原理都是缓存,区别在于CDN部署在网络提供商的机房,使用户在请求网站服务时,可以从距离自己最近的网络提供商机房获取数据;而反向代理则部署在网站的中心机房,当用户请求到达中心机房后,首先访问的服务器是反向代理服务器,如果反向代理服务器中缓存着用户请求的资源,就将其直接返回给用户
目的都是尽早返回数据给用户,一方面加快用户访问速度,另一方面也减轻后端服务器的负载压力
7、使用分布式文件系统和分布式数据库系统
分布式数据库是网站数据库拆分的最后手段,只有在单表数据规模非常庞大的时候才使用,不到不得已时,网站更常用的数据库拆分手段是业务分库,将不同业务的数据库部署到不同的物理服务器上
8、使用NoSQL和搜索引擎
随着网站业务越来越复杂,对数据存储和检索的需求也越来越复杂,网站需要采用一些非关系数据库技术如NoSQL和非数据库查询技术如搜索引擎
NoSQL和搜索引擎都是源自互联网的技术手段,对可伸缩的分布式特性具有更好的支持。应用服务器则通过一个统一数据访问模块访问各种数据,减轻应用程序管理诸多数据源的麻烦
9、业务拆分
为应对日益复杂的业务场景,通过使用分而治之的手段将网站业务分成不同产品线
10、分布式服务
随着业务拆分越来越小,存储系统越来越庞大,应用系统的整体复杂度呈指数级增加,部署维护越来越困难。由于所有应用要和所有数据库系统连接,在数万台服务器规模的网站中,这些连接的数目是服务器规模的平方,导致数据库连接资源不足,拒绝服务
将共用的业务提取出来,独立部署。由这些可服用的业务连接数据库,提供共用业务服务,而应用系统只需要管理用户界面,通过分布式服务调用共用业务服务完成具体业务操作
大型网站的架构演化到这里,基本上大多数的技术问题都得以解决,注入跨数据中心的实时数据同步和具体网站业务相关的问题也都可以通过组合改进现有技术架构来解决
但事物发展到一定阶段,就会拥有自身的发展冲动,摆脱其初衷,向着使自己更强大的方向发展,既然大型网站架构解决了海量数据的管理和高并发事物的处理,那么就可以吧这些解决方案应用到网站自身以外的业务上去,目前许多大型网站都开始建设云计算平台,将计算机作为一种基础资源出售,中小网站不需要再关心技术架构问题,只需要按需付费,就可以是网站随着业务的增长逐渐获得更大的存储空间和更多的计算资源
网站架构模式
为了解决大型网站面临的高并发访问、海量数据处理,高可靠运行等一系列问题与挑战,大型互联网公司在实践中提出了许多解决方案,以实现网站高性能、高可用、易伸缩、可扩展、安全等各种技术架构目标,这些结局方案又被更多网站重复使用,从而逐渐形成大型网站架构模式
分层
- 将系统很想维度切分成几个部分,每个部分负责一部分相对比较单一的职责,然后通过上层对下层的依赖和调用组成一个完整的系统
- 将网站软件系统分为应用层、服务层、数据层
- 应用层:负责具体业务和视图展示,如网站首页及搜索输入和结果展示
- 服务层:为业务层提供服务支持(业务逻辑),如用户管理服务,购物车服务等
- 数据层:提供数据存储访问服务,如数据库、缓存、文件、搜索引擎等
- 分层架构模式最初的目的是规划软件清晰的逻辑结构便于开发维护,但在网站的发展过程中,分层结构对网站支持高并发想分布式方向发展至关重要
分割
- 如果说分层是将软件横向切分,那么分割就是在纵向进行切分
- 将不同功能和服务分割开来,包装成高内聚低耦合的模块单元,一方面有助于开发和维护,一方面便于不同模块的分布式不是,提高网站的并发处理能力和功能扩展能力
分布式
- 分层和分割的目的是为了切分后的模块便于分布式部署,即将不同模块部署在不同的服务器上,通过远程调用协同工作。分布式意味着可以使用更多的计算机完成同样的功能。
- 常用的分布式方案
- 分布式应用和服务
- 将分层和分割后的应用和服务模块分布式部署,除了可以改善网站性能和并发性、加快开发和发布速度、减少数据库连接资源消耗外;还可以使不同应用复用共同的业务,便于业务功能扩展
- 分布式静态资源
- 将js、css、图片等静态资源独立分布式部署,并采用独立的域名。可减轻应用服务器的负载压力,通过独立域名加快浏览器并发加载速度
- 分布式数据和存储
- 分布式计算
- 此外,还有可以支持网站线上服务器配置实时更新的分布式配置;分布式环境下实现并发和协同的分布式锁;支持云存储的分布式文件系统等
- 分布式应用和服务
集群
- 集群的目的就是提高系统的可用性
缓存
- 缓存就是将数据存放在距离计算最近的位置以加快处理速度。
- CDN
- 即内容分发网络,部署在距离终端用户最近的网络服务商,用户的网络请求总是先到他的网络服务商那里,在这里缓存网站的一些静态资源(较少变化的数据),可以就近以最快速度返回给用户,如视频网站和门户网站会将用户访问量大的热点内容缓存在CDN
- 反向代理
- 属于网站前端架构的一部分,部署在网站的前端,当用户请求到达网站的数据中心时,最先访问到的就是反向代理服务器,这里缓存网站的静态资源,无需将请求继续转发给应用服务器就能返回给用户
- 本地缓存
- 在应用服务器本地缓存着的热点数据,应用程序可以在本机内存中直接访问数据
- 分布式缓存
- 将数据缓存在一个专门的分布式缓存集群中,应用程序通过网咯通信访问缓存数据
- 使用缓存有两个前提条件,一是数据访问热点不均衡,某些数据频繁访问,应放缓存中;二是数据在某个时间段内有效,不会很快过期否则缓存的数据就会因已经失效而产生脏读,影响结果的正确性
- 缓存除了可以加快数据访问速度,还可以减轻后端应用和数据存储的负载压力
异步
- 软件发展的一个重要目标是降低软件耦合性。系统解耦合的手段除了前面提到的分层、分割、分布等,还有一个重要手段就是异步,义务之间的消息传递不是同步调用,二十将一个阢操作分成多个阶段,每个阶段之间通过共享数据的方式异步执行进行协作
- 在单一服务器内部可通过多线程共享内存队列的方式实现异步,处在业务操作前面的线程将输出写入到队列,后面的线程从队列中读取数据进行处理;在分布式系统中,多个服务器集群通过分布式消息队列实现异步,分布式消息队列可以看做内存队列的分布式存储
- 异步架构是典型的生产者消费者模式,两者不存在直接调用,只要保持数据结构不变,彼此功能实现可以随意变化而不互相影响,这对网站扩展新功能非常便利。除此之外,使用异步消息队列还有如下特性
- 提高系统可用性。消费者服务器发生故障,数据会在消息队列服务器中存储堆积,生产者服务器可以继续处理业务请求,系统整体表现无故障。消费者服务器恢复正常后,继续处理消息队列中的数据
- 加快网站响应速度。处在业务处理前端的生产者服务器在处理完业务请求后,将数据写入消息队列,不需要等待消费者服务器处理就可以返回,响应延迟减少
- 消除并发访问高峰。使用消息队列将突然增加的访问请求数据放入消息队列中,等待消费者服务器依次处理,就不会对整个网站负载造成太大压力
- 需要注意的是,使用异步方式处理业务可能会对用户体验、业务流程造成影响。需要网站产品设计方面的支持
冗余
- 网站需要一直连续运行,但是服务器随时可能出现故障,特别是服务器规模比较大时,出现某台服务器宕机是必然事件。要想保证在服务器宕机的情况下网站依然可以继续服务,不丢失数据,就需要一定程度的服务器冗余运行,数据冗余备份,这样当某台服务器宕机时,可以将其上的服务和数据访问战役到其他机器上
- 访问和负载很小的服务也必须部署至少两台服务器构成一个集群,其目的就是通过冗余实现服务高可用。数据库除了定期备份,存档保存,实现冷备份外,为了保证在线业务高可用,还需要对数据库进行主从分离,实时同步热备份
自动化
安全
- 密码和手机验证码进行身份认证;登录、交易等操作需要对网络通信进行加密,存储用户敏感数据也要加密;为了防止机器人程序滥用网络资源攻击网站,网站使用验证码进行识别;对于常见的用户攻击网站的XSS攻击、SQL注入,进行编码转换等相应处理;对于垃圾信息、敏感信息进行过滤;对交易转账等重要操作根据交易模式和交易信息进行风险控制
大型网站核心架构要素
架构:最高层次的规划,难以改变的决定,这些规划和决定奠定了事物未来发展的方向和最终的蓝图
软件架构:有关软件整体结构与组件的抽象描述,用于指导大型软件系统各个方面的设计
除了当前的系统功能需求外,软件架构还需要关注性能、可用性、伸缩性、扩展性和安全性这5个架构要素,架构设计过程中需要平衡着5个要素之间的关系以实现需求和架构目标
性能
- 浏览器端:浏览器缓存、页面压缩、合理布局页面、较少Cookie传输等手段;还可以使用CDN,将网站静态内容分发至离用户最近的网络服务商机房,使用户通过最短的访问路径获取数据;可以在网站机房部署反向代理服务器,缓存热点文件,加快请求响应速度,减轻应用服务器负载压力
- 应用服务器端:本地缓存、分布是缓存,减轻数据库压力;也可以通过一部操作将用户请求发送到消息队列等待后续任务处理,而当前请求直接返回响应给用户;代码层面,多线程、改善内存管理等手段
- 数据库服务器端:索引、缓存、SQL优化等。NoSQL数据库通过优化数据模型、存储结构、伸缩特性等
- 衡量网站性能有一些列指标,重要的有响应时间、TPS、系统给性能计数器等
可用性
- 高可用设计的目标就是当服务器宕机的时候,服务或者应用依然可用
- 网站高可用的主要手段是冗余,应用部署在多态服务器上同时提供访问,数据存储在多台服务器上互相备份,任何一台服务器宕机都不会影响应用的整体可用,也不会导致数据丢失
- 对应用服务器而言,多态应用服务器通过负载均衡设备组成一个集群共同对外提供服务,任何一台服务器宕机,只需把请求切换到其他服务器就可实现应用的高可用,但是一个前提条件是应用服务器上不能保存请求的会话信息。否则服务器宕机,会话丢失,即使将用户请求转发到其他服务器上也无法完成业务处理
- 对于存储服务器,由于其上存储着数据,需要对数据进行实时备份,当服务器宕机时需要将数据访问转移到可用的服务器上,并进行数据恢复以保证继续有服务器宕机的时候数据依然可用
- 除了运行环境,网站的高可用还需要软件开发过程的质量保证。通过预发布验证,自动化测试、自动化发布、灰度发布等手段,减少将故障引入线上环境的的可能,避免故障范围扩大
- 衡量高可用指标,就是假设系统中任何一台或者多台服务器宕机时,以及出现各种不可预期的问题时,系统真题是否依然可用
伸缩性
- 通过不断向集群中不断向集群中加入服务器的手段来缓解不断上升的用户并发访问压力和不断增长的数据存储需求
- 标准就是是否可以用那个多态服务器构建集群,是否容易想集群中添加新的服务器。加入新的服务器后是否可以提供和原来的服务器无差别的服务。集群中可容纳的总的服务器数量是否有限制
- 对应用服务器集群:只要服务器上不保存数据,所有服务器都是对等的,通过使用合适的负载均衡设备就可以向集群中不断加入服务器
- 对缓存服务器集群:加入新的服务器可能会导致缓存路由失效,进而导致集群中大部分缓存数据都无法访问。虽然缓存的数据可以通过数据库重新加载,但是如果应用已经严重依赖缓存,可能会导致整个网站崩溃。需要改进缓存路由算法保证缓存数据的可访问性
- 关系数据库虽然支持数据复制,主从热备等机制,但是很难做到大规模集群的伸缩性,因此关系数据库的集群伸缩性方案必须在数据库之外实现,通过路由分区等手段将部署多个数据库的服务器组成一个集群
扩展性
- 随着网站快速发展,功能不断扩展,使网站架构能够快速响应需求的变化
- 标准就是网站增加新的业务产品时,是否可以实现对现有产品透明无影响,不需要任何改动或者很少改动既有业务功能就可以上线新产品。不同产品之间是否低耦合
- 主要手段是事件驱动架构和分布式服务
- 事件驱动架构通常利用消息队列实现。将用户请求和其他业务事件构成消息发布到消息队列,消息的处理者作为消费者从消息队列中获取消息进行处理。
- 分布式服务则是将业务和可复用服务分离开来,通过分布式服务框架调用。
安全性
- 保护网站不受恶意访问和攻击,保护网站的重要数据不被窃取
- 衡量安全性标准就是针对现存和潜在的各种攻击与窃密手段,是否有可靠的应对策略
网站的高性能架构
性能测试方法
- 性能测试、负载测试、压力测试、稳定性测试
性能优化可分为Web前端性能呢优化、应用服务器性能优化、存储服务器性能优化3大类
1、web前端性能优化
一般说来,web前端指网站业务逻辑之前的部分,包括浏览器加载、网站视图模型、图片服务、CDN服务等。主要优化手段有优化浏览器访问、使用反向代理、CDN等
- 浏览器访问优化
- 减少http请求:主要手段是合并CSS、合并js、合并图片。将浏览器一次访问需要的js、css合并成一个文件,这样浏览器就只需要一次请求。图片也可以合并,多张图片合并成一张,如果每张图片有不同的超链接,可通过css偏移响应鼠标点击操作,构造不同的URL
- 使用浏览器缓存:将更新频率比较低的静态资源文件缓存在浏览器中。通过设置HTTP头中Cache-Control和Expires的属性,可设定浏览器缓存
- 启用压缩:在服务端对文件进行压缩,在浏览器对文件解压缩,可有效减少通信传输的数据量css放在页面最上面、js放在页面最下面:浏览器会在下载完全部css之后对整个页面进行渲染,因此最好的做法是将css放在页面最上面,让浏览器尽快下载css。js则相反,浏览器在加载js后立即执行,有可能会阻塞整个页面,造成页面显示缓慢,因此js最好放在页面最下面。但是如果页面解析时就需要用到js,这时放在底部就不合适了
- 减少Cookie传输:静态资源的访问,发送cookie没有意义,可以考虑静态资源使用独立域名访问,避免请求静态资源时发送Cookie,减少Cookie传输次数CDN加速(内容分发网络)
- cdn本质任然是一个缓冲,将数据缓存在离用户最近的地方,使用户最快速度获取数据,减少数据中心负载压力;CDN能够缓存的一般是静态资源,如图片、文件、css、script脚本、静态网页等,但是这些文件访问频率很高,将其缓存在CDN可极大改善网页的打开速度
- 反向代理
- 保证网站安全,来自互联网的访问请求必须经过代理服务器,相当于在web服务器和可能的网络攻击之间建立了一个屏障
- 也可以通过配置缓存功能加速web请求。也可以缓存动态内容,比如维基百科及某些博客论坛网站,把热门词条、帖子、博客缓存在反向代理服务器上加速用户访问速度,当这些动态内容有变化时,通过内部通知机制通知反向代理缓存失效,反向代理会中心加载最新的动态内容再次缓存起来
- 此外,反向代理也可以实现负载均衡的功能,而通过负载均衡构建的应用集群可以提高系统总体处理能力,进而改善网站并发情况下的性能
2、应用服务器性能优化
应用服务器就是处理网站业务的服务器,网站的业务代码都部署在这里,是网站开发最复杂,变化最多的地方,优化手段主要有缓存、集群、异步等
- 分布式缓存:合理使用缓存,对网站性能优化意义重大
- 网站性能优化第一定律:优先考虑使用缓存优化性能
- 缓存基本原理:将数据存储在相对较高访问速度的存储介质中,以供系统处理。一方面缓存访问速度快,可以减少数据访问的时间,另一方面如果缓存的数据是经过计算处理得到的,那么被缓存的数据无需重复计算即可直接使用,因此缓存还起到减少计算时间的作用
- 缓存的本质是一个内存Hash表
- 缓存主要用来存放那些读写比很高、很少变化的数据,如商品的类目信息,热门词的搜索列表信息,热门商品信息等。应用程序读取数据时,先到缓存中读取,如果读取不到货数据已失效,再访问数据库,并将数据写入缓存
- 网站数据访问通常遵循二八定律,因此利用Hash表和内存的告诉访问特性,将这20%的数据缓存起来,可很好的改善系统性能,提高数据读取速度,降低存储访问压力
- 合理使用缓存
- 频繁修改的数据:一般说来,数据的读写比在2:1以上,即写入一次缓存,至少读取两次,缓存才有意义
- 没有热点的访问:缓存数据访问比较集中的小部分数据
- 数据不一致与脏读:一般会对缓存的数据设计失效时间
- 缓存可用性:通过分布式缓存服务器集群,可在一定程度上改善缓存的可用性
- 缓存预热:就是在缓存系统启动的时候讲热点数据先预加载好
- 缓存穿透:如果因为不恰当的业务、或者恶意攻击持续高并发地请求某个不存在的数据,由于缓存没有保存该数据,所有的请求都会落到数据库上,会对数据库造成很大压力,甚至崩溃。一个简单对策是将不存在的数据也缓存起来(其value为null)
- 分布式缓存架构
- 指缓存部署在多个服务器组成的集群中,以集群方式提供缓存服务,其架构方式有两种,一种是以JBoss Cache为代表的需要更新同步的分布是缓存,一种是以Memcached为代表的不互相通信的分布式缓存
- JBoss Cache的分布式缓存在集群中所有服务器中保存相同的缓存数据,当某台服务器有缓存数据更新的时候,会通知集群中其他机器更新缓存数据或清除缓存数据。JBoss Cache通常将应用程序和缓存部署在同一台服务器上,应用程序可从本地快速获取数据,但是这种方式带来的问题是缓存数据的数量受限于单一服务器的内存空间,而且当集群规模较