去年双十一期间,我们团队负责的淘客返利平台经历了前所未有的流量冲击。当天峰值QPS突破120万,是日常流量的50倍以上。这种脉冲式流量对系统稳定性提出了严峻考验——优惠券查询接口响应时间从平均80ms飙升到2.3秒,核心服务多次触发熔断,直接影响平台佣金收入。
经过压力测试和线上事故复盘,我们识别出三大核心痛点:
采用Spring Cloud Alibaba生态体系:
选择依据:
code复制用户请求 → API网关 → 限流层 → 本地缓存 → 分布式缓存 → 数据库
↑ ↑ ↑
Sentinel Caffeine Redis
关键设计点:
java复制// 基于Sentinel的热点参数限流
@SentinelResource(
value = "couponQuery",
blockHandler = "handleBlock",
fallback = "queryFallback"
)
public List<Coupon> queryCoupons(Long itemId) {
//...
}
// 动态规则配置
private void initFlowRules() {
List<FlowRule> rules = new ArrayList<>();
FlowRule rule = new FlowRule();
rule.setResource("couponQuery");
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
rule.setCount(5000);
rule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER);
rule.setMaxQueueingTimeMs(1000);
rules.add(rule);
FlowRuleManager.loadRules(rules);
}
订单创建流程改造前后对比:
| 步骤 | 同步模式 | 异步模式 |
|---|---|---|
| 1. 校验库存 | 直接调用库存服务 | 本地库存缓存 |
| 2. 生成订单 | 同步写数据库 | 写入RocketMQ |
| 3. 发券 | 同步调用券系统 | 消费MQ消息 |
| 4. 返利计算 | 实时计算 | 离线任务调度 |
改造后接口RT从380ms降至120ms,吞吐量提升4倍。
yaml复制# Sentinel配置示例
spring:
cloud:
sentinel:
datasource:
ds1:
nacos:
server-addr: 127.0.0.1:8848
dataId: sentinel-rules
rule-type: flow
transport:
dashboard: localhost:8080
flow:
cold-factor: 3 # 冷启动因子
熔断策略矩阵:
| 指标 | 阈值 | 恢复策略 | 适用场景 |
|---|---|---|---|
| 慢调用比例 | RT>500ms & 比例>50% | 渐进恢复 | 数据库查询 |
| 异常比例 | 错误率>40% | 快速失败 | 外部接口调用 |
| 异常数 | 5分钟100次 | 冷启动 | 核心交易链路 |
分级降级策略:
问题现象:
解决方案:
java复制public static int customHash(String key) {
int slot = CRC16.crc16(key.getBytes()) % 16384;
if(isHotKey(key)) {
return slot % 8; // 强制路由到前8个分片
}
return slot;
}
java复制// Caffeine配置
LoadingCache<String, Object> cache = Caffeine.newBuilder()
.maximumSize(10_000)
.expireAfterWrite(5, TimeUnit.MINUTES)
.refreshAfterWrite(1, TimeUnit.MINUTES)
.build(key -> loadFromRedis(key));
sql复制/* 原方案 */
UPDATE user_balance SET amount=amount-100 WHERE user_id=123;
/* 优化方案 */
INSERT INTO balance_operate(user_id, delta) VALUES(123, -100);
java复制// 每100ms批量处理一次
@Scheduled(fixedRate = 100)
public void batchUpdate() {
List<Operation> batch = BufferQueue.take();
jdbcTemplate.batchUpdate(
"UPDATE items SET stock=stock-? WHERE id=?",
batch.stream().map(op -> new Object[]{op.delta, op.id})
.collect(Collectors.toList())
);
}
监控指标分层:
Prometheus关键配置:
yaml复制scrape_configs:
- job_name: 'spring'
metrics_path: '/actuator/prometheus'
static_configs:
- targets: ['app1:8080','app2:8080']
分级告警规则示例:
| 级别 | 条件 | 通知方式 | 响应时间 |
|---|---|---|---|
| P0 | 核心接口成功率<95% | 电话+短信 | 5分钟 |
| P1 | Redis命中率<80% | 企业微信 | 15分钟 |
| P2 | 单节点CPU>80% | 邮件 | 1小时 |
JMeter测试计划设计:
关键参数:
properties复制jmeter.threads=1000
jmeter.rampup=300
jmeter.duration=1800
优化前后对比数据:
| 指标 | 优化前 | 优化后 | 提升 |
|---|---|---|---|
| 最大QPS | 8万 | 62万 | 675% |
| 平均RT | 420ms | 89ms | 78% |
| 错误率 | 4.2% | 0.17% | 96% |
| 服务器数量 | 120台 | 45台 | 62% |
问题现象:
解决方案:
yaml复制spring:
redis:
lettuce:
pool:
max-active: 800 # 原值200
max-idle: 100
min-idle: 20
timeout: 5000
java复制@Bean
public RedisTemplate<String, Object> redisTemplate() {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory());
template.setEnableTransactionSupport(true);
template.afterPropertiesSet();
// 增加连接泄露监控
((LettuceConnectionFactory)redisConnectionFactory())
.setValidateConnection(true);
return template;
}
问题场景:
优化方案:
java复制RLock lock = redisson.getLock("coupon:"+couponId);
try {
if(lock.tryLock(100, 10, TimeUnit.MILLISECONDS)) {
// 业务逻辑
}
} finally {
lock.unlock();
}
java复制// 本地锁减少网络开销
private final ConcurrentHashMap<String, Object> localLocks = new ConcurrentHashMap<>();
public void deductBalance(Long userId) {
Object localLock = localLocks.computeIfAbsent(userId.toString(), k -> new Object());
synchronized (localLock) {
// 获取分布式锁
}
}