共计 2392 个字符,预计需要花费 6 分钟才能阅读完成。
背景痛点:为什么我们需要重构龙虾 Skill 系统
在最初的单体架构下,我们的龙虾 Skill 系统面临三个核心问题:

- 响应延迟飙升 :当并发请求超过 500TPS 时,API 平均响应时间从 200ms 骤增至 1.2s
- 数据库瓶颈 :MySQL 连接池频繁耗尽,出现 ”Too many connections” 错误
- 扩展困难 :业务逻辑耦合严重,新增技能类型需要全量部署
通过火焰图分析发现,75% 的 CPU 时间消耗在同步处理语音转文本和第三方 API 调用上。
技术选型:架构与消息队列的抉择
架构方案对比
| 维度 | 单体架构 | 微服务架构 |
|---|---|---|
| 开发效率 | ⭐⭐⭐⭐ | ⭐⭐ |
| 性能上限 | ⭐⭐ | ⭐⭐⭐⭐ |
| 运维复杂度 | ⭐ | ⭐⭐⭐ |
| 技术债务 | 快速积累 | 可控 |
决策依据 :根据业务预测,未来 6 个月并发量将增长 10 倍,最终选择基于 Spring Cloud 的微服务架构。
消息队列选型
// Kafka 生产者性能测试片段
@Benchmark
public void testThroughput() {for (int i = 0; i < 100000; i++) {producer.send(new ProducerRecord<>("topic", "key", "value"));
}
}
测试数据表明:
- Kafka 吞吐量达到 150k msg/s,是 RabbitMQ 的 3 倍
- RabbitMQ 在消息延迟稳定性上表现更好(±5ms vs ±25ms)
最终选择 Kafka,因为:
- 龙虾 Skill 业务对吞吐量更敏感
- 允许少量消息延迟波动
- 已有 Kafka 运维经验
核心实现:关键代码与设计
微服务拆分方案
graph TD
A[API Gateway] --> B[Auth Service]
A --> C[Skill Manager]
A --> D[Async Processor]
C --> E[Kafka]
E --> D
- Auth Service:独立鉴权服务,QPS 3000+
- Skill Manager:技能元数据管理,低 QPS 但高可用要求
- Async Processor:核心业务处理器,部署 10+ 实例
异步处理关键代码
@KafkaListener(topics = "skill_requests")
public void handleRequest(SkillRequest request) {
// 1. 分布式锁防重
String lockKey = "lock:" + request.getRequestId();
try {if (!redisLock.tryLock(lockKey, 10, TimeUnit.SECONDS)) {log.warn("Duplicate request: {}", request.getRequestId());
return;
}
// 2. 幂等检查
if (requestCache.exists(request.getRequestId())) {return;}
// 3. 异步处理核心逻辑
CompletableFuture.runAsync(() -> {processSkill(request);
}, asyncExecutor);
} finally {redisLock.unlock(lockKey);
}
}
分布式锁实现
基于 Redisson 的 MultiLock 解决跨服务竞争问题:
RLock lock1 = redisson.getLock("lock1");
RLock lock2 = redisson.getLock("lock2");
RLock multiLock = redisson.getMultiLock(lock1, lock2);
try {if (multiLock.tryLock(50, 10, TimeUnit.SECONDS)) {// 临界区代码}
} finally {multiLock.unlock();
}
性能优化实战
压力测试方案
使用 JMeter 模拟三种场景:
- 突发流量:0→5000TPS 瞬时增长
- 持续高压:3000TPS 维持 10 分钟
- 阶梯增长:每 5 分钟增加 1000TPS
关键配置 :
# JMeter 配置
threads=500
ramp_up=10
loop_count=-1
JVM 调优参数
对比 G1 与 ZGC 的表现后,最终采用:
java -jar \
-Xms4g -Xmx4g \
-XX:+UseZGC \
-XX:MaxGCPauseMillis=100 \
-XX:ConcGCThreads=4 \
-Dio.netty.allocator.type=pooled \
-jar skill-service.jar
优化效果:
| 指标 | 调优前 | 调优后 |
|---|---|---|
| GC 停顿时间 | 230ms | 28ms |
| 吞吐量 | 1200TPS | 3800TPS |
生产环境避坑指南
消息幂等三要素
- 唯一 ID:使用 Snowflake 生成 requestId
- 去重表 :MySQL+Redis 二级缓存
- 过期策略 :设置合理的 TTL(我们设为 7 天)
服务降级策略
配置多级降级(基于 Sentinel):
- 一级:关闭非核心技能(QPS 阈值 1000)
- 二级:返回兜底结果(QPS 阈值 2000)
- 三级:直接拒绝请求(QPS 阈值 3000)
监控体系
# Prometheus 配置示例
- job_name: 'skill_service'
metrics_path: '/actuator/prometheus'
scrape_interval: 15s
static_configs:
- targets: ['service1:8080', 'service2:8080']
关键监控项:
- Kafka 消费延迟
- Redis 内存使用率
- 线程池队列积压
总结与扩展
这套方案已稳定运行 6 个月,支撑日均 1.2 亿次请求。值得关注的改进方向:
- Serverless 化 :将 Async Processor 改为 FaaS 实现
- 多活部署 :当前架构仅支持同城双活
- AI 调度 :基于预测模型动态扩缩容
对于其他技能类系统,建议重点关注:
- 业务隔离度
- 异步通道容量规划
- 分布式事务补偿机制
经验分享:我们在灰度发布阶段发现,新老版本消息协议不兼容会导致消息堆积。解决方案是采用双 topic 并行方案过渡两周,逐步迁移。
正文完
