大型网站架构演化
-
初始阶段
单机+开源软件
继续发展的瓶颈: 单机不能满足需求
-
应用服务器, 数据服务器, 文件服务器分离
各种服务器的资源需要不同
继续发展的瓶颈: 数据库压力太大导致访问延迟
-
使用缓存
网站访问特点也有二八定律: 80%的业务访问集中在20%的热点数据
缓存分本地缓存和远程分部式缓存
继续发展的瓶颈: 访问高峰时应用服务器成为瓶颈
-
应用服务器集群
通过负载均衡调度服务器+应用服务器集群, 改善了并发处理能力, 实现了可伸缩性
继续发展的瓶颈: 又是数据库负载
-
数据库读写分离
数据库主从分离, 热备, 实现读写分离, 从而改善数据库负载压力
应用服务器配置专门的数据访问模块, 实现透明的读写分离
继续发展的瓶颈: 网络访问需要加速
-
使用CDN服务器和反向代理服务器
CDN和反向代理原理都是缓存, 可以加快用户访问, 页减轻后端负载
继续发展的瓶颈: 数据库系统和文件系统
-
分布式文件系统和分布式数据库系统
分布式数据库是网站数据库拆分的最后手段, 数据库按照业务分库, 部署到不同物理机器
继续发展的瓶颈: 存储和检索越来越复杂
-
使用NoSQL和搜索引擎
NoSQL和搜索引擎对可伸缩的分布式具有很好的支持
继续发展的瓶颈: 业务复杂
-
业务拆分
按照业务拆分不同应用, 每个应用独立部署维护, 应用之间通过超链接建立关系, 也可以通过消息队列进行数据分发
继续发展的瓶颈: 业务越来越小, 存储系统越来越大, 部署维护越来越困难
-
分布式服务
提取个个业务应用中相同的业务操作, 作为服务独立部署, 提供分布式调用
-
云平台
云计算云存储
大型网站解决了海量数据管理和高并发事务处理, 可以应用到其他网站
大型网站架构模式
模式描述了在我们周围不断重复发生的问题以及该问题解决方案的核心. 这样, 你就能一次又一次地使使用该方案而不必做重复的工作
分层
横向切分系统, 各层职责单一, 通过上层对下层依赖进行调用
目的:
- 各层的资源需求不一致
- 清晰的软件逻辑结构, 便于维护
实例:
- 网络7层协议
- 计算机硬件, 操作系统, 应用软件
- deal service
挑战和约束:
- 合理规划层次边界和接口
- 严格遵循分层约束, 禁止跨层调用或逆向调用
分割
纵向对软件进行切分, 按照功能和服务分割为高内聚低耦合的模块单元
分层和分割都可以提高网站的并发处理能力和扩展能力
分层分割的主要目的是便于分布式部署
分布式
作用:
- 提高性能: 分布式意味着可以使用更多的计算机资源, 提高并发能力
- 提高可扩展性
分布式带来的问题:
- 服务调用必须走网络
- 分离粒度越小, 服务器越多, 服务宕机的概率也就越大
- 分布式环境中数据一致性和事务难度增大
分布式需要量力而行, 切莫为了分布式而分布式
分布式方案:
- 分布式应用和服务 [考虑分布式, css编译没有考虑]
- 分布式静态资源 [js css 多个域名, 独立静态资源域名]
- 分布式数据和存储 [Nosql]
- 分布式计算
- 分布式配置
- 分布式锁
- 分布式文件系统
集群
作用:
- 提高可用性(高可用集群)
- 提高性能, 并发能力 (负载均衡集群)
题外: 分布式与集群的区别
一种观点(我倾向于):
- 分布式:一个业务分拆多个子业务,部署在不同的服务器上; 分布式强调的是任务差异性
- 集群:同一个业务,部署在多个服务器上; 集群强调的是任务的同一性
分布式是将不同的业务分布在不同的地方. 而集群是将多台服务器集中在一起, 实现同一个业务
分布式的每一个节点, 都可以做集群
另一种观点: 集群是个物理形态,分布式是个工作方式
集群: 只要是一堆机器,就可以叫集群,他们是不是一起协作不重要 分布式: 一个程序或系统,只要运行在不同的机器上,就可以叫分布式
集群分类
- 高可用集群
- 负载均衡集群
- 科学计算集群
缓存
- CDN
- 反向代理
- 本地缓存
- 分布式缓存
使用缓存的两个前提:
- 数据访问热点不均
- 数据存在一定时效性, 不会很快过期. 缓存时效性很短的数据会出现脏读 [秒杀数据为什么不能缓存]
异步
作用:
- 系统解耦, 异步架构是典型的生产者消费者模式, 两者不直接调用, 只要保持数据结构不变, 彼此功能实现可以随意变化而互不影响
- 提高可用性 (签到积分实例)
- 加快网站响应速度: 生产者在写入消息队列后马上返回, 无需等待消费者处理
- 消除并发访问高峰
影响: 影响用户体验, 业务流程. 需要产品设计
冗余
主要目的是容灾和可用性
实现方式:
- 集群也是一种冗余的实现
- 冷备份: 数据库定期备份
- 热备份: 数据库主从同步
- 灾备中心
自动化
- 自动化代码管理
- 自动化部署
- 自动化安全检测
- 自动化监控
- 自动化报警
- 自动化失效转移
- 自动化失效恢复
- 自动化降级
- 自动化分配资源
安全
大型网站核心架构要素
架构是最高层次的规划, 是难以改变的决定
架构五要素:
- 性能
- 可用性
- 伸缩性
- 扩展性
- 安全性
瞬时响应: 网站的高性能架构
性能指标
-
响应时间
-
并发数: 同事处理请求的数目
-
吞吐量: 体现系统的整体处理能力. 常见度量单位: 请求树/秒 页面数/秒 访问人数/天 TPS(每秒事务数) HPS(每秒HTTP请求数) QPS(每秒查询数)
提高并发, 吞吐量增加 继续提高, 吞吐量达到极限
-
性能计数器
- System load(系统负载): 被CPU执行和等待的进程数目的总和, 反映系统忙闲程度的重要指标
- 对象与线程数
- 内存使用
- CPU使用
- 磁盘,网络IO等
性能测试方法
- 性能测试: 验证系统在资源可接受范围内, 是否达到性能预期
- 负载测试: 使系统某些性能指标达到安全临界值, 继续施压, 系统处理能力不增反降
- 压力测试: 超过安全负载, 继续施压使系统崩溃, 以获得系统最大承压能力
- 稳定性测试: 特定的软硬件网络环境下, 使用不均匀压力运行较长一段时间, 测试系统是否稳定
性能优化
前端优化
- 减少http请求: 如js/css/图片合并
- 使用浏览器缓存
- 启用压缩: 减少传输量
- css在上, js在下
- 减少cookie传输: 目的是减少传输量, 可以考虑静态资源使用独立域名
- CDN 加速: 本质是缓存, 还起到网络加速作用
- 反向代理: 缓存作用; 包含server安全, 还可以实现负载均衡
应用服务器性能优化
-
分布式缓存
合理使用缓存:
- 谨慎缓存频繁修改的数据, 通常读写比在2:1以上的缓存才有意义
- 谨慎缓存没有热点访问的数据
- 业务需要容忍一定时间的脏读和数据不一致, 因为缓存更新有延迟
- 考虑缓存可用性: 因为缓存是可失数据, 但缓存不可用时往往会造成雪崩; 分布式缓存可以提高缓存可用性, 因此可以缓解此问题.
- 考虑缓存预热: 缓存系统启动时可以考虑主动加载热点数据, 以提高系统性能和降低数据库负载
- 缓存预防穿透: 防止不存在的数据导致频繁的数据库查询. 可以考虑不存在的数据也缓存
分布式缓存架构:
- 节点互相需要通信同步架构(JBoss): 适用小的系统
- 节点互不通信架构(memcached): 伸缩性好, 容易扩容
-
异步操作
任何可以晚点做的事情都应该晚点做
- 改善网站扩展性
- 提高系统性能
-
削峰作用
- 异步操作消费端可能失败, 需要考虑业务一致性和数据一致性
-
使用集群
-
代码优化
-
多线程
解决线程安全问题手段: 将对象设计为无状态; 使用局部对象; 并发访问资源加锁
-
资源复用: 资源比如数据库连接, 通信连接, 线程, 复杂对象, 主要手段:
- 单例
- 对象池: 如线程池
-
优化数据结构: 比如哈希算法约随机, 集群读写效率越高
-
垃圾回收
-
-
存储性能优化
- 机械硬盘: 快速顺序读写, 慢速随机读写
- 固态硬盘: 快速随机读写性能, 适合网站访问数据特性(随机读写)
TODO
小结
分布式可以优化高并发的响应时间, 但是分布式也带来了架构复杂和通信延迟, 因此往往结果是: 缩短了高并发时的延迟, 但是增加了低并发时的延时
性能优化需要合理调整各方面对性能优化的心理预期
万无一失: 网站的高可用架构
可用性度量
- 99: 基本可用, 一年不可用小于 88 小时
- 999: 较高可用, 一年不可用小于 9小时
- 9999: 高可用, 一年不可用小于 53分钟
- 99999: 极高可用, 一年不可用小于 5分钟
高可用网站架构
服务器一年宕机一次是大概率事件, 高频读写磁盘损坏概率更大
高可用手段:
- 冗余备份
- 失效转移
大型网站分层架构
应用层
- 应用层应该设计为无状态 (方便做无状态负载均衡)
- 负载均衡 + 应用集群
- 负载均衡和应用之间心跳检测, 实现失效转移
服务层
- 设计为无状态
- 负载均衡
- 分级管理: 核心服务使用更好的资源和硬件; 服务部署隔离, 避免连锁反应
- 超时设计
- 考虑服务作为异步调用, 需要结合业务场景
- 服务降级: 主要有拒绝服务和关闭功能
- 幂等设计: 服务重复调用无法避免
数据层
- 数据备份
- 失效转移
CAP 原理
CAP无法同时满足, 伸缩性(P)必不可少, 通常是一定程度放弃一致性(C), 保证可用性(A)
数据一致性分为:
- 数据强一致
- 数据用户一致: 数据在各个物理副本可能不一致, 但终端用户访问时, 通过纠错和校验, 可以返回正确的数据
- 数据最终一致: 数据物理存储不一致, 终端用户访问也可能不一致, 但是系统通过一段时间自我修复, 最终达到一致
数据备份
-
冷备:
数据定期复制, 无法保证数据最终一致性
从冷备恢复需要较长时间, 无法保证数据可用性
-
热备:
- 异步热备: 有主从之分, 应用写主, 主返回, 主同步给从
- 同步热备: 无主从之分, 应用写多个副本, 延迟是最慢的那台服务器延迟
失效转移
- 失效确认
- 心跳检测
- 应用访问失败报告
- 访问转移
- 数据恢复
高可用网站的软件质量保证
-
网站发布: 网站发布是一次提前预知的服务器宕机, 可以采用:
- 每次关闭服务器集群的一小部分, 发布完后再切换
- 平滑重启呢??
-
自动化测试:
- 为了全面的回归
- 兼容性测试, 节约人力, 时间成本
-
预发布验证
- 主要原因是测试环境和线上环境的差异
- 问题: 预发布是真实的数据, 操作不当会引起不可预知的问题
-
代码控制
-
自动化发布
- 示例: 火车发布模型, 基于规则驱动
- 好处: 人工干预越少, 自动化程度越高, 引入故障的可能性就越小
-
灰度发布
- 原因1: 集群规模庞大, 如果发生故障, 回滚非常耗时
- 原因2: 可以用于用户测试, 版本测试, 也叫AB测试
网站运行监控
- 监控数据采集 TODO
-
监控管理
- 系统报警
- 失效转移
- 自动优雅降级
永无止境: 网站的伸缩性架构
网站伸缩性是指不需要改变网站软硬件设计, 仅仅通过改变部署的服务器数量就可以扩大或者缩小服务器的处理能力
-
物理分离实现伸缩
- 分层: 横向 (按照处理流程)
- 分割: 纵向 (按照业务) 粒度可以非常小, 甚至是一个关键页面部署一个独立服务
-
单一功能通过集群规模实现伸缩
一头牛拉不动车的时候, 不要去寻找一头更强壮的牛, 而是用两头牛来拉车
- 应用服务器集群
- 缓存集群
- 数据服务器集群
应用服务器集群伸缩性
-
负载均衡
-
http重定向负载均衡:
优点是简单
缺点重定向服务器自身处理能力可能是瓶颈, 集群伸缩规模有限, seo有影响
-
DNS域名解析负载均衡:
利用DNS配置多个ip
优点: 负载均衡工作交给DNS; DNS还支持基于地理位置的域名解析
缺点: DNS生效需要时间; 控制器往往在域名服务商, 网站无法做更强大管理
实际: DNS作为第一级负载均衡, 解析后的服务器是一个网站的负载均衡内部服务器
-
反向代理负载均衡:
优点: 反向代理和负载均衡集成在一起, 部署简单
缺点: 反向代理服务器可能成为瓶颈
-
IP 负载均衡:
入流: 网关服务器修改目的ip实现
出流: 网关服务器修改源ip实现
-
数据链路层负载均衡
网关只修改入流时的mac地址, 出流不需要经过负载均衡
引用广泛
LVS (Linux Virtual Server)
-
负载均衡算法
- 轮询
- 加权轮询
- 随机
- 最少连接
- 原地址散列: 根据请求源的ip地址就行hash计算, 得到应用服务器, 这样可以实现会话粘滞
分布式缓存集群伸缩性
缓存集群和应用集群的区别: 缓存访问必须找到需要数据的服务器
挑战: 缓存服务器上线/下线, 对整个分布式缓存集群影响最小
缓存路由算法:
-
hash 算法/hash 加权算法
缺点: 伸缩性差: N台机器增加一台, 不能命中的概率是N/(N+1)
解决的笨办法: 在网站访问较少的时候进行扩容
-
一致性hash算法
实现:
- 构造长度为
0~2^32
的整数环, hash环代表所有key的映射关系 - 将服务器节点均匀分布在hash环上(一台机器负责若干hash值)
- 通过数据的key计算hash值, 在找到(顺时针查找机器)负责这个hash值的机器
- 新加入机器时, 只影响一小段hash和服务器的对应关系
问题:
- 新加入一个节点后, 新节点和分离节点的负载是其他节点的一半, 负载不均衡
- 性能高和性能低的机器, 负载需要不同
方案: 增加虚拟服务器节点:
- 一个服务器不再是一个单独的节点, 而是多个虚拟服务器节点, 均匀分布在hash环上
- 通过数据的key计算出hash值后, 再通过hash找到虚拟服务器节点, 然后再找到实际的服务器节点
- 这样增减服务器, 会影响到所有实际服务器节点的负载
- 一台服务器的虚拟节点越多, 负载约均衡, 经验值是150
附: 一致性哈希要解决的问题:
- 散列的不变性:就是同一个请求(比如:同一个用户id)尽量的落入到一台机器,不要因为时间等其他原因,落入到不同的机器上了;
- 异常以后的分散性:当某些机器坏掉(或者增加机器),原来落到同一台机器的请求(比如:用户id为1,101,201),尽量分散到其他机器,不要都落入其他某一台机器。这样对于系统的冲击和影响最小
- 构造长度为
数据存储服务器机器伸缩性
数据存储伸缩性和缓存伸缩性相比, 难点在于, 持久性和可用性有更高的要求
- 关系数据库
- NoSQL
关系数据库
- 利用数据库主从之分, 配合读写分离
- 业务分割, 数据分库, 不过存在不能join的制约
- 拆表
- 数据分片代理, 如Cobar
NoSQL
关系数据库的瓶颈: 糟糕的海量数据处理能力和僵硬的设计约束
NoSQL放弃关系数据库的: 1. 结构化查询(SQL) 2. 事务一致性ACID
强化: 高可用; 伸缩性
HBASE TODO
高手定律: 这个世界只有遇不到的问题, 没有解决不了的问题, 高手之所以成为高手, 是因为他们遇到了常人很难遇到的问题, 并解决了.
随需应变: 网站的可扩展性架构
扩展性: 基础设施不需要经常改变, 应用之间较少的依赖和耦合, 对需求敏捷响应
伸缩性: 通过增减自身资源的规模, 实现处理能力的增减
- 开发低耦合系统是软件设计终极目标
- 度量一个开发框架, 设计模式, 编程语言的优劣的重要衡量尺度就是让软件开发过程和软件产品更加低耦合
- 架构师的最大价值: 将大系统切割为N个低耦合的子模块的能力
- 网站设计的核心思想是模块化: 降低耦合; 提高复用
模块部署的两种体现:
- 分布式消息队列
- 分布式服务
2017-8-24 更新: http://www.jianshu.com/p/bf431f8159bd