高可用架构基础:可用性等级、冗余设计与故障隔离

做高可用这么多年,我最大的感触是:很多团队一上来就谈“我们要上多活”“做单元化”,结果连可用性到底该怎么量化、冗余到底要解决什么问题都没搞清楚。这章咱们就扎扎实实地把三个最基础的概念捋清楚——可用性等级、冗余设计思想、故障域与隔离。

什么是可用性?从数字说起

可用性说白了就是一个公式:系统正常服务的时间占比。假设一年8760小时,如果只宕机8.76小时,可用性就是99.9%。这里我习惯用「9」的个数来记——3个9对应年宕机8.76小时,4个9对应52.56分钟,5个9对应5.26分钟。

核心理解:可用性数字不是拍脑袋定的,它直接决定你要花多少钱买机器、做多深的冗余。

不同的可用性等级对应的停机容忍尺度差别很大:

可用性等级 年停机时间 月停机时间 典型场景
99% 87.6小时 7.3小时 内部工具、非关键业务
99.9% 8.76小时 43.8分钟 大多数SaaS产品
99.99% 52.56分钟 4.38分钟 金融交易、实时通信
99.999% 5.26分钟 26.3秒 电信、关键基础设施

我曾经遇到一个项目,甲方要求“99.99%”,结果他们说只准备了两台机器做主备切换——切换时间动辄十几分钟,根本跑不到4个9。你想想看,如果把设备故障、网络抖动、版本发布都算进去,99.99%其实是非常苛刻的目标。

为什么水印服务需要高可用?

水印服务听起来简单——给图片或视频打上一个标记。但线上场景里,它往往是生产链路中的关键环节。我记得有一次,一个客户的水印服务部署在单机上,磁盘挂了,整整6个小时所有新生成的素材都没有水印,最后被甲方罚款二十万。

我自己也踩过坑。早期做视频转码系统,水印节点只配了一台,半夜硬件宕机,运维值班人员没看告警,第二天才发现一堆任务失败。从那以后我再也不敢对非关键路径的服务掉以轻心——水印服务一旦不可用,下游数据就可能出现合规风险。

冗余设计思想:把鸡蛋放在多个篮子里

冗余,说白了就是用多个副本对抗单点失效。但冗余不是简单复制,你得想清楚两个问题:冗余的方式有哪些?冗余之后怎么保持一致?

常见的冗余模式有这三种:

  • 主备(Active-Standby):一台干活,一台等着。切换需要时间,但实现简单。
  • 双活(Active-Active):两台同时处理请求,故障时流量重新分配。资源利用率高,但需要解决数据一致性问题。
  • 多活(Multi-Active):跨机房甚至跨地域的多个副本同时服务。最灵活,但网络延迟和一致性成本最高。
冗余模式 故障切换时间 资源利用率 一致性复杂度 适用场景
主备 秒级~分钟级 约50% 低 低成本、容忍短暂中断
双活 毫秒级 约80% 中 对RTO要求高的核心服务
多活 秒级(跨地域) 约90% 高 异地容灾、全球服务

我的习惯:对水印这种无状态服务(只处理文件,不保存结果),双活是最划算的选择。因为不用操心数据同步,主要搞定负载均衡和健康检查就行。

故障域与隔离:不要让一颗老鼠屎坏了一锅粥

冗余能解决单点故障,但如果两个副本共享同一个电源、同一条网络,那一个故障就能干掉所有副本。这就引出了一个关键概念——故障域。

故障域是一个物理或逻辑边界,边界内的组件发生故障时,边界外的组件不受影响。比如一台服务器是一个故障域,一个机柜、一个交换机、一个机房也都是不同粒度的故障域。

隔离就是把不同冗余副本放到不同的故障域里。我之前见过一个线上事故:两个节点的网卡连接到同一台ToR交换机,交换机电源爆炸,两个节点同时失联,服务直接挂掉。当时负责架构的同事懊恼地说:“谁想到交换机会炸呢?”但这就是故障域没设计好——两个副本应该分散到不同机柜、不同交换机。

我曾经踩过的坑:第一次做高可用,把主备两台机器放在同一个机架,还用了同一路PDU。机房夏天跳闸,两台机器一起断电,故障转移完全无效。那次之后我规定:任何服务的主备或双活节点,必须跨机架、跨PDU。

故障域的粒度要根据你的成本和服务等级来定。对水印服务来说,至少要做到:

  • 同机房内跨机架(应对机架级故障)
  • 同城跨机房(应对机房级故障,比如空调漏水、网络割接)
  • 极端场景下可以考虑异地(应对城市级灾害)

一张图看懂高可用基础概念

下面这张图把可用性等级、冗余设计、故障域与隔离的关系串起来了。水印服务的可用性目标决定了你选多少个9,而9的个数反过来决定你要做多深的冗余、多大粒度的故障隔离。

高可用架构基础概念关系图 高可用架构基础 可用性等级 冗余设计 故障域与隔离 99.9% 99.99% 99.999% 主备 双活 多活 跨机架 跨机房 异地 设计核心逻辑 1. 根据水印服务的业务重要性选择可用性等级(99.9%还是99.99%) 2. 由可用性目标反推冗余模式(主备/双活/多活) 3. 把冗余副本放在不同的故障域内(跨机架→跨机房→异地)

实战中的避坑指南

小技巧:在设计冗余时,可以用一个简单的Python函数快速估算不同可用性等级下的允许中断时长,辅助决策:

def downtime_per_year(nines):
    return 365 * 24 * 60 * 60 * (1 - nines/100)

print(f"99.9% = {downtime_per_year(99.9):.0f}秒")
print(f"99.99% = {downtime_per_year(99.99):.0f}秒")

特别提醒:故障域隔离不是有了就万事大吉。我见过一个团队把双活节点放在两个机架,但两个机架共用同一个列头柜电源——列头柜一跳闸,两个节点一起跪。设计完成后一定要物理走查,确保每个故障域真的隔离了共享资源。

好了,这一章的基础概念打牢了,后面我们讲具体架构的时候才能心里有数。记住:先定可用性目标,再选冗余模式,最后用故障域隔离把风险分散开。这三步走稳了,高可用架构的根就扎实了。