在做运维和架构设计的这些年里,我发现一个特别有意思的现象:很多同学对“几个九”这个概念倒背如流,但你真问他“99.9% 可用性对应一年能停多久”,他得现拿计算器按。更有意思的是,按出来之后,还经常把“停机时间”和“不可用时长”搞混,导致容量评估和故障响应策略从一开始就跑偏。
这篇文章我就把这笔账彻底算清楚。你不光能拿到一份可以直接抄作业的年、月、周、天停机时间对照表,我还会把背后的计算公式、监控落地方式、错误预算应用,以及那些“看着可用性很高、实际一故障就穿帮”的典型坑都翻出来讲一遍。这篇东西适合运维工程师、后端开发、SRE、架构师,以及所有需要跟 SLA 数字打交道的人。
1. 可用性指标到底在衡量什么
可用性这个指标,听起来简单,但它的定义在实际落地时特别容易产生歧义。我们通常说的“可用性 = 正常运行时间 / 总时间”,这个公式本身没毛病,但问题是:什么叫“正常运行”?什么叫“总时间”?
我先说几个常见误区。
第一个误区:把“总时间”理解成“工作日的 9 到 18 点”。有些内部系统的 SLA 确实是按业务时段来算的,但对大多数面向外部用户的系统,总时间就是全年 365 天、每天 24 小时。你在凌晨三点升级挂掉的五分钟,一样要算进停机时间里。
第二个误区:把“正常运行”理解成“进程没退出”。进程活着但接口超时、数据库连接池打满、消息堆积不消费,这些对于用户来说都是不可用。所以更严谨的可用性定义应该基于“请求成功率”:在一段时间内,成功响应用户请求的比例是多少。
第三个误区:混淆“单次故障时长”和“年度累计停机时长”。99.9% 可用性意味着一年累计停机不超过 8.77 小时,但这不意味着你可以一次故障停 8 小时。如果你的错误预算(Error Budget)是一个月大约 43.8 分钟,月初就一口气用完了,后面就得冻结发版,这种管理机制才是可用性指标真正的价值所在。
我在实际项目中,一般用这样一个口径来统计:每秒钟统计请求总数和失败数,按分钟聚合成功率,然后当月累计。这个口径比较符合 SRE 实践里的 SLI/SLO 思路。稍后我会在监控章节详细说这块怎么落地。
2. 从 90% 到 99.999%:各等级停机时间精确对照
先给出一张可以直接截图保存的对照表。这张表我按“2 个 9”到“6 个 9”做了年、月、周、天的精确数字。月我按 30 天算,周按 7 天算,天就是 24 小时。注意“月”这里不同月份天数不同,实际误差会有一两天,但做预算规划用 30 天足够。
| 可用性等级 | 年停机时间 | 月停机时间(30天) | 周停机时间 | 天停机时间 |
|---|---|---|---|---|
| 90%(1个9) | 36.5 天 | 3 天 | 16.8 小时 | 2.4 小时 |
| 95% | 18.25 天 | 1.5 天 | 8.4 小时 | 1.2 小时 |
| 97% | 10.95 天 | 21.6 小时 | 5.04 小时 | 43.2 分钟 |
| 98% | 7.3 天 | 14.4 小时 | 3.36 小时 | 28.8 分钟 |
| 99%(2个9) | 3.65 天 | 7.2 小时 | 1.68 小时 | 14.4 分钟 |
| 99.5% | 1.83 天 | 3.6 小时 | 50.4 分钟 | 7.2 分钟 |
| 99.9%(3个9) | 8.77 小时 | 43.8 分钟 | 10.08 分钟 | 1.44 分钟 |
| 99.95% | 4.38 小时 | 21.9 分钟 | 5.04 分钟 | 43.2 秒 |
| 99.99%(4个9) | 52.6 分钟 | 4.38 分钟 | 1.01 分钟 | 8.64 秒 |
| 99.995% | 26.3 分钟 | 2.19 分钟 | 30.24 秒 | 4.32 秒 |
| 99.999%(5个9) | 5.26 分钟 | 26.3 秒 | 6.05 秒 | 0.864 秒 |
| 99.9999%(6个9) | 31.5 秒 | 2.63 秒 | 0.6 秒 | 0.0864 秒 |
这张表咋看数据差异巨大,仔细一分析全是细节:从 99% 到 99.9%,年停机时间从 3.65 天骤降到 8.77 小时,差了整整 10 倍。从 99.9% 到 99.99% 再降 10 倍,变成 52.6 分钟。每往上提一个“9”,容错空间就断崖式缩小。
我举个具体场景:假设你有个核心支付系统,对外承诺 99.99% 可用性,那全年只允许挂 52.6 分钟。这 52.6 分钟里,还得包括你发版本导致的短暂连接断开、数据库主从切换的那几十秒、甚至机房网络抖动的那几秒。你想想,一个 CDN 边缘节点故障 5 分钟,可能这个季度预算就没了。
所以这也是为什么很多大厂对外敢承诺 99.99%,但内部实际以 99.95% 为目标来设计系统。留出一倍的安全余量,否则任何一个不可控的小故障都会直接击穿 SLO。
3. 计算公式与推算逻辑
这些数字不是背下来的,你得知道是怎么算的。公式不复杂,小学数学水平,但逻辑值得掰扯清楚。
年停机时间 = 365 × 24 × 60 × (1 - 可用性) ,单位是分钟。
以 99.9% 为例:365 × 24 × 60 = 525600 分钟,525600 × 0.001 = 525.6 分钟 = 8.76 小时。这里跟表里的 8.77 小时有 0.01 的舍入误差,因为 8.76 小时其实更精确,我表中统一保留了常见工程口径。
月停机时间 = 30 × 24 × 60 × (1 - 可用性) ,单位是分钟。30 × 1440 = 43200 分钟,43200 × 0.001 = 43.2 分钟。注意不能简单地把年停机时间除以 12,因为一个月的时长不等于年的十二分之一精确值,但对于粗估,8.77 × 60 / 12 ≈ 43.85 分钟,差距也不大。
周停机时间 = 7 × 24 × 60 × (1 - 可用性) ,单位是分钟。7 × 1440 = 10080 分钟,10080 × 0.001 = 10.08 分钟。
天停机时间 = 24 × 60 × (1 - 可用性) ,单位是分钟。1440 × 0.001 = 1.44 分钟 = 86.4 秒。
这里我想多说一句:为什么单位要用分钟,而不是小时或秒?因为我们在做告警阈值设计时,一般以分钟为粒度来配置。比如 99.99% 的月度错误预算是 4.38 分钟,如果你的监控数据显示当前 30 分钟内累计故障已经超过 4.38 分钟,你就知道这个月 SLO 已经守不住了,需要立刻启动应急响应。
反过来,你也可以根据期望的单次故障时长来反推系统需要几个九。比如你希望单次故障 30 分钟内必须恢复,全年这样的故障最多发生 2 次,那你需要的年停机时间是 60 分钟,对应可用性就是 60 / 525600 = 0.999885,约等于 99.99%。这个方法在系统设计阶段特别有用。
4. 不同“九”背后的高可用架构要求
说句实在话,光背住数字没意义,关键是要知道不同等级对应什么样的架构投入。我根据自己的实操经验,把几个典型档位的“待遇”梳理一下,大家评估系统设计方案时可以直接对标。
4.1 99%(两个九):适合内部工具和低关键业务,基础设施冗余即可
两个九是很多内部管理系统的及格线。这类系统一年挂 3.65 天,看起来好像挺多,但对于内部员工使用的报表系统、工单系统,其实是可以接受的。架构上不需要太复杂:应用多副本部署,数据库用主从热备,备份策略保证可以快速恢复,就差不多了。一年 3.65 天的停机预算,分摊到每个月约 7.2 小时,足够你从容应对常规故障了。
但这里有个容易翻车的地方:即使目标只是 99%,也不意味着可以没有任何监控。我见过不少内部系统“裸奔”,挂了两天没人发现,那可用性可能连 95% 都不到。所以哪怕你有 3 天多的容错,基本的探活告警还是必须配置。
4.2 99.9%(三个九):生产级系统的基本线,必须做自动故障转移
99.9% 是大多数对外业务系统的基本线,年停机 8.77 小时看着不少,但拆到月只有 43.8 分钟。这意味着大部分故障必须在几分钟内完成自动恢复,不能等人去手动查日志、重启服务。
我之前负责过一个订单系统,目标就是 99.9%。当时架构上的核心改造就三条:一是应用服务全部多活部署,单节点宕机自动摘除流量;二是数据库做了主从自动切换,主库出问题能在 30 秒左右完成切换;三是所有依赖的外部接口都配置了超时和降级策略。这三板斧落地之后,系统才勉强兜住了 3 个九的底线。
4.3 99.99%(四个九):金融、交易类场景,需要单元化和多活
四个九意味着全年只允许挂 52.6 分钟。这时候光靠单机房多副本已经不够了,因为机房级别的故障(断电、光缆被挖断)就能让你一次性消耗掉全年预算。
要做到 99.99%,你至少需要同城双活或者异地多活的架构能力。流量可以在两个机房之间切换,任何一个机房整体故障,另一个机房能在分钟级接管全部流量。数据库层面,要么做双主同步,要么做基于日志的实时同步,加上数据校验和回补机制。这部分的复杂度和成本,比 3 个九高出一截。
我参与过的一个支付类项目,就做了同城双机房部署。平时两边各承担一半流量,配置了全局负载均衡,每 5 秒做一次健康检查。真发生机房级故障时,DNS 切换加上连接池重建,整体恢复时间控制在 2 到 3 分钟以内。但如果要求全年 52.6 分钟停机,意味着这种机房故障最多只能出现十几次,才有余量处理其他意外。
4.4 99.999%(五个九):极致场景,必须容忍任意单点失效
五个九,年停机 5.26 分钟,这是绝大多数企业难以达到的级别。那不是靠“高可用架构”能解决的,而是要从根本上消灭“不可用窗口”。
这种级别的系统,通常要求做到以下几点:全链路冗余无单点,包括网络设备、光缆、供电线路;应用层要做到滚动发布不中断;数据库层面通常是分布式数据库,支持多副本强一致,节点故障自动完成选主;更关键的是,要有常态化的故障演练机制,确保所有自动化切换流程真的可用。
说句实在话,大部分系统声称的 99.999% 都是统计口径上算出来的,实际架构上未必真的支撑得住。真拿故障注入去演练,很多系统撑不过第一轮。但目标定高一点,架构上的抗风险能力确实会更强。
5. 监控告警与错误预算的计算方式
前面聊了这么多架构层面的东西,现在落到监控实操。没有正确的监控,你根本不知道自己当前可用性是多少,更别提决策了。
5.1 SLI 怎么选
SLI(Service Level Indicator)是可用性计算的基础指标。最常见的做法是用“请求成功率”:SLI = 成功请求数 / 总请求数。这个口径的难点在于“成功”的定义,HTTP 200 算成功,那 404 算不算?如果用户访问一个不存在的页面,是否计入故障?
我的做法是把 4xx 排除在外,只统计 5xx、超时和连接失败作为失败请求。因为 4xx 通常是客户端问题,不是系统不可用。同时,对于异步消费类的任务(比如消息处理),成功与否要看消息是否被成功消费,这个指标得单独统计,不能和 HTTP 接口混在一起。
还有一类系统是纯后台离线计算的,根本没有对外请求,这种怎么算可用性?可以用“作业成功率”,即单位时间内成功完成的定时任务比例。比如每天有 1000 个离线脚本任务,只要有一个任务失败重试后仍失败,这一天就可能需要扣减可用性。
5.2 错误预算怎么算
错误预算 = 1 - SLO。比如你定的是月度 99.9%,那一个月(43200 分钟)里的错误预算就是 43200 × 0.001 = 43.2 分钟。
实际落地时,我一般会做两张表:一张是实时累计不可用时长,另一张是剩余错误预算。每天用定时任务计算,一旦消耗超过 70%,就触发告警;超过 100%,就要进入“发布冻结”状态,除了紧急修复,不允许任何变更上线。这个机制虽然听起来有点“无情”,但它是保证可用性最有效的手段之一。
5.3 用 Prometheus 计算可用性
如果你用的是 Prometheus,可以这样定义一个可用性指标:
# 以 5 分钟为窗口,统计请求成功率 sum(rate(http_requests_total{code!~"4.."}[5m])) / sum(rate(http_requests_total[5m]))这个表达式会得到一个 0 到 1 之间的数,乘以 100 就是百分比。但要算累计可用性,还要按时间加权。我一般用 recording rule 先把每分钟的成功率算出来存起来,再用avg_over_time算最近 30 天的平均值。
groups: - name: sli.rules interval: 1m rules: - record: job:sla_success_rate:rate5m expr: | sum(rate(http_requests_total{code!~"4.."}[5m])) / sum(rate(http_requests_total[5m]))这里有个容易踩的坑:如果某个时间窗口内完全没有请求,rate的结果是 0,会导致成功率变成 0 或者 NaN,直接拉低你的可用性数据。解决办法是加一个or on() vector(1),把无流量的窗口视为成功:
( sum(rate(http_requests_total{code!~"4.."}[5m])) / sum(rate(http_requests_total[5m])) ) or on() vector(1)这个细节我之前没注意,结果团队排查了大半天,发现不是系统故障,是凌晨低峰期没有流量导致监控把空窗口算成了不可用。
5.4 告警阈值如何从可用性推导
告警阈值的设计也要跟可用性挂钩。比如你的 SLO 是 99.95%,月度错误预算是 21.9 分钟。如果按 10 分钟的检测窗口看,10 分钟里允许的不可用时长是 30 秒。那告警阈值可以设为:最近 10 分钟的成功率低于 99.5% 时触发 Warning;低于 99% 触发 Critical。
你要知道,按这个逻辑设置的告警,才真正跟业务承诺挂钩。不是随便拍脑袋定一个“CPU 超过 80% 就报警”,那个是资源告警,不是可用性告警。两种告警要分开配,用途完全不同。
6. 可用性计算中的隐藏陷阱与避坑清单
这块是全文含金量最高的部分。这些坑,我在不同团队里反复见过,你看看自己的系统有没有中招。
6.1 把“健康检查通过”当成“可用”
很多系统的可用性监控就是探活 URL,比如每秒 curl 一下首页,能返回 200 就认为系统可用。问题是:首页返回 200 时,数据库可能已经被打满,订单接口可能大面积 5xx。这种探活方式只能证明“服务进程活着”,跟用户的真实体验差了十万八千里。
建议:探活只能作为基础设施层的最低保障。真正常用的可用性口径必须是用户实际请求的采样结果,也就是从流量入口或业务日志里统计真实请求的成功率。
6.2 忽略“人为窗口”和“计划内维护”
这是最容易引起商务纠纷的一个点。你在合同里写 99.99%,结果每个月固定停 10 分钟做维护,一年下来计划内停机 120 分钟,远超 52.6 分钟的预算。这时候客户拿数据来找你,你怎么解释?
我的建议是:要么把计划内维护明确排除在 SLA 统计之外,但前提是提前公告,并且提供无损变更方案;要么就把计划内维护也计入停机时间,逼着自己做滚动升级,这才是高可用系统的正确姿态。
6.3 数据库“主从切换”期间的不可用
很多数据库切换方案表面上是“秒级”,但实际执行时会发现:切换前三分钟可能已经开始出现故障,连接池里堆积了大量请求;切换后还需要等待数据补齐、缓存预热,这些时间都没算进“停机时间”里。
实操中我遇到过一次 MySQL 主从切换,从故障发生到服务完全恢复,中间经历了 15 分钟,但监控面板上记录的“切换耗时”只有 30 秒。差距在哪?监控记录的是从“执行切换命令”到“主库可用”的间隔,而用户感受到的是从“第一条报错”到“请求完全恢复正常”的间隔。
正确做法:把故障检测时间 + 切换执行时间 + 依赖恢复时间 + 流量重放时间都计算在内。不然你以为自己 99.99%,实际可能也就 99.9%。
6.4 依赖了“外部强依赖”,却只统计自己的指标
你的系统可用性再高,如果强依赖了一个第三方接口,那个接口一抖,你的成功率照样崩。很多团队只统计自身服务的请求成功率,没有把外部依赖的失败折算进来,导致监控数据漂漂亮亮,客户反馈却不间断。
建议:在统计 SLI 时,内外部接口分开统计,然后做加权。外部依赖的失败应该像“内部故障”一样,实时反映到可用性大盘上。
6.5 忘记“瞬间并发尖峰”对成功率的影响
有些系统平时可用性 99.99%,一到秒杀、大促就崩。因为高并发下的失败率和平时的失败率完全不是一个量级。你按全天累计算,秒杀那几分钟的失败率可能只占总请求的 0.01%,神不知鬼不觉地就过去了,但用户的体感是已经不可用了。
处理方式:统计可用性时,可以另外加一个“峰值窗口可用性”指标,比如在每分钟请求量超过平时均值 5 倍时,单独追踪该分钟的成功率。这样大促质量复盘时才有据可依。
7. 常见问题速查表
最后给大家整理一个速查表,方便日常工作中快速定位问题。
| 常见问题 | 可能原因 | 排查方法 |
|---|---|---|
| 监控显示可用性 99.99%,但客户投诉打不开 | 健康检查和用户真实请求不一致 | 对比探活与真实请求成功率 |
| 可用性比预期低很多 | 统计口径包含 4xx 错误 | 排除客户端错误,只统计 5xx 和超时 |
| 凌晨时段可用性突降 | 空窗口被当成不可用 | 加or on() vector(1)处理无流量 |
| 合同 SLA 达标但客户不认 | 计划内维护未排除或未公告 | 明确统计口径,提前公告维护窗口 |
| 数据库切换后可用性仍跌 | 故障检测和恢复时长未统计 | 从第一条报错开始计时,而不是从切换命令开始 |
| 错误预算总是提前耗尽 | 告警阈值过高,故障发现滞后 | 缩短检测窗口,设置分级告警 |
| 外部接口抖动拖垮整体可用性 | 缺少依赖降级策略 | 增加熔断器、超时控制和降级开关 |
| 大促期间成功率波动异常 | 峰值流量冲击,限流失效 | 压测验证限流阈值,设置独立峰值监控 |
8. 实际案例:一个 99.95% 目标系统的整改过程
说一个我经手的实际案例,帮助你把前面的理论串起来。
这个系统是一个面向客户的订单查询服务,当时对外承诺的 SLA 是 99.95%。但从监控看,实际可用性只有 99.7% 左右,年停机时间远超预算。排查下来发现三个主要问题:
一是探活只看进程是否存活,不校验数据库连接,导致数据库出问题时探活依然通过。整改方式是引入一个内部检测接口,该接口会实际查询一次数据库,并检查关键依赖的响应时间,超过 200ms 即视为异常。
二是数据库切换依赖人工确认,从发现故障到切换完成平均要 25 分钟。整改后加装自动健康检查,连续 3 次检测失败就触发自动切换,切换时间从 25 分钟压缩到 1 分钟以内。
三是没有熔断机制,第三方地图服务一慢,接口响应时间飙到 5 秒以上,前端大量超时。整改后对第三方调用加装熔断器和降级策略,第三方响应超过 500ms 直接走缓存兜底。
整改完成后,系统可用性从 99.7% 提升到了 99.95% 以上,月度错误预算从月中的 60% 消耗降到了月底的 30% 左右。整个团队最大的感受是:不是某个单点改动有多神奇,而是把 SLO 指标从“只在汇报 PPT 里出现”变成了“指导具体架构和运维决策的指挥棒”。
9. 个人实操体感与长期建议
做了这么多年可用性治理,我最大的体感是:可用性这个指标,最难的其实不是技术,而是坚持“用数据说话”的原则。
团队里常常有这种争论:这次故障只影响了 3 个用户,要不要算进停机时间?某个接口超时了但重试成功了,算不算不可用?这种时候,没有一套冻结的统计口径,每次都是“看情况”,SLO 就名存实亡了。建议把统计口径写入团队的故障等级定义文档里,并且每季度评审一次。
还有一个经常被忽略的动作:每次故障复盘后,不只是写报告,而是要把新的检查项固化到监控告警和发布检查清单里。否则同一个坑,半年后换个同学又能踩一次。
最后分享一个实用的预算分配建议:不要把全年可用性预算看成一个整体,而是拆成月度、甚至每周的粒度。按周来算的话,99.95% 的周错误预算是 5.04 分钟,一旦某周故障超过这个数,下周要么加人保障,要么主动减少变更。这种短周期复盘机制,比年底对着年度数字后悔要有效得多。
可用性治理这条路没有终点,但只要你把数字算明白、把指标管起来、把监控做到位,系统会一天比一天皮实。