从0开始学架构(高可用架构)
CAP理论
- 定义:在一个分布式系统(指互相连接并共享数据的节点集合)中,当涉及读写操作时,只能保证一致性(Consistence)、可用性(Availability)、分区容错性(Partition Tolerance)三者中的两个,另外一个必须被牺牲。
- 一致性:对某个指定的客户端来说,读操作保证能够返回最新的写操作结果
- 可用性:非故障的节点在合理的时间内返回合理的响应(不是错误和超时的响应)
- 分区容错性:当出现网络分区后,系统能够继续“履行职责”
实际应用中,必须选择P(分区容错性),因此只有AP、CP两种选择
CP(Consistency/Partition Tolerance)
- 为了保证一致性,当发生分区现象后,客户端请求到未收到最新数据的节点时,节点返回Error,即不满足可用性
AP(Availability/Partition Tolerance)
- 为了保证可用性,当发生分区现象后,客户端请求到未收到最新数据的节点时,节点返回当前持有的旧数据,因为该数据不是最新的,所以又不满足一致性
CAP理论细节
CAP细节阐述
CAP 关注的粒度是数据,而不是整个系统
- 一个系统会涉及到多种数据,不同的数据可以各自选择CP还是AP
- CAP 是忽略网络延迟的
正常运行情况下,不存在 CP 和 AP 的选择,可以同时满足 CA
- 架构设计的时候既要考虑分区发生时选择 CP 还是 AP,也要考虑分区没有发生时如何保证 CA
放弃并不等于什么都不做,需要为分区恢复后做准备
- 我们可以在分区期间进行一些操作,从而让分区故障解决后,系统能够重新达到 CA 的状态
ACID理论
Atomicity(原子性)
- 要么做,要么全不做
Consistency(一致性)
- 在事务开始之前和事务结束以后,数据库的完整性没有被破坏
Isolation(隔离性)
- 允许多个并发事务同时对数据进行读写和修改的能力
- 隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致
Durability(持久性)
- 事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失
BASE理论
- 核心思想是即使无法做到强一致性(CAP 的一致性就是强一致性),但可以采用适合的方式达到最终一致性
基本可用(Basically Available)
- 分布式系统在出现故障时,允许损失部分可用性,即保证核心可用
软状态(Soft State)
- 允许系统存在中间状态,而该中间状态不会影响系统整体可用性
- 这里的中间状态就是 CAP 理论中的数据不一致
最终一致性(Eventual Consistency)
- 系统中的所有数据副本经过一定时间后,最终能够达到一致的状态
- ACID 是数据库事务完整性的理论,CAP 是分布式系统设计理论,BASE 是 CAP 理论中 AP 方案的延伸
FMEA方法
- FMEA(Failure mode and effects analysis,故障模式与影响分析),是一种通过对系统范围内潜在的故障模式加以分析,并按照严重程度进行分类,以确定失效对于系统的最终影响的方法。
具体分析方法
- 给出初始的架构设计图
- 假设架构中某个部件发生故障
- 分析此故障对系统功能造成的影响
- 根据分析结果,判断架构是否需要进行优化
分析维度
- 功能点(指的是从用户角度来看的,而不是从系统各个模块功能点划分来看的)
- 故障模式(指的是系统会出现什么样的故障,包括故障点和故障形式,这里不需要给出故障原因)
- 故障影响(功能点具体会受到什么影响,需要尽量准确描述)
- 严重程度(严重程度 = 功能点重要程度 × 故障影响范围 × 功能点受损程度)
- 故障原因(不同原因的概率、检测手段、处理措施会不一样)
- 故障概率(高/中/低)
- 风险程度(即故障等级,风险程度 = 严重程度 × 故障概率)
- 已有措施(针对具体的故障原因,系统现在是否提供了某些措施来应对)
- 规避措施(为了降低故障发生概率而做的一些事情,技术或管理手段)
- 解决措施(为了能够解决问题而做的一些事情,一般都是技术手段)
- 后续规划(技术/管理手段,规避/解决措施)
- Xmind图
- 举例
存储高可用架构:双机架构
- 存储高可用方案的本质都是通过将数据复制到多个存储设备,通过数据冗余的方式来实现高可用
- 常见架构:主备、主从、主主
主备复制
架构关系
- 正常时:客户端-(读&写)->主机-(数据复制)->备机
- 主机不可用时:客户端-(读&写)->备机
- 优点:简单(客户端不感知备机、主备机仅需要数据复制)
- 缺点:备机硬件成本浪费、不可用时需要人工切换
主从复制
架构关系
- 客户端-(读&写)->主机-(数据复制)->从机
- 客户端-(读)->从机
优点
- 主机故障时,从机能继续提供读服务
- 从机提供读服务,发挥了硬件性能
缺点
- 客户端需要感知主从关系,增加复杂度
- 如果主从复制延迟比较大,会出现数据不一致问题
- 故障时仍需要人工干预
双机切换
互连式
- 指主备机直接建立状态传递的渠道(主->从/备)
- 通道的具体实现方式多样:网络连接、串口线
- 客户端只记录虚拟IP;或者同时记录主备IP,能连哪个就哪个
- 缺点:如果传递通道有问题,则从/备机会变成主机,造成有两个主机
中介式
- 在主备两者之外引入第三方中介,主备机都去连接中介,通过中介来传递状态信息
- 优点:连接管理更简单、状态决策更简单
- 缺点:中介自己如果不可用,则整个系统陷入双备状态
模拟式
- 备机模拟成一个客户端,向主机发起模拟的读写操作,根据读写操作的响应情况来判断主机的状态
- 优点:实现更加简单,因为省去了状态传递通道的建立和管理工作
- 缺点:模拟式读写操作获取的状态信息只有响应信息,没有互连式那样多样,基于有限的状态来做状态决策,可能出现偏差
主主复制
架构关系
- 客户端-(读&写)->主机A
- 客户端-(读&写)->主机B
- 主机A<-(数据复制)->主机B
存在问题
- 必须保证数据能够双向复制,而很多数据是不能双向复制的(例如自增ID,库存数)
存储高可用架构:集群和分区架构
数据集群
数据集中集群
架构关系
- 客户端-(读&写)->主机-(数据复制)->从/备机1、2……n
复杂度高
- 主机如何将数据复制给备机
- 备机如何检测主机状态
- 主机故障后,如何决定新的主机
数据分散集群
- 多个服务器组成一个集群,每台服务器都会负责存储一部分数据;同时,为了提升硬件利用率,每台服务器又会备份一部分数据(类似RAID)
- 均衡性
- 容错性
- 可扩展性
数据分区
- 数据分区指将数据按照一定的规则进行分区,不同分区分布在不同的地理位置上,每个分区存储一部分数据
数据量
- 数据量越大,分区规则会越复杂,考虑的情况也越多
分区规则
- 例如:洲际分区、国家分区、城市分区
复制规则
集中式
- 指存在一个总的备份中心,所有的分区都将数据备份到备份中心
优点
- 设计简单,各分区之间并无直接联系,可以做到互不影响
- 扩展容易
缺点
- 成本较高,需要建设一个独立的备份中心
互备式
- 指每个分区备份另外一个分区的数据
- 优点:成本低,直接利用已有的设备
缺点
- 设计比较复杂,各个分区除了要承担业务数据存储,还需要承担备份功能
- 扩展麻烦
独立式
- 指每个分区自己有独立的备份中心
优点
- 设计简单,各分区互不影响
- 扩展容易,新增加的分区只需要搭建自己的备份中心即可
缺点
- 成本高,每个分区需要独立的备份中心
计算高可用架构
- 计算高可用的本质是通过冗余更多计算机器来规避部分故障的风险
- 常见架构:主备、主从、集群
主备架构
架构关系
- 任务分配器-(计算任务)->主机
- 任务分配器-(计算任务,故障时人工切换)->备机
- 任务分配器将所有任务分配给主机,当主机不可用时,人工切换至备机
备机类型:冷备、温备
- 冷备:备机上的程序包和配置文件都准备好,但备机上的业务系统没有启动
- 温备:备机上的业务系统已经启动,只是不对外提供服务
- 优点:简单;缺点:人工切换
主从架构
架构关系
- 任务分配器-(计算任务A)->主机
- 任务分配器-(计算任务B)->从机
- 正常情况下,计算任务A分配给主机,计算任务B分配给从机;当主机故障时,人工将从机升级为主机,此时任务A&B均分配给新主机
- 优点:发挥从机硬件性能;缺点:需要任务分类,且任务分配会复杂一点
集群架构
对称集群
- 集群中每个服务器的角色都是一样的,都可以执行所有任务
具体设计
- 正常情况下,任务分配器按照一定分配算法将任务分配给不同的机器
- 当检测到某机器故障时,不再给它分配任务
- 当故障机器恢复正常后,重新分配任务
设计关键点
- 任务分配算法:随机、轮询
- 检测服务器状态:通过心跳来传递信息,包括服务器信息和任务信息
非对称集群
- 一台master,多台slaver。部分任务是 Master 服务器才能执行,部分任务是 Slave 服务器才能执行。
具体设计
- 集群会通过某种方式来区分不同服务器的角色(ZAB算法选举)
- 任务分配器将不同任务发送给不同服务器
- 若master故障,则从多台slaver中重新选举新的master;如果slaver故障,则只要剔除掉它即可
复杂点
- 任务分配策略更加复杂
- 角色分配策略实现比较复杂
业务高可用:异地多活
应用场景
- 异地就是指地理位置上不同的地方;多活就是指不同地理位置上的系统都能够提供业务服务。
- 代价:系统复杂度会发生质的提高;成本会上升。
架构模式
同城异区
- 定义:同一个城市的不同机房
- 优点:由于同城,逻辑上我们可以将它们看作同一个机房,这样的设计大大降低了复杂度,减少了异地多活的设计和实现复杂度及成本
- 不足:城市级别的灾难无法解决(例如新奥尔良大水灾)
跨城异地
- 存在问题:网络传输速度会显著降低;中间传输过程中不可控因素增加;造成的数据短时间内不一致
跨国异地
- 适用场景:为不同地区用户提供服务;只读类业务做多活
异地多活设计4大技巧
保证核心业务的异地多活
- 举例:登录功能比注册核心,而登录所需数据可同步至其它中心
保证核心数据的最终一致性
- 尽量减小异地多活机房的距离,搭建高速网络
- 尽量减少数据同步,只同步核心业务相关的数据
- 保证最终一致性,不保证实时一致性
采用多种手段同步数据
- 消息队列
二次读取
- 第一次读取本地,本地失败后第二次读取对端
存储系统同步
- MySQL 的主备复制、Redis 的 Cluster 功能等
回源读取
- 判断数据属于的中心,直接读它
重新生成数据
- 例如:session读取失败,则重新生成即可
- 只保证绝大部分用户的异地多活
异地多活设计4步走
业务分级
- 按照一定的标准将业务进行分级,挑选出核心的业务设计异地多活,降低方案整体复杂度和实现成本
- 评价维度:访问量大、核心业务、产生大量收入业务
数据分类
- 挑选出核心业务后,需要对核心业务相关的数据进一步分析,目的在于识别所有的数据及数据特征,这些数据特征会影响后面的方案设计
- 分析维度:数据量、唯一性、实时性、可丢失性、可恢复性
设计数据同步方案
存储系统同步
- 优点:使用简单
- 不足:无法针对业务数据特点做定制化的控制
消息队列同步
- 适合无事务性或者无时序性要求的数据
重复生成
- 数据不同步到异地机房,每个机房都可以生成数据。例如session,cookie
异常处理
多通道同步
- 采取多种方式来进行数据同步,例如存储系统+消息队列
- 一般情况下,两种通道即可,不然维护成本也很高
- 不能采用相同的网络连接,否则一旦网络故障,两个通道都同时故障
- 需要数据是可以重复覆盖的,即无论哪个通道先到哪个通道后到,最终结果是一样的
同步和访问结合
- 不能让数据库同步和接口访问都走同一条网络通道
- 数据有路由规则,可以根据数据来推断应该访问哪个机房的接口来读取数据
- 由于有同步通道,优先读取本地数据,本地数据无法读取到再通过接口去访问
日志记录
- 每个关键操作前后都记录相关一条日志,然后将日志保存在一个独立的地方,当故障恢复后,拿出日志跟数据进行对比,对数据进行修复
常用日志保存方式
- 服务器上保存日志
- 本地独立系统保存日志
- 日志异地保存
- 用户补偿
如何应对接口级的故障
典型表现
- 系统并没有宕机,网络也没有中断,但业务却出现问题(业务响应缓慢、访问超时或出现异常)
故障原因
- 内部原因:程序bug、慢SQL,程序逻辑不完善导致耗尽内存等
- 外部原因:黑客攻击(DDoS)、大量正常请求(双十一秒杀)
应对思想
- 优先保证核心业务和优先保证绝大部分用户
应对措施
降级
- 指系统将某些业务或者接口的功能降低,可以是只提供部分功能,也可以是完全停掉所有功能
降级方式
- 系统后门降级(优点:成本低。缺点:存在安全隐患、要一台台搞效率低)
- 独立降级系统
熔断
- 指的是当依赖的系统或服务出现异常故障时,停止访问该服务,而是直接报错返回
- 设计关键:阈值的设定。一般先根据分析确定阈值,然后上线观察效果,再进行调优。
- 与降级的区别:降级是服务提供方的操作(我不行了,只保证部分功能,或者直接给你返回个结果);而熔断则是服务消费方的操作(我依赖你,你不行了,我就不再调你,省的我自己被拖累)。
限流
- 限流是从系统访问压力的角度来应对故障的方式。只承受能够承受的访问请求,超过部分丢弃。
限流方式
- 基于请求限流,例如QPS。设计关键仍是阈值,一般采用压测分析,上线观察,调优。
- 基于资源限流,例如CPU使用率、线程数。设计关键也是如何选择资源以及对应的阈值。
排队
- 是限流的变种,它不丢弃请求,而是全部扔在队列里面,调度处理(若队列满了还是要丢弃的)。