高可用架构基础:单点故障、冗余设计、负载均衡与健康检查

聊高可用架构,咱们得从最让人头疼的东西说起——单点故障。说白了,就是系统里那个“一挂全完”的倒霉节点。

我记得刚带团队那会儿,有个线上服务跑得好好的,突然就崩了。查了半天,发现是某个单机数据库连接池满了。就这一个点,拖垮了整个业务线。那次之后,我养成了一个习惯:每设计一个系统,先拿笔圈出所有单点,再一个个干掉它们。

单点故障(SPOF)——系统的阿喀琉斯之踵

单点故障,英文叫 Single Point of Failure,简称 SPOF。它指的是系统中某个组件一旦失效,就会导致整个系统不可用。

常见的单点有哪些?我列几个你肯定见过:

  • 单台服务器:比如就一台 Web 服务器扛着所有流量
  • 单个数据库实例:主库挂了,整个写入都停了
  • 单个负载均衡器:入口就一个,它挂了流量全断
  • 共享存储:比如 NFS 服务器,它一挂所有节点都读不了数据
  • 单一网络链路:一根网线断了,整个机房失联
⚠️ 注意: 单点不一定是一个物理设备。一个进程、一个连接池、甚至一个配置文件,都可能成为单点。我曾经遇到过因为 DNS 解析超时导致全站不可用的情况——那也是一个单点。

你想想看,为什么单点这么可怕?因为它的故障影响范围是 100%。没有冗余,没有回退方案,挂了就是挂了。

冗余设计原则——用“多”来对抗“挂”

冗余,是解决单点故障最直接的手段。但冗余不是简单堆机器,它有几个核心原则。

1. 消除单点,但不制造新单点

这个听起来像废话,但很多人会犯。比如你给数据库加了个从库,结果从库和主库连在同一个交换机上。交换机一挂,主从一起完蛋。这叫“冗余了个寂寞”。

2. 冗余要有独立性

冗余的节点之间,尽量做到物理隔离、网络隔离、甚至地域隔离。我习惯把关键服务部署在不同的可用区,甚至不同的云厂商。成本是高了一点,但心里踏实。

3. 冗余要可切换

光有备胎不行,还得能快速换上去。我见过不少团队,备机配好了,但切换脚本半年没跑过,真到切换时发现密码都忘了。冗余不演练,等于没有冗余。

4. 冗余要有容量余量

别搞成“1+1=1”的冗余。主节点扛 100% 流量,备用节点也得能扛 100%。我遇到过有人把备用节点配成低配机器,主节点挂了,备用节点直接被打爆。那叫“半冗余”,还不如没有。

💡 我的经验: 冗余设计时,我习惯用 N+1 或 N+2 模型。比如 Web 层需要 3 台机器扛流量,我就部署 4 台。多出来的那台,平时也参与服务,只是权重调低。这样既保证了冗余,又避免了“冷备”带来的切换延迟。

负载均衡基础——把流量分均匀

有了冗余节点,怎么把请求分到它们头上?这就是负载均衡干的事。

负载均衡的核心就一句话:把请求按照某种策略,分发给后端多个节点。它解决了两个问题:一是避免某个节点过载,二是当某个节点挂了,自动把流量切到其他节点。

常见的负载均衡策略

策略 原理 适用场景
轮询(Round Robin) 按顺序轮流分发 后端节点配置相同,无状态服务
加权轮询 按权重分配,权重高的多分 后端节点配置不同
最少连接 分给当前连接数最少的节点 长连接服务,如数据库连接池
IP Hash 根据客户端 IP 计算哈希,固定分给某个节点 需要会话保持的场景
一致性哈希 哈希环算法,节点增减影响最小 缓存服务,如 Redis 集群

我个人比较喜欢用加权轮询加最少连接的组合。加权轮询保证了大流量节点的分配,最少连接则能动态调整,避免某个节点因为慢请求堆积而被打垮。

负载均衡的部署模式

  • 四层负载均衡:工作在传输层,基于 IP 和端口转发。性能高,但不关心应用层协议。典型代表是 LVS、F5。
  • 七层负载均衡:工作在应用层,能解析 HTTP、HTTPS 等协议。可以做 URL 路由、SSL 卸载、会话保持。典型代表是 Nginx、HAProxy。

我一般这么用:入口用四层负载均衡扛流量,后面再用七层负载均衡做精细化路由。这样既保证了吞吐量,又保留了灵活性。

🔑 关键点: 负载均衡器本身不能成为单点。所以生产环境一定要做负载均衡器的高可用,比如用 Keepalived 做 VIP 漂移,或者用云厂商的托管负载均衡服务。

健康检查机制——让系统自己“看病”

冗余节点有了,负载均衡也配了,但怎么知道后端节点还活着?这就是健康检查要干的事。

健康检查,说白了就是负载均衡器定期向后端节点发一个“你还活着吗?”的请求。如果节点没回应,或者回应异常,负载均衡器就把它从可用列表里摘掉,不再分发流量给它。

健康检查的几种方式

  • ICMP Ping:最基础的方式,只检查网络通不通。但节点网络通了不代表服务正常。我遇到过机器能 ping 通,但 Nginx 进程已经挂了的情况。
  • TCP 端口检查:尝试连接后端节点的指定端口。比 Ping 靠谱一些,但依然无法确认应用层是否正常。
  • HTTP 检查:发送一个 HTTP 请求,检查返回的状态码和响应体。这是最常用的方式。我习惯在应用里专门暴露一个 /health 接口,返回 200 表示正常,返回 503 表示服务不可用。
  • 自定义脚本检查:执行一个脚本,脚本里可以检查数据库连接、缓存状态、磁盘空间等。这种方式最灵活,但也最重。

健康检查的关键参数

参数 说明 建议值
检查间隔 多久检查一次 5-10 秒
超时时间 等待响应的最长时间 2-3 秒
健康阈值 连续成功几次才算健康 2-3 次
不健康阈值 连续失败几次才算不健康 3-5 次
⚠️ 避坑指南: 我曾经把健康检查的超时时间设成了 10 秒,结果后端节点响应慢的时候,健康检查请求堆积,把负载均衡器自己给打挂了。后来我改成 2 秒超时,配合 3 次失败阈值,既避免了误判,又保护了负载均衡器。

知识体系总览

下面这张图,把本章的核心逻辑串起来了。你可以看到,从单点故障出发,通过冗余设计消除单点,再用负载均衡把流量分散到冗余节点,最后用健康检查确保负载均衡只把流量分给健康的节点。环环相扣,缺一不可。

高可用架构基础:核心逻辑 单点故障(SPOF) 冗余设计原则 负载均衡基础 健康检查机制 识别问题 消除单点 分发流量 自动摘除 持续保障

嗯,到这里,高可用架构的基础部分就聊完了。单点故障是我们要解决的问题,冗余设计是解决问题的思路,负载均衡是落地的工具,健康检查是保障机制。这四个东西,你中有我,我中有你,缺一个都不行。

📌 一句话总结: 没有冗余,就没有高可用;没有负载均衡,冗余就是摆设;没有健康检查,负载均衡就是瞎子。

专注资料整理