大型网站技术架构核心原理与案
1. 大型网站架构演化
1.4 网络架构设计误区
1.4.3 企图用技术解决所有问题
12306在2013年抢票为秒杀模式,这种几亿人一票难求的情况下仍然用秒杀模式,无法从技术水平上解决
从业务方面下手,购票改为分时段售票.
2. 大型网站架构模式
建筑学的模式: 每一个模式描述一个在我们周围不断重复发生的问题以及该问题解决方案的核心.这样,你就能一次又一次地使用该方案而不必重复工作
2.1 网站架构模式
2.1.1 分层
横向切分
- 应用层: 视图和业务展示
- 服务层: 为应用层提供服务支持
- 数据层: 提供数据存储访问服务
分层最初为了规划软件清晰的逻辑结构,但分层结构对高并发分布式方向发展至关重要
2.1.2 分割
比如在应用层,将不同业务进行分割
2.1.3 分布式
对于大型网站,分层和分割的其中一个目的是为了切分后的模块便于分布式部署
2.1.4 集群
即使访问量很少的分布式应用和服务,也至少要部署两台服务器构成一个小的集群
2.1.5 缓存
2.1.6 异步
服务器可以通过多线程共享内存队列来实现异步
2.1.7 冗余
服务器可能出现故障,某台服务器down掉是必然事件.
要想保住服务器宕机情况下网站一人可以继续服务,不丢失数据,就需要一定程度的服务器冗余进行,数据冗余备份
访问和负载很小也必须至少部署两台服务器构成一个集群
数据库除了定期备份,存档保存,实现冷备份外,为了保证业务高可用,还需要数据库主从分离,实时同步实现热备份
为了抵御地震,海啸,还需要全球范围内部署灾备数据中心
2.1.8 自动化
- 自动化代码管理: 代码版本控制、代码分支创建合并等过程自动化(打tag可以自动化,但是代码分支创建合并自动化????)
- 自动化测试: 自动化测试并发测试报告
- 自动化部署: 将工程代码自动部署到线上生产环境(简单理解为一键部署吧?)
- 自动化安全检测: 安全检查工具对代码进行静态安全扫描及部署到安全测试环境进行安全攻击测试,评估其安全性.
- 自动化监控: 对服务器进行心跳检测,对各项性能指标和应用程序的关键数据指标.
- 自动化失效转移: 监控到有问题的服务器,自动移除出集群
- 自动化失效恢复: 故障消除后,自动失效恢复
- 自动化降级: 当网站到达高峰时,关闭不重要和耗时的功能,保证整个系统安全可用
- 自动化分配资源: 必要时,还需要自动化分配资源,将空闲资源给配给重要的服务
- 自动化性能测试: 发布部署时,可以对前端模拟加载时间和访问接口自动进行压测(笔者自己加的)
2.1.9 安全
- 通信家吗
- XSS SQL注入防范
3 大型网站核心架构要素
架构: 最高层次的规划,难以改变的决定
3.1 性能
性能只是必要条件,指标有响应时间,TPS,系统性能计数器
3.2 可用性
网站高可用的主要手段是冗余
3.3 伸缩性
应用服务器,只要服务器不保存服务器,所有服务器偶读对等
缓存服务器,加入新服务器可能会导致缓存路由失效,可能会导致系统GG
关系数据库的伸缩性方案必须在数据库之外实现,通过路由分区等手段将部署有多个数据库的服务器组成一个集群
而大部分NoSQL是天生支持伸缩的
3.4 拓展性
如何设计网站的架构能快速响应业务变化,是可拓展的主要目的
3.5 安全性
4 瞬时响应: 网站高性能架构
4.1 网站性能测试
4.1.2 性能测试指标
响应时间
一般的响应时间表
- 打开一个网站: 几秒
- 在数据库查找有索引的记录: 十几毫秒
- 机械磁盘一次寻址定位: 4毫秒
- 从机械磁盘顺序读取1MB数据: 2毫秒
- 从SSD顺序读取1MB数据: 0.3毫秒
- 从远程分布式缓存Redis读取一个数据: 0.5毫秒
- 从内存中读取1MB数据: 十几微秒
- Java本地方法调用: 几毫秒
- 网络传输2KB数据: 1微秒
并发数
指系统能够同时处理请求的数目
吞吐量
指单位时间内系统处理的请求数量
- TPS: 每秒事务数
- HPS: 每秒HTTP请求数
- QPS: 每秒查询数
性能计数器
主要是top的指标
4.3 应用服务器性能优化
4.3.4 代码优化
多线程
启动线程数 = [任务执行时间/(任务执行时间-IO等待时间)] X CPU内核数
注意线程安全问题
- 将对象设计为无状态对象: 对象本身不存储状态信息(对象无成员变量或者成员变量也是无状态对象)
- 使用局部变量: 除非故意的把对象传给其他线程
- 并发访问资源时加使用锁:
资源复用
- 单例
- 对象池
5 万无一失: 网站的高可用架构
6 永无止境: 网站的伸缩性架构
6.3 分布式缓存集群的伸缩性设计
6.3.2 Memcached分布式缓存集群的伸缩性挑战
简单的路由算法可以用余数Hash
用服务器数目除缓存数据KEY的Hash值
余数为服务器列表的下标编号
如果不考虑服务器集群的伸缩性,余数Hash几乎可以满足绝大多数缓存路由需求
但是
假如由于业务发展网站从三台缓存服务器扩容到四台
那么大概会有3/4被缓存的数据不能被命中
所以这种扩容抖好一般都要在访问量比较少时j进行(例如半夜)
假如在100台服务器中加入一台服务器,不能命中的概率为99%
6.3.3 分布式缓存的异质性Hash算法
一致性Hash算法通过一个叫做一致性Hash环的数据结构实现KEY到缓存服务器的Hash映射
具体算法过程: 先构造2^32的整数环(一致性Hash环), 根据节点名称的Hash值(其分部范围是[0, 2^32 - 1]), 将缓存服务器节点放置在这个Hash环上。
然后根据需要缓存数据的KEY值计算得到其Hash值(其范围也是[0, 2^32 - 1]), 然后在Hash环上顺时针查找距离这个Key的Hash值最近的缓存服务器节点
就完成了KEY到服务器的Hash映射查找
当服务器扩容时 只需要讲新节点插入一致性Hash环即可, 影响的只有整个环中的一小段
3台服务器扩容到4台服务器时 命中原先概率为75%
100台服务器扩容增加一台服务器 继续命中的概率为99%
具体应用中 这个长度为2^32的一致性Hash环通常使用二叉树查找实现, Hash查找的过程是在二叉查找树中找不少于查找树的最小数值。
当然这个二叉树最右边椰子节点和最左边的椰子节点相连接, 构成环
但是还有一个小问题
新加入的节点Node3只使Node1收益了, 即一部分原来要访问Node1的数据要访问Node3(概率上为50%)
但是原先的Node0和Node2不受影响, 意味着Node0和Node2缓存数据量和压力是Node1和Node3的两倍
如果四个机器的性能一样, 那么这种结果显然不是我们需要的
计算机领域有句话: 计算机的任何问题都可以通过增加一个虚拟层来解决
做法是 将每台物理服务器虚拟为一组虚拟缓存服务器, 将虚拟服务器的Hash值放置在Hash环上, KEY在还上先
找到虚拟服务器节点,再得到物理服务器的信息
这样新加入服务器节点时, 是将一组虚拟节点加入环中, 如果虚拟节点的数组足够多,
这组虚拟节点蒋辉影响统一多数目的已经在环上存在的虚拟节点,这些已经存在的虚拟节点又对应不同的物理节点
这样最终新加一台缓存服务器, 将会较为均匀的影响原来集群中所有的服务器
6.4 数据存储服务器集群的伸缩性设计
和缓存服务器集群不同, 数据库存储服务器集群的伸缩性对数据的持久性和可用性提出了更高的要求
6.4.3 NoSQL数据库的伸缩性设计
NoSQL: Not Only SQL,表示NoSQL只是关系数据库的补充,而不是替代方案