社交App最怕什么?不是功能做不出来,而是做出来后扛不住。流量洪峰时系统崩溃,用户大量流失,这是很多团队的噩梦。这篇文章讲高可用设计的核心三板斧:限流、熔断、降级。
一、高可用的本质是什么
高可用不是「永远宕机」,而是「宕机了能快速恢复,影响范围最小化」。
核心指标:
| 指标 | 定义 | 目标 |
|---|---|---|
| SLA | 服务可用性 | 99.9%(全年停机<8.76小时) |
| MTTR | 平均恢复时间 | <5分钟 |
| MTBF | 平均故障间隔 | 越长越好 |
社交系统的高可用难点:
· 流量不可预测(热点事件、运营活动)
· 依赖服务多(IM、RTC、推送、支付)
· 用户容忍度低(消息发不出去就想卸载)
二、限流:流量洪峰的第一道防线
2.1 为什么限流
社交App的流量特点:
· 突发性强(话题引爆、活动开始)
· 潮汐效应(早晚高峰、节假日)
· 热点倾斜(某个大V直播间涌入大量用户)
如果不限流,流量超过系统承载能力时:
· 服务响应变慢 → 用户重试 → 流量翻倍 → 服务崩溃
2.2 限流算法
2.1 为什么限流
社交App的流量特点:
· 突发性强(话题引爆、活动开始)
· 潮汐效应(早晚高峰、节假日)
· 热点倾斜(某个大V直播间涌入大量用户)
如果不限流,流量超过系统承载能力时:
· 服务响应变慢 → 用户重试 → 流量翻倍 → 服务崩溃
2.2 限流算法
1. 固定窗口算法
每分钟最多1000次请求
- 0-59秒:计数器=0
- 第1秒来了500次 → 计数器=500
- 第30秒来了600次 → 计数器=1100 → 拒绝100次
- 第60秒:计数器重置
问题: 边界突刺。第59秒来500次,第60秒来500次,实际1秒内可能承受1000次。
2. 滑动窗口算法
窗口大小=1分钟,每秒滑动
- 统计最近60秒的请求总数
- 更精确,但内存开销大
3. 令牌桶算法(推荐)
令牌桶
- 以固定速率放入令牌(如100个/秒)
- 桶容量有限(如1000个)
- 请求来时取令牌
- 无令牌则拒绝
优势: 允许一定突发流量(桶内有存量令牌),控制平均速率(放入速率固定)
4. 漏桶算法
漏桶
- 请求先进入队列
- 以固定速率处理请求
- 队列满则丢弃
优势: 流量整形,输出平稳
劣势: 无法应对突发流量
2.3 限流维度
| 维度 | 场景 | 实现 |
|---|---|---|
| 全局限流 | 保护系统整体 | Nginx/API网关 |
| 用户级限流 | 防刷、防滥用 | Redis计数 |
| 接口级限流 | 保护核心接口 | 代码层面 |
| IP级限流 | 防攻击 | Nginx/网关 |
| 房间级限流 | 大房间消息量控制 | 服务端逻辑 |
2.4 实战配置示例
# 限流配置
rate_limit:
# 全局限流
global:
qps: 100000
burst: 1000
# 用户级限流
user:
send_message:
qps: 10
burst: 20
join_room:
qps: 5
burst: 10
# 房间级限流
room:
message:
qps: 1000
burst: 2000
三、熔断:防止级联故障
3.1 什么是熔断
场景: 你的消息服务依赖用户服务,用户服务挂了,你的请求一直等待超时,导致消息服务也被拖垮。
熔断机制: 当依赖服务失败率达到阈值时,直接返回失败或降级结果,不再调用依赖服务。一段时间后尝试恢复。
3.2 熔断器状态机
状态说明:
· 关闭: 正常状态,请求正常调用
· 打开: 熔断状态,直接返回失败/降级
· 半打开: 探测状态,允许少量请求测试是否恢复
3.3 熔断配置示例
# 熔断配置
circuit_breaker:
user_service:
failure_threshold: 50% # 失败率阈值
request_threshold: 100 # 最小请求数
timeout: 30s # 熔断时长
half_open_requests: 5 # 半开状态测试请求数
im_service:
failure_threshold: 30%
request_threshold: 50
timeout: 10s
3.4 常见熔断框架
| 框架 | 语言 | 特点 |
|---|---|---|
| Sentinel | Java | 阿里开源,功能全面 |
| Hystrix | Java | Netflix开源,成熟稳定 |
| Resilience4j | Java | 轻量级,模块化 |
| resilience4j-spring | Java | Spring生态整合 |
| gobreaker | Go | 简单易用 |
| circuit-breaker | Node.js | JS生态 |
四、降级:保核心、舍非核心
4.1 降级策略
原则: 牺牲非核心功能,保证核心功能可用。
| 策略 | 说明 | 场景 |
|---|---|---|
| 自动降级 | 系统自动触发(负载高、依赖失败) | 熔断后降级 |
| 手动降级 | 运维手动开关 | 大促前预先降级 |
| 读降级 | 读走缓存、减少精度 | 历史消息只查缓存 |
| 写降级 | 写入异步化、延迟处理 | 消息先写MQ |
| 功能降级 | 关闭非核心功能 | 推荐功能关闭 |
4.2 社交系统降级场景
场景1:用户服务不可用
正常:用户发送消息 → 校验用户状态 → 发送
降级:用户发送消息 → 跳过校验 → 发送(可能发给封禁用户)
场景2:消息存储压力大
正常:消息 → 写存储 → 返回成功
降级:消息 → 写Redis → 返回成功(异步写存储)
场景3:推荐服务压力大
正常:进入房间 → 推荐相关房间 → 展示
降级:进入房间 → 跳过推荐 → 展示默认列表
场景4:推送服务压力大
正常:消息 → 推送给所有在线用户
降级:消息 → 只推送给核心用户(房主、管理员)
4.3 降级配置中心
**配置示例:**
{
"degrade_rules": {
"user_profile": {
"enabled": false,
"strategy": "cache",
"fallback": "default_profile"
},
"recommendation": {
"enabled": true,
"strategy": "disable",
"fallback": "popular_rooms"
},
"message_search": {
"enabled": false,
"strategy": "limit",
"fallback": "recent_100"
}
}
}
五、实战案例:一次流量洪峰的处理过程
5.1 场景描述
某社交App举办线上活动,直播间人数从500人瞬间暴涨到5000人。
5.2 处理过程
5.3 关键指标变化
| 时间点 | CPU | 消息延迟 | 错误率 | 用户体验 |
|---|---|---|---|---|
| T+0 | 70% | 50ms | 0.1% | 正常 |
| T+30 | 85% | 100ms | 1% | 轻微卡顿 |
| T+60 | 90% | 200ms | 2% | 部分功能不可用 |
| T+120 | 85% | 150ms | 1% | 消息正常,推荐不可用 |
| T+300 | 70% | 80ms | 0.5% | 基本恢复 |
| T+600 | 50% | 50ms | 0.1% | 完全恢复 |
六、高可用架构设计原则
| 原则 | 说明 |
|---|---|
| 无单点 | 任何组件都要有冗余 |
| 快速失败 | 超时、异常要快速返回,不要等待 |
| 优雅降级 | 核心功能保住,非核心可以牺牲 |
| 限流保护 | 宁可拒绝部分请求,也不能让系统崩溃 |
| 监控先行 | 没有监控就没有高可用 |
| 预案演练 | 提前准备预案,定期演练 |
下篇预告: 《用户关系链存储方案:MySQL够用吗?图数据库何时引入》——深入探讨社交系统的数据存储设计。
持续输出社交App开发实战经验,关注我,一起成长。