一、突发流量场景:动态限流与弹性扩容
场景特征:节假日促销、热点事件等场景下,系统流量在短时间内呈指数级增长,超出服务处理能力阈值。
典型问题:若未及时控制,可能导致服务雪崩、数据库连接池耗尽、缓存击穿等连锁故障。
技术方案:
- 动态限流算法:
- 令牌桶算法:通过固定速率生成令牌,请求需获取令牌才能被处理,适用于平滑突发流量。例如,某电商平台设置每秒1000个令牌,突发流量下允许短时间超发(如2000个/秒),但后续请求需等待令牌补充。
- 漏桶算法:以恒定速率处理请求,超出部分直接丢弃,适用于对实时性要求不高的场景(如日志上报)。
- 弹性扩容策略:
- 容器化自动扩缩容:基于CPU/内存使用率或请求队列长度触发扩容,例如Kubernetes的Horizontal Pod Autoscaler(HPA)可结合自定义指标(如QPS)动态调整实例数。
- 服务网格流量分流:通过Sidecar代理(如Envoy)将部分流量导向备用集群,避免主集群过载。
代码示例(令牌桶限流):
public class TokenBucket {private final long capacity;private final long refillTokensPerMillis;private long tokens;private long lastRefillTime;public TokenBucket(long capacity, long refillTokensPerSecond) {this.capacity = capacity;this.refillTokensPerMillis = refillTokensPerSecond / 1000;this.tokens = capacity;this.lastRefillTime = System.currentTimeMillis();}public synchronized boolean tryAcquire() {refill();if (tokens > 0) {tokens--;return true;}return false;}private void refill() {long now = System.currentTimeMillis();long elapsed = now - lastRefillTime;long newTokens = elapsed * refillTokensPerMillis;if (newTokens > 0) {tokens = Math.min(capacity, tokens + newTokens);lastRefillTime = now;}}}
二、资源竞争场景:分布式锁与队列优化
场景特征:多实例并发访问共享资源(如数据库、缓存、文件系统),导致数据不一致或性能下降。
典型问题:
- 缓存击穿:热点Key过期时,大量请求同时穿透至数据库。
- 数据库死锁:事务未按固定顺序访问表,引发循环等待。
技术方案:
- 分布式锁实现:
- Redis Redlock算法:通过多个Redis节点投票获取锁,避免单点故障。需注意锁的过期时间需大于业务执行时间。
- Zookeeper临时顺序节点:利用Zookeeper的节点唯一性实现锁,适合长事务场景。
- 队列缓冲设计:
- 异步消息队列:将写操作转为消息投递至队列(如Kafka、RabbitMQ),由消费者按顺序处理,避免直接竞争数据库连接。
- 本地队列+批量提交:例如,日志服务将多条日志暂存本地队列,每秒批量写入一次,减少I/O操作。
代码示例(Redis分布式锁):
import redisimport timeclass RedisLock:def __init__(self, redis_client, lock_key, timeout=10):self.redis = redis_clientself.lock_key = lock_keyself.timeout = timeoutdef acquire(self):while True:if self.redis.set(self.lock_key, "locked", nx=True, ex=self.timeout):return Truetime.sleep(0.1) # 避免忙等待def release(self):self.redis.delete(self.lock_key)
三、服务依赖场景:熔断与降级策略
场景特征:系统依赖的下游服务(如支付、短信网关)出现延迟或不可用,导致请求堆积并反向压垮上游服务。
典型问题:链式故障传播,最终引发全链路崩溃。
技术方案:
- 熔断机制:
- Hystrix/Sentinel实现:当下游服务错误率超过阈值(如50%)时,快速失败并返回备用响应(如缓存数据或默认值)。
- 滑动窗口统计:按时间窗口(如10秒)统计请求成功率,动态调整熔断阈值。
- 服务降级:
- 静态降级:预先配置降级策略(如非核心功能关闭)。
- 动态降级:基于实时监控数据(如CPU负载>80%)触发降级。
配置示例(Sentinel熔断规则):
FlowRule rule = new FlowRule();rule.setResource("paymentService");rule.setGrade(RuleConstant.FLOW_GRADE_QPS);rule.setCount(100); // QPS阈值rule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_WARM_UP); // 预热模式FlowRuleManager.loadRules(Collections.singletonList(rule));
四、慢请求堆积场景:超时控制与优先级队列
场景特征:部分请求处理时间过长(如复杂查询、大文件上传),占用线程池资源,导致新请求被拒绝。
典型问题:线程池耗尽,系统失去响应能力。
技术方案:
- 全局超时控制:
- HTTP客户端超时:设置连接超时(如5秒)和读取超时(如10秒)。
- gRPC死线(Deadline):通过元数据传递截止时间,上下游服务统一校验。
- 优先级队列:
- 多线程池分区:将请求按优先级分配至不同线程池(如高优先级使用核心线程,低优先级使用最大线程)。
- Redis ZSET实现延迟队列:按执行时间排序任务,消费者仅处理到期任务。
代码示例(gRPC Deadline):
// 客户端设置Deadlinectx, cancel := context.WithTimeout(context.Background(), 5*time.Second)defer cancel()response, err := client.SomeMethod(ctx, &request)if err != nil {if status.Code(err) == codes.DeadlineExceeded {log.Println("Request timed out")}}
五、综合实践:全链路流量控制体系
- 监控与告警:
- 集成Prometheus+Grafana监控QPS、错误率、延迟等指标。
- 设置阈值告警(如错误率>1%触发熔断)。
- 混沌工程测试:
- 模拟下游服务故障,验证熔断、降级策略是否生效。
- 容量规划:
- 基于历史流量数据预估峰值QPS,预留20%余量。
总结
流量控制是分布式系统设计的核心能力,需结合业务场景选择合适策略。对于突发流量,优先采用动态限流+弹性扩容;资源竞争场景需依赖分布式锁+队列缓冲;服务依赖问题需通过熔断+降级解决;慢请求堆积则需超时控制+优先级队列。实际系统中,建议通过全链路监控和混沌工程持续优化策略,确保系统在极端场景下仍能稳定运行。