从“服务雪崩”到稳定交付:Spring Cloud Alibaba 在高并发项目中的实战经验分享
去年我参与了一个金融类平台的重构项目。这个平台是一个典型的中大型微服务架构,原本采用的是 Spring Cloud Netflix 的技术栈,包括 Eureka、Zuul、Ribbon 等组件。但由于某些原因,公司决定转向 Spring Cloud Alibaba(简称 SCA),并以 Dubbo + Nacos 作为核心框架进行重构。
当时我对 Spring Cloud Alibaba 还没有深入实战经验,只是大致了解它提供的一些能力——比如服务发现、分布式配置管理、限流熔断等。但真正在生产环境使用时,才发现它的优势和坑远比想象中多得多。
这篇文章我会结合项目的实际背景,详细聊聊我们是如何一步步落地 SCA 栈,并在解决“服务雪崩”、“数据库压力大”以及“接口设计混乱”等问题上积累的经验。
项目背景与挑战

我们的系统每天有超过百万级的请求量,涉及用户账户、风控评估、交易流水等多个模块。由于原系统基于 Spring Cloud Netflix 搭建,服务之间调用链复杂、故障传播快,在某个服务出现异常时,很容易引发服务雪崩。
更糟糕的是,随着业务扩展,原有的网关 Zuul 成为性能瓶颈,响应延迟经常突破 1 秒以上。同时,配置中心和限流机制也存在不少问题,运维同学对这套体系越来越难以维护。
于是我们决定重构整个后端架构,选择 Spring Cloud Alibaba 作为新一代微服务框架。目标很明确:提高系统的稳定性、可维护性和性能表现。
技术选型与整体架构设计

我们并没有一开始就全盘替换原有架构,而是逐步过渡。以下是最终确定的技术栈:
- 服务注册发现:Nacos(支持 AP 和 CP 切换)
- RPC 框架:Dubbo 3.x(比 Feign 更适合高频调用场景)
- 服务网关:Gateway + Nacos 动态路由(替代 Zuul)
- 限流熔断:Sentinel(内置热点参数限流是亮点)
- 消息队列:RocketMQ(国产自研,兼容性好)
- 分布式事务:Seata(用于跨账户转账等关键流程)
此外,我们在数据库方面做了分库分表的设计,采用了 ShardingSphere 来做读写分离与数据路由;缓存则使用了 Redis + Caffeine 双层缓存结构来减轻 DB 压力。
整个架构图大概是这样:
[ Gateway ]
↓
[ Nacos 注册中心 ]
↙ ↘
[ User Service ] [ Risk Service ] [ Trade Service ] ...
↓ ↓ ↓
[ Sentinel 限流 ] [ RocketMQ 异步通信 ]
↓
[ Seata 分布式事务控制 ]
↓
[ ShardingSphere 分库分表 ]
实战中遇到的问题与解决方案

问题一:服务间调用频繁导致线程阻塞,进而引发雪崩效应
这是最棘手的一个问题。最初我们采用的是 Dubbo 默认的同步调用方式,结果在高峰期一旦下游某台服务器挂掉或延迟高一点,上游服务会大量等待阻塞,线程池被打满,直接崩溃。
解决方案:
我们将部分非核心调用改为异步方式,并配合 RocketMQ 做消息解耦。例如风控评估结果可以通过 MQ 广播给其他系统,而不是每次都等一个返回结果。
另外,我们在服务入口加上了 Sentinel 的限流规则,设置了 QPS 与线程数双维度的限流策略,保障核心路径的可用性。
举个例子:
spring:
cloud:
sentinel:
datasource:
flow:
nacos:
server-addr: nacos-host:8848
data-id: user-service-flow-rules
group: DEFAULT_GROUP
然后我们在 Nacos 中配置具体的限流规则 JSON:
[
{
"resource": "/api/user/get",
"limitApp": "default",
"grade": 1,
"count": 2000,
"strategy": 0,
"controlBehavior": 0
}
]
通过这种方式,我们实现了动态限流,而且能在控制台实时调整规则而无需重启应用。
问题二:服务注册失败频繁,Nacos 出现抖动
有一次上线过程中,多个节点启动失败,日志显示连接不上 Nacos。排查之后发现是网络分区引起的,再加上客户端重试机制不合理,造成服务注册不及时,后续调用全部失败。
解决方案:
我们统一将 Nacos 客户端升级到了最新版本,并引入了心跳机制优化,设置健康检查频率为 5s,超时时间为 2s,提升感知速度。
同时我们在部署层面采用了 Nacos 集群模式,三节点部署 + MySQL 外部存储元数据,提升了可靠性和容灾能力。
Dubbo 配置如下:
dubbo:
registry:
address: nacos://nacos-host1:8848,nacos://nacos-host2:8848,nacos-host3:8848
问题三:接口设计混乱,服务边界模糊
早期很多服务之间的接口没有统一设计规范,造成了接口复用差、参数冗余、文档缺失等一系列问题。
解决方案:
我们引入了 OpenAPI 规范(Swagger + Knife4j),每个服务都必须提供标准化的接口文档,并通过统一网关进行鉴权和路由。所有对外暴露的服务都走 Gateway,禁止绕过网关直连。
此外我们还制定了接口命名规范、异常编码标准,并通过 AOP 实现通用的日志记录和异常拦截:
@Aspect
@Component
@Slf4j
public class RequestLogAspect {
@Pointcut("execution(* com.example..*.controller.*.*(..))")
public void requestLog() {}
@Before("requestLog()")
public void doBefore(JoinPoint joinPoint) {
ServletRequestAttributes attributes =
(ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
log.info("URL : " + request.getRequestURL().toString());
log.info("HTTP_METHOD : " + request.getMethod());
log.info("CLASS_METHOD : " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
log.info("ARGS : " + Arrays.toString(joinPoint.getArgs()));
}
}
踩过的几个坑与避坑建议
1. Dubbo 泛化调用性能不如预期
我们曾尝试用泛化调用来实现一些通用逻辑处理,后来发现每次都要构建 Map 参数对象,序列化反序列化开销较大。最终我们还是改成了定义 DTO 对象的方式,虽然开发效率低点,但运行性能更好。
2. Sentinel 不支持 Spring MVC 的注解限流
一开始我们想对 Web 层 Controller 接口直接加 @SentinelResource 注解,但默认只适用于方法级别的资源名,无法自动识别 URL 路径。后来我们通过自定义 Filter + Sentinel Rule API 的方式实现了统一控制。
3. Seata 在高并发下出现死锁问题
Seata 在 TCC 模式下需要手动编写 Confirm 和 Cancel 方法。我们早期在库存扣减逻辑中使用不当,导致在并发下单时出现事务卡死的问题。最后通过对数据库加行锁、优化本地事务提交顺序,才缓解了这一问题。
最终效果与收益总结
经过半年的努力,我们成功完成了整套系统的迁移到 Spring Cloud Alibaba 架构。迁移后的效果非常明显:
| 指标 | 改造前 | 改造后 |
|---|---|---|
| 网关平均 RT | 1100ms | 400ms |
| 服务间调用失败率 | 5% ~ 7% | <0.5% |
| 全链路成功率 | 92% | 99.6% |
| 日均故障次数 | 8次 | ≤2次 |
更重要的是,现在的架构具备良好的可观测性和可维护性,运维同学可以轻松地通过 Nacos 控制台查看服务状态、Sentinel 查看实时监控指标、Seata 查看事务日志,大大节省了排障时间。
经验总结与建议
如果你也在考虑或者已经开始使用 Spring Cloud Alibaba,以下几点是我踩坑后总结下来的心得:
✅ 架构设计建议
- 优先使用 Dubbo 替代 Feign,尤其是 RPC 调用密集的场景。
- 结合 Sentinel 实现动态限流,避免单一 QPS 的限制。
- 使用 Nacos 做统一配置中心,配置文件要精细化划分。
- 所有服务都走 Gateway,严禁服务间跳过网关直连。
✅ 性能调优方向
- 合理设置线程池大小,防止资源耗尽;
- 使用本地缓存 + Redis 缓存结合,减少 DB 访问;
- 接口尽量保持幂等,利于限流降级和回滚;
- 对关键链路进行埋点,方便定位性能瓶颈。
✅ 开发协作建议
- 统一接口规范,使用 Swagger/Knife4j 自动生成文档;
- 所有服务命名统一规划,如 user-service、order-service;
- 异常码统一格式,避免服务间理解歧义;
- 接口调用统一封装成 SDK,降低依赖耦合。
写在最后:一次架构的进化,不止于代码
回顾整个过程,我深刻体会到:一个好的架构不是一开始就能设计出来的,而是在一次次线上事故、一次次需求迭代中打磨出来的。
Spring Cloud Alibaba 提供了一套非常完整的微服务解决方案,但它也像一把刀,怎么使用取决于使用者的经验和水平。
如果你刚接触这个生态,不妨从小项目入手,先掌握 Dubbo + Nacos 的基本用法,再逐步引入 Sentinel、Seata、RocketMQ 等进阶组件。只有真正动手实践过,才能感受到这些工具背后的原理和价值。
希望这篇文章能给你带来一些启发,少走一些弯路。如果你们也有类似的实战经验,欢迎一起交流探讨!
如果你觉得这篇文章对你有所帮助,别忘了点赞、收藏、转发哦~你的支持是我继续写作的最大动力!

评论 0