Spring Cloud Alibaba 生产实践:一次微服务架构改造的真实经历
开篇:为什么是 Spring Cloud Alibaba?

两年前,我所在的团队接手了一个典型的单体 Java 应用。这个应用原本部署在几台物理服务器上,随着业务增长和功能不断迭代,代码臃肿、响应延迟严重、发布流程繁琐等问题逐渐暴露出来。我们意识到必须进行架构升级,向微服务方向演进。
当时市场上主流的技术栈有 Netflix 的 Spring Cloud、Dubbo,以及后来者居上的 Spring Cloud Alibaba。经过技术选型评估后,我们最终选择了 Spring Cloud Alibaba,因为它不仅完美兼容 Spring Boot 和 Spring Cloud 的生态体系,还自带了 Nacos、Sentinel、Seata 等一揽子工具,解决了服务注册与发现、限流降级、分布式事务等一系列痛点问题。
这篇文章不是一篇“官方文档复读机”式的技术介绍,而是基于我们在生产环境落地 Spring Cloud Alibaba 时踩过的坑、做过的权衡、总结的经验,希望能给正在走这条路的朋友带来一些启发。
项目背景:从单体到微服务的转型

系统原先是基于 Spring Boot + MyBatis 构建的单一应用,主要提供用户管理、订单、支付、活动营销等功能。整个系统运行在一个 WAR 包中,每天平均请求量约 30 万次,高峰期可达百万次。
随着新需求不断增加,团队协作也变得愈发困难:
- 功能模块交织复杂,代码难以维护;
- 每次上线都要全量重启,影响范围大;
- 高并发场景下出现性能瓶颈,响应时间不稳定;
- 单点故障风险高,缺乏有效的熔断机制。
这些痛点促使我们必须做出改变。
我们的目标很明确:
- 把单体拆成多个服务,实现服务解耦;
- 提升系统的可观测性、可运维性和扩展性;
- 实现更细粒度的权限控制和资源分配;
- 为未来支持多租户架构打基础。
遇到的挑战:不只是技术选型那么简单

说实话,在初期阶段遇到的挑战远远超出预期。
首先是如何划分服务边界?虽然理论上可以根据业务域来切分,但在实际执行中往往会因为数据表关联、历史接口依赖等现实因素而变得模糊不清。我们花了将近两周反复讨论,甚至推翻了好几次方案。
其次是服务通信效率的问题。微服务之间免不了需要调用,但使用普通的 Feign 或 Dubbo RPC 会出现网络延迟,特别是在链路较长的情况下(如 A 调 B,B 再调 C),响应时间急剧上升。
还有就是服务注册与发现的稳定性。我们最初尝试用 Zookeeper 搭配 Dubbo,但配置复杂,运维成本高;后来换成 Eureka,又面临健康检查不准确的问题。最后才转向了 Spring Cloud Alibaba 自带的 Nacos。
最头疼的是数据库拆分后的事务一致性问题。原来的系统使用同一个 MySQL 数据库,很多业务逻辑通过本地事务就能完成。拆分成微服务后,订单服务要操作库存、支付等多个服务的数据,如何保证原子性成为一个关键难题。
解决思路:Spring Cloud Alibaba 的全套落地方案

1. 服务注册中心 —— Nacos
我们选用 Nacos 作为统一的服务注册与配置中心。
优势:
- 可以同时支持服务注册/发现和配置中心;
- 提供 Web 管理界面,运维友好;
- 健康检查机制可靠;
- 支持灰度发布、动态路由等功能。
启动一个 Nacos Server 非常简单:
spring:
application:
name: nacos-server
server:
port: 8848
服务端只需添加以下依赖即可接入:
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
再配上 bootstrap.yml:
spring:
cloud:
nacos:
discovery:
server-addr: 192.168.1.50:8848
启动后就可以在 Nacos 控制台看到服务信息了。
2. 服务调用链优化 —— RestTemplate & Feign & LoadBalancer
早期我们使用 RestTemplate 手动写 HTTP 请求,这种方式灵活性强但重复工作较多。后来我们改用 FeignClient 结合 OpenFeign 和 LoadBalancer 进行服务间通信。
例如:
@FeignClient(name = "order-service")
public interface OrderServiceClient {
@GetMapping("/orders/{id}")
OrderVO getOrderById(@PathVariable String id);
}
这样的声明式方式大大提高了开发效率。同时配合 Ribbon 做客户端负载均衡,基本能满足需求。
3. 服务治理神器 —— Sentinel
Sentinel 是阿里巴巴出品的流量控制组件,支持熔断、限流、降级、热点探测等多种策略。
我们将其集成到每个微服务中,防止某个服务雪崩导致整个系统崩溃。
比如对 /orders 接口设置 QPS 限制:
@Bean
public SentinelResourceAspect sentinelResourceAspect() {
return new SentinelResourceAspect();
}
// 在 Controller 中使用注解
@GetMapping("/orders")
@SentinelResource(value = "getOrders", blockHandler = "handleBlock")
public List<OrderVO> getOrders() {
// 具体逻辑
}
public List<OrderVO> handleBlock(BlockException ex) {
return Collections.emptyList();
}
Sentinel Dashboard 提供可视化监控,非常直观,适合运营排查问题。
4. 分布式事务解决方案 —— Seata
这是我们整个项目中最难啃的一块骨头。
我们采用了 Seata 的 AT 模式,基于全局事务 ID 来协调不同服务之间的事务。
比如订单创建涉及到三个服务:
- 订单服务:生成订单
- 库存服务:扣减库存
- 支付服务:锁定金额
这三个服务分别开启分支事务,并由 Seata 的 TM 统一提交或回滚。
为了启用 Seata,我们需要在每个服务引入以下依赖:
<dependency>
<groupId>io.seata</groupId>
<artifactId>seata-spring-boot-starter</artifactId>
</dependency>
并配置 application.yml:
seata:
enabled: true
application-id: order-service
tx-service-group: my_test_tx_group
service:
vgroup-mapping:
my_test_tx_group: default
grouplist:
default: 192.168.1.60:8091

然后在业务方法上加 @GlobalTransactional 注解:
@GlobalTransactional
@Transactional
public void createOrder(OrderDTO dto) {
// call other services via Feign
// if any exception, rollback globally
}
需要注意的是,Seata 依赖于底层数据库的事务支持,因此数据库必须支持 undo_log 表结构,这部分也是容易出错的地方。
踩过的坑和经验教训
1. 微服务拆分过早抽象,反被其累
在初期我们曾试图把所有通用能力(如日志、认证、缓存)抽成独立服务,结果反而造成依赖过多、维护成本高、启动缓慢等问题。后来我们调整策略,改为按业务线横向切分,优先保障核心链路,非核心能力逐步抽象。
教训:不要为了拆而拆,微服务的本质是“业务驱动”。
2. Nacos 启动失败与集群搭建的细节
Nacos 默认以单机模式启动,但在测试环境中我们发现经常出现节点宕机后无法恢复的情况。后来我们改为采用集群模式,三个节点互为主备,配合 MySQL 存储元数据,提升了稳定性。
记得一定要配置持久化存储:
# application.properties
spring.datasource.platform=mysql
db.num=1
db.url.0=jdbc:mysql://nacos-mysql:3306/nacos_config?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true
db.user=root
db.password=nacos
3. Seata 分支事务超时导致全局事务冻结
这是一个线上曾经出现的问题。由于某服务响应较慢,导致 Seata 的分支事务等待超时,进而使整个全局事务处于挂起状态。
解决办法是合理设置超时时间,并且对于长耗时的操作要考虑是否真的需要纳入全局事务范畴。
4. 多服务共享 Redis 缓存冲突
我们一开始将多个微服务共享同一个 Redis 实例,结果在上线期间出现了 Key 冲突和缓存失效混乱的问题。
后来我们改为每个微服务使用独立的 Redis DB 或命名空间隔离,配合 Redisson 这类封装较好的客户端使用,效果显著提升。
成果与收益
上线半年后,我们取得了以下成果:
- 系统可用性显著提高,全年无重大故障;
- 发布频率从每周一次提高到每日多次,大大加快了产品迭代速度;
- 单个服务部署灵活,可以根据业务压力单独扩容;
- 运维复杂度降低,通过 Nacos + Sentinel + Prometheus 实现了全面监控;
- 开发效率提升,得益于统一的技术栈和清晰的模块职责划分。
给开发者的几点建议
如果你也在考虑使用 Spring Cloud Alibaba,这里是我总结的一些经验,供大家参考:
1. 微服务划分要“小步快跑”,先解耦关键路径
别想着一口气拆干净,先把核心业务模块化,其他模块保持单体也可以慢慢迁移。
2. 不要忽视服务治理的重要性
哪怕是简单的限流和熔断,都能避免很多线上事故。推荐至少引入 Sentinel 并配置好规则。
3. 做好服务间的协议定义和版本控制
微服务之间靠接口通信,如果没有良好的契约管理,后面会非常痛苦。建议结合 OpenAPI 文档和语义化版本号。
4. 使用合理的网关设计
我们使用的是 Zuul + Sentinel 的组合,后续计划升级到 Spring Cloud Gateway。无论哪种方案,网关都应该是安全、鉴权、限流的第一道防线。
5. 监控和日志不能少
Prometheus + Grafana 做指标收集,ELK 做日志分析,再加上 SkyWalking 做分布式追踪,构建完整的可观测性体系非常重要。
尾声:技术只是手段,团队才是根本
最后我想说的是,任何技术框架都不是银弹。我们在落地 Spring Cloud Alibaba 的过程中,不仅仅是用了什么组件,更重要的是形成了新的协作方式、新的开发规范和一套稳定的交付流程。
技术是推动生产力的工具,而真正让系统稳定运转的,是团队的理解力、执行力和持续改进的能力。
如果你也在探索微服务之路,希望这篇文章能给你带来一些实战层面的参考。愿我们都在不断试错中成长,写出更优雅、更健壮的代码。

评论 0