如何系统性地提升系统可用性?
面试场景
面试官:”你之前的项目是如何保证高可用的?”
这是一道开放性问题。如果仅回答”用了限流降级熔断”,只能得到及格分。高分回答需要结构化思维,从全局视角梳理高可用策略。
核心思路:三大策略
构建高可用系统,核心围绕三个策略展开:
- 减少故障次数:尽可能让故障不发生
- 降低故障时长:一旦发生,快速止血恢复
- 缩小故障范围:控制爆炸半径,避免雪崩
本题聚焦减少故障次数的五大方法。
方法一:限流
核心思想
保护系统不被超出其处理能力的请求击垮,通过主动拒绝保障可用性。
关键点
1. 阈值设置
- 过高形同虚设,过低浪费资源
- 最佳实践:在业务低峰期使用真实流量回放压测,阈值设为峰值容量的 50%~70%
2. 多级布控
系统整体限流(如600 QPS)
│
├── 接口级别限流(慢接口单独设限)
│
└── 来源级别限流(按租户/业务线区分)
3. 主流工具
- Guava RateLimiter(单机令牌桶)
- Sentinel(阿里开源,支持集群限流、热点参数限流)
- Nginx limit_req_zone(网关层限流)
方法二:防刷
与限流的区别
限流针对正常业务洪峰,防刷针对异常请求:DDoS攻击、抢票工具、代码BUG(循环调用)。
防护层级(越上层越好)
| 层级 | 方式 | 说明 |
|---|---|---|
| WAF | IP围栏、DDoS速率限制 | 云厂商WAF产品 |
| Nginx | limit_req_zone + limit_conn | IP维度请求速率限制 |
| 应用层 | Redis计数器 | 用户ID+接口维度限制 |
应用层示例
String key = "rateLimit:" + userId + ":" + method;
Long count = redisTemplate.opsForValue().increment(key, 1);
if (count == 1) {
redisTemplate.expire(key, 1, TimeUnit.SECONDS);
}
if (count > 10) {
throw new RateLimitException("请求过于频繁");
}
方法三:超时设置
为什么需要超时?
下游服务可能存在长尾请求(TP99=100ms,但TP999=5s),不设超时会导致线程池被占满。
最佳实践
- 超时时间设置在 TP99 ~ TP999 之间
- 例如:TP99=100ms,超时可设200ms
- 配合重试策略(重试次数、退避算法、幂等保障)
超时配置示例(Dubbo)
dubbo:
consumer:
timeout: 200
retries: 2
方法四:系统巡检
巡检时机
- 代码上线后:检查是否引入性能问题
- 业务高峰期前:提前发现隐患
巡检内容
┌─ 硬件指标 ─┬─ 应用服务器:CPU、内存、负载、网络
│ └─ 数据库服务器:连接数、磁盘IO、慢SQL
│
├─ 业务指标 ─── QPS/TPS、接口响应时间、错误率
│
└─ 数据库指标 ─ 新增慢SQL、锁等待、主从延迟
方法五:故障复盘
复盘方法论
- 5 WHYS:连续追问5次”为什么”,找到根因
- 黄金三问:发生了什么?为什么发生?如何防止再发生?
复盘输出要点
- TODO必须可落地,而非”下次多注意”
- 区分重要紧急和重要不紧急,明确负责人和完成时间
- 由点及面:一个故障可能揭示一类问题
面试答题要点
- 结构化:先给出”减少故障次数、降低故障时长、缩小故障范围”的框架
- 深入细节:限流要讲阈值设置和多级布控,不能只说”加了限流”
- 结合场景:最好能举出具体案例,如”压测发现系统峰值3000 QPS,限流阈值设2000”
- 工具选型:能说出Sentinel、Hystrix等工具的选型理由
总结
减少故障次数的五大方法:
| 方法 | 核心价值 |
|---|---|
| 限流 | 控制入口流量,保护系统 |
| 防刷 | 拦截异常请求,防止恶意攻击 |
| 超时设置 | 防止单点慢导致全局卡死 |
| 系统巡检 | 提前发现隐患,防患于未然 |
| 故障复盘 | 从历史故障中学习,持续改进 |