系统怎样做到高可用
高并发系统除了要“快”,还必须“稳”。所谓高可用(High Availability),本质上就是:
系统在出现故障、流量突增、部分组件失效时,仍然能够持续对外提供服务。
高可用的核心目标不是“永远不出问题”,因为在大型分布式系统中,故障一定会发生。真正重要的是:
- 故障发生时系统不能整体崩溃
- 出问题后能够快速恢复
- 尽量减少对用户的影响
因此,高可用的本质其实是:
接受故障一定发生,并提前设计好“故障处理机制”。
一、高可用系统的核心指标
衡量高可用通常看“可用性”: 可用性 =系统正常运行时间/总运行时间
常见标准:
- 99%:一年约宕机 3.65 天
- 99.9%:一年约宕机 8.7 小时
- 99.99%:一年约宕机 52 分钟
互联网核心业务往往追求“四个 9”甚至“五个 9”。
但可用性越高,系统复杂度和成本越高,因此必须结合业务做权衡。
二、系统为什么会不可用
常见故障来源包括:
1. 机器故障
- 服务器宕机
- 磁盘损坏
- 网络故障
- 机房断电
这是最基础的问题。
2. 软件故障
- 内存泄漏
- 死锁
- Bug
- GC 暂停
- 程序崩溃
很多线上事故其实都不是硬件问题,而是软件问题。
3. 流量问题
- 突发流量
- 热点事件
- 秒杀活动
- 恶意攻击
系统容量不足时容易雪崩。
4. 依赖故障
现代系统大量依赖:
- Redis
- MySQL
- MQ
- RPC 服务
一个下游服务故障,可能导致整个调用链崩溃。
这就是“故障传播”。
三、高可用的核心设计思想
高可用设计的核心思想有两个:
1. 避免单点
系统中不能存在“唯一节点”。
因为:
单点故障 = 系统故障。
所以关键组件都需要冗余:
- MySQL 主从
- Redis 哨兵/集群
- Nginx 双机
- 多实例部署
- 多机房部署
核心思想是:
一个节点挂掉,其他节点立刻接管。
2. 故障隔离
分布式系统最怕:
一个小故障拖垮整个系统。
因此必须把故障限制在局部。
常见手段:
- 服务拆分
- 线程池隔离
- 资源隔离
- 机房隔离
- 熔断降级
核心目标:
出问题时“局部受影响”,而不是“全站崩溃”。
四、高可用的核心技术手段
1. 集群化
高可用最基础的方法:
多台机器共同提供服务。
好处:
- 某台机器挂了还能继续服务
- 提升系统容灾能力
- 还能提升并发能力
因此:
- Web 服务通常无状态化 + 集群部署
- 数据库使用主从
- Redis 使用哨兵或 Cluster
2. 负载均衡
集群必须配合负载均衡。
作用:
- 将请求分散到多台机器
- 自动摘除故障节点
常见方案:
- LVS
- Nginx
- F5
负载均衡本身也必须高可用。
3. 超时机制
分布式调用中:
最大的问题不是失败,而是“卡死”。
如果请求一直等待:
- 线程会被耗尽
- 连接会被打满
- 最终整个系统阻塞
因此必须设置:
- RPC 超时
- 数据库超时
- 网络超时
核心思想:
宁可失败,也不要无限等待。
4. 限流
系统承载能力有限。
当流量超过极限时:
- CPU 打满
- 数据库崩溃
- 整个系统雪崩
因此必须限制流量。
常见算法:
- 令牌桶
- 漏桶
- 计数器
限流本质上是:
牺牲部分请求,保护整体系统。
5. 降级
当系统压力过大时:
可以关闭部分非核心功能。
例如:
- 评论关闭
- 推荐关闭
- 排行榜延迟刷新
优先保证核心功能:
- 登录
- 支付
- 下单
核心思想:
优先活下来。
6. 熔断
熔断用于防止故障扩散。
例如:
- 下游服务已经大量超时
- 如果继续请求,只会拖垮自己
因此直接中断调用。
类似电路中的“保险丝”。
熔断后:
- 不再请求故障服务
- 等待恢复后再尝试
五、高可用最重要的思想:容错
高可用系统不是“不会失败”,而是“允许失败”。
因此系统设计必须默认:
- 机器会挂
- 网络会断
- 服务会超时
- 流量会暴涨
提前设计:
- 重试
- 超时
- 隔离
- 熔断
- 降级
- 自动恢复
这才是真正的工程化高可用。
六、高可用建设的完整思路
高可用建设一般遵循:
第一步:消除单点
所有核心组件做集群化。
第二步:做好监控
及时发现问题:
- CPU
- 内存
- QPS
- RT
- 错误率
第三步:快速止损
通过:
- 限流
- 熔断
- 降级
- 隔离
阻止故障扩散。
第四步:自动恢复
包括:
- 自动重试
- 自动切换
- 自动扩容
- 自动摘除故障节点