可用性的定义
- 可用性是指当你需要它时,它就在那里,随时准备执行任务。
- 可用性建立在可靠性概念的基础上,增加了恢复的概念。
- 可用性和可靠性的区别。
可靠性关注“多久坏一次”,可用性关注“坏了多久能修好”此时能不能用。
| 对比维度 | 可靠性 | 可用性 |
|---|---|---|
| 核心定义 | 在指定条件下、指定时间内,系统不出现故障持续运行的能力。 | 在指定时间内,系统成功提供服务的时间占总时间的百分比。 |
| 关注焦点 | 关注故障的频率(容错性)和故障的严重性(数据损坏、计算错误)。 | 关注停机的时间(时长)和服务的连续性(只要能连上,哪怕功能降级也行)。 |
| 核心数学指标 | MTBF(平均故障间隔时间)。MTBF越长,可靠性越高。 | MTTR(平均修复时间),运行时间 / (运行时间 + 停机时间)。通常用“几个9”衡量(如99.99%)。 |
| 失败的定义 | 功能错误:返回了错误结果、数据丢失、系统崩溃、进程异常退出。 | 响应失败:请求超时、连接被拒、服务不可达(哪怕后台逻辑没错)。 |
| 修复的态度 | 必须根除缺陷,防止再次发生(严控Bug) | 允许故障发生,但必须快速恢复(靠冗余和重启) |
| 极端场景 | 高可靠低可用:银行核心账务系统。几乎不出错(可靠性极高),但每晚需要批量跑批,跑批期间暂停对外服务(可用性并非100%)。 | 低可靠高可用:电商秒杀系统。可能经常出现库存扣减逻辑Bug(可靠性一般),但通过负载均衡和熔断降级,保证页面永远能打开让用户下单(可用性极高)。 |
一般来说,金融/支付类优先保可靠性(钱不能错);互联网/ToC 应用优先保可用性(体验不能断)。
什么是以上提到的故障?
故障是失效的原因! 1. 故障可以是系统内部的、也可以是系统外部的。 2. 故障可以被预防、容忍、消除或预测,进而让系统对故障变得有弹性。 3. 对此,我们应该关心的是: 如何检测故障; 可能发生故障的频率; 故障发生后会有什么后果; 系统允许停止操作的时间; 什么时候故障或失效可以发生; 如何避免故障; 失效时需要什么类型的通知。- 什么是失效?
系统与其规格之间的偏差称为失效!可用性还包括系统修复(屏蔽)故障的能力。
1. 从而确保服务停机累计时间在指定的时间间隔内,不会超过设定的值。 2. 这个定义包含了可靠性(Reliability)、健壮性和任何其他涉及不能接受失效概念的质量属性(防护性、性能、安全性)。- 系统发生了故障不一定就失效了。
如果执行了包含故障的代码,但系统能够从故障中恢复,而没有任何可观察到的偏离行为,则认为没有失效。- 如何量化一个系统的可用性。
系统可用性需求的例子和可接受的系统停机时间的相关阀值,如下表,测量周期为90天和1年。| 可用性 | 停机时间/90天 | 停机时间/年 |
|---|---|---|
| 99.0% | 21h 36 min | 3天 15.6h |
| 99.9% | 2h 10min | 8h 0min 46s |
| 99.99% | 12min 58s | 52min 34s |
| 99.999% | 1min 18s | 5min 15s |
| 99.9999% | 8s | 32s |
注意:计划之内的停机时间不计入!
实现可用性的方法(如何实现可用性)
使用架构模式实现
架构模式描述特定上下文中反复出现的典型设计问题,并提供经过 验证的架构解决方案。最重要的可用性架构模式如下:
- 以冗余备份为中心:包括活动冗余(热备)、被动冗余(温备)、备份(冷备),
三者的主要区别:在于备份组件状态与活动组件状态的一致程度。
- 活动冗余(热备):
备份组件状态和活动组件状态高度一致。
因为备份组件与活动组件拥有相同的状态,所以,它可以在大约几毫秒的时间内接管故障组件。- 被动冗余(温备):
备份组件状态和活动组件状态周期性一致。
温备是在昂贵的热备和便宜的冷备之间寻求平衡。- 备份(冷备):
备份组件状态和活动组件状态不一致(发生故障后才一致)。
由于恢复性较差,平均修复时间较长,因此,这种模式不适合高可用需求的系统。冗余备份的好处:在出现故障时,只需要短暂延迟,系统就能继续正常运行。另一种选择是系统停止正常运行,或者完全停止运行,直到故障组件被修复。这种修复可能需要数小时或数天。
冗余备份的权衡:这些模式都需要增加额外的成本和复杂性。需要权衡成本和恢复时间,例如,热备成本最高,但恢复时间最短。
- 三模冗余
1. 采用三个相同的组件,每个组件 接收相同的输入,并将输出转发给投票逻辑,该逻辑检测三个输出的任何不一致。 2. 针对不一致情况报告故障,并决定使用哪个输出。 3. 此模式的不同实现是由所用决策规则决定的。典型的规则是采用多数原则或选择不同输出的平均值。 4. 当然,该模式也可能使用5个、19个或53个冗余组件。然而,多数情况3个就足够。- 断路器
1. 一个常用的可用性策略(方法)是重试。如果在调用服务时出现超时或故障,调用者只需不断尝试。 2. 断路器可以防止调用者尝试无数次去等待一个永远不会出现的响应。 3. 通过这种方式,当认为系统正在处理故障时,就会中断无穷无尽的重试。 4. 在断路器被“重置”之前,后续调用将立即返回,而不会进行服务请求。这就避免了无休止的无结果的重试,这种无休止的重试会导致调用者与失效的被调用者组件一样无用。 5. 这个问题特别是在分布式系统中尤其严重,调用者无休止的调用一个没有响应的组件,会引发调用者无法继续服务,从而会导致整个系统的失效级联。 6. 断路器与监听并恢复服务的软件结合,可以防止这个问题。- 进程对:此模式使用检查点和回滚。
- 正向错误恢复,此模式找到一个安全的、可能降级状态,以便操作继续向前。
使用可用性策略实现
可用性策略的目标:使系统能够防止或忍受系统故障,从而使系统交付的服务仍然符合其规格。以下这些可用性策略可以防止故障变成失效,或至少降低故障的影响并使修复成为可能。这些策略通常由软件基础设施(中间件)实现,也可通过自定义代码、通用框架实现。可用性策略有如下三大类:
- 故障监测
- 监视
实现监视系统的健康状态,通常需要从多个维度、多个层次持续采集信号,并基于规则或模型判断系统是否偏离正常状态。
a、健康状态监视的主要维度有:
| 维度 | 监视内容 | 示例 |
|---|---|---|
| 基础设施层 | CPU、内存、磁盘、网络、进程状态 | CPU使用率>90%、磁盘只读、OOM(out of Memery) |
| 应用服务层 | 服务是否存活、请求成功率、相应时间、线程池、连接池 | HTTP 500比例、DB连接耗尽 |
| 业务逻辑层 | 关键业务流程是否可正常完成 | 下单、支付 、登录成功率 |
| 依赖组件层 | 数据库、缓存、消息队列、第三方服务 | Redis连接失败、MQ积压0 |
| 部署与版本层 | 发布状态、配置变更、实例数量 | 新版本启动失败、配置错误 |
b、实现:
健康检查端点:服务主动暴露状态接口,由监控系统或负载均衡器定期调用。
常见端点设计:
/health/liveness:进程是否存活,只检查服务本身是否运行。
/health/readiness:服务是否准备好接收流量,检查依赖是否就绪。
/health/dependency:检查数据库、缓存、消息队列等依赖组件状态。
可被 Kubernetes、Nginx、Spring Boot Actuator、Consul 等直接集成。指标监控
常见指标类型:资源指标(CPU、内存、磁盘 I/O、网络吞吐);应用指标(QPS、响应时间 P99、错误率、线程池使用率。)业务指标(订单量、支付成功率、活跃用户数。)采集方式:Prometheus定期拉取 exporter 暴露的指标
日志监控与异常检测:日志是定位故障的重要数据源,通过实时分析日志可发现错误模式。
使用ELK、Loki、Splunk
等日志平台集中收集日志.对日志进行结构化解析,提取错误码、异常堆栈、关键事件。分布式追踪(Distributed Tracing):在微服务架构中,一次请求可能经过多个服务,需要追踪调用链定位故障点。
使用 OpenTelemetry、Jaeger、Zipkin 等,
为请求生成唯一 Trace ID。记录每个服务调用的耗时、返回码、异常信息。
可快速定位慢调用或失败调用发生在哪个服务。
ping/echo
在这种机制中,节点之间交换异步请求/响应消息对,用于确定通过相关网络路径的可达性和往返延迟。ping/echo和心跳之间的区别在于谁负责启动检查——时监视器还是组件本身。ping通常由系统监视器发送。心跳
参考:心跳机制的本质、基本模型及流程用于判断一个节点或服务是否仍然存活。这种故障检测机制在
系统监视器和被监视的进程进行周期性的消息交换。心跳机制适用场景:a、服务实例存活检测。b、分布式节点成员状态维护。c、长连接保活。
Nacos就内置了心跳机制:它支持临时实例(类似Eureka的客户端心跳上报)和持久实例(服务端主动发起TCP/HTTP探活)两种模式,机制更为灵活,能识别更细粒度的故障。
其他很多组件都内置了心跳机制:Eureka、Consul、ZooKeeper、etcd、Kubernetes (K8s)、RabbitMQ、Kafka、RocketMQ、Prometheus、Zabbix / Nagios / Icinga、Nginx / HAProxy、Keepalived、Istio / Envoy、**Spring Boot Actuator **、MQTT、等等、心跳检测的实现已经深度集成到了现代软件架构的各个层面。时间戳
时间戳机制并不是一个单一的技术,而是一类利用时间信息来协调、决策和恢复的设计模式
它通过提供轻量级的顺序依据、超时判断和冲突解决基础,减少系统对全局同步和强一致协调的依赖,从而在故障和分区时保持服务可用时间戳用来检测不正确的时间序列,主要用于分布式消息传递系统。心跳检测是故障检测的基础,而心跳检测高度依赖时间戳。条件监视
它不同于心跳机制只判断“节点是否活着”,而是持续检查系统
是否满足某些预设条件、阈值或不变量。监视系统内部状态是否处于可接受范围。条件监视回答的问题是:系统当前的状态是否满足正常运行所需的条件?这些条件可以是:资源条件:CPU、内存、磁盘、连接池、队列长度。 性能条件:响应时间、吞吐量、错误率。 状态条件:主从角色、副本数量、配置版本。 数据条件:数据是否完整、一致、未损坏。 依赖条件:数据库、缓存、消息队列是否可用条件监视的本质是:将系统健康状态转化为一组可计算、可比较的布尔条件或数值指标,并持续评估这些条件。 例如: CPU 使用率 < 80% 磁盘剩余空间 > 10% 主从复制延迟 < 5 秒 数据块校验和 == 存储的校验和 副本数量 >= 2一旦条件为假,就触发相应动作。校验和正是把“数据是否完好”这一条件,转化为一个可比较的数值。
条件监视的一个例子:校验和则是条件监视中用于判断数据完整性的一种经典技术。
数据在存储、传输、内存中可能发生静默损坏: 磁盘坏道、位翻转; 网络传输错误; 内存软错误; 软件 Bug 写坏数据; 消息在队列中损坏。校验和通过以下方式实现条件监视:
数据生成或写入时,计算一个校验和,并与数据一起存储或发送。 读取或接收时,重新计算校验和,并与保存的值比较。 如果两者相等,说明数据在概率上完好;如果不等,说明数据已损坏。 触发恢复动作:重试、从副本读取、修复、隔离、告警、故障转移因此,校验和是一种数据完整性条件监视
完整性检查
完整性检查回答的问题是:这个操作的输出,在当前上下文中,是否有效?是否合理?检查范围:函数或服务的返回值; 数据库写入后的状态; 消息处理后的结果; 网络响应的内容; 配置加载后的参数; 状态机转换后的状态。检查内容:a、有效性检查:有效性关注输出是否满足形式化约束。 类型正确:返回值是预期的数据类型。 范围合法:数值在允许区间内,如年龄 0~150、金额非负。 格式正确:日期、邮箱、UUID、JSON Schema 符合规范。 非空/非缺失:关键字段不为 null、空字符串或空集合。 唯一性:ID、主键不重复。 引用完整性:外键指向存在的记录。 枚举合法:状态值属于预定义集合。 b、合理性检查:合理性关注输出是否与上下文、业务逻辑和常识一致。 业务规则:转账后总金额不变;订单总价等于明细之和。 逻辑一致性:状态转换合法,如“已支付”不能直接变“已发货”而跳过“待发货”。 时间合理性:时间戳单调递增,事件时间不早于创建时间。 统计合理性:数值突变在历史波动范围内,如温度从 20℃ 跳到 200℃。 交叉验证:多个字段相互印证,如开始时间 ≤ 结束时间。 资源约束:分配的内存不超过配额,库存不减为负。 冗余计算比较:两个独立实现计算同一结果并比较。
完整性检查与校验和、心跳的区别
| 对比项 | 心跳 | 校验和 | 完整性检查 |
|---|---|---|---|
| 目标 | 节点是否存活 | 数据位是否损坏 | 输出是否有效合理 |
| 层次 | 进程/网络 | 位级/字节级 | 语义/业务级 |
| 检查对象 | 信号 | 字节序列 | 返回值、状态、业务规则 |
| 错误类型 | 节点故障 | 传输/存储损坏 | 计算错误、逻辑缺陷、数据污染 |
| 典型技术 | 超时、租约 | CRC、哈希 | 断言、规则引擎、冗余计算 |
| 恢复 | 重选、切流 | 重传、修复 | 重试、回滚、切换、隔离 |
- 投票
- 异常检测
- 自检
故障修复
1、 准备和修复
a. 冗余备份冗余备份指的是一种配置。在这种配置中,如果组件发生故障,一个或多个备份组件可以介入并接管工作。备份可分为热备、温备、冷备三种,区别在于:接管时备份组件的更新程度。见上方架构模式
b. 回滚回滚运行系统在检测到故障时恢复到以前已知的良好状态(成为回滚行),该策略通常与冗余备份策略结合使用。回滚取决于正在回滚的组件是否可以使用先前良好状态(检查的)的副本。检查的可以存储在固定位置,定期更新(或在处理过程中方便时更新 或 在重要的时间点(例如复杂操作完成时)更新)
c. 异常处理一旦检测到异常,系统将以某种方式处理它。最简单的办法就是直接崩溃(从可用性、易用性、可测试性的角度来看,这是一个不好的办法。)异常处理会返回错误码、异常名称、异常产生的原因等
d. 软件升级待补充
e.重试使用重试的前提:导致失效的故障时暂时的,并且重试操作可能会成功。它常被用于网络和服务器集群中, 在这些地方故障时预料之中的,也是很常见的。注意! 应该限制重试的次数!避免发生的故障时永久的以造成无穷无尽的重试。
f.故障忽略当确定来源的消息时虚假时,就可以忽略故障。
g.柔性降级在组件出现故障的情况下保持最关键的系统功能,而放弃不太关键的功能这是在单个组件故障会降低系统功能性,但不会导致整个系统失效的情况下完成的。
h.重新配置重新配置试图通过将职责重新分配给(可能受限的)仍在运行的资源或组件,同时,尽可能多的维持功能,从而重故障中恢复。
2、重入
a.影子系统以“影子模式”操作先前失效或在线升级的组件一段预定义时间。在此期间,可以监视其行为的正确性,并以增量方式重新填充其状态。
b.状态再同步待补充
c.逐级重启改变重启动组件的颗粒度****和最小化服务影响级别从故障中恢复。。通俗讲就是:分多步启动,每次增加一些功能,直至功能全部启动完成。
d.不间断转发待同步故障预防
1、 从服务中移除组件暂时将组件置于停止服务状态,以减少潜在的系统失效。例如,在故障积累达到影响服务的级别之前,选取系统的一个组件并重置,以消除潜在的故障(如内存泄漏、碎片或未受保护缓存中的软错误)这种策略也成为软件再生或治疗性重启每天重启电脑,就是一种从服务中移除组件的一个实例
2、 事务待补充
3、 预测模型待补充
4、异常预防待补充
5、增加能力集程序的能力集是指程序鞥能够“胜任操作”的情况集。例如:访问公共资源的组件在发现访问被阻塞时:第一种处理:直接排除异常。第二种处理:增加能力集——等待访问 或者 立即返回并指示它将在可以访问时完成相关操作。