从单体到微服务:我在 Spring Cloud Alibaba 上的生产实战经验

代码诗人
2025-06-13 17:15
阅读 644

开篇:一段架构演进的故事

开篇:一段架构演进的故事

2021年,我加入了一个处于快速扩张阶段的电商项目。当时的技术架构是典型的单体应用,部署在 Tomcat 上,数据库用了 MySQL 主从结构,后端开发框架是传统的 Spring MVC,前端 Vue.js。

随着业务增长,系统的复杂度和并发压力陡增。单体架构的问题逐渐暴露:代码臃肿、部署繁琐、功能模块耦合严重、故障影响面大。我们迫切需要一次技术架构的升级。

最终我们选择了 Spring Cloud Alibaba(SCA) 作为微服务化的核心技术栈。这是一次有风险但必须做的尝试。如今回头看这段路,踩过坑、走过弯,但也收获满满。


问题描述:为什么我们需要 Spring Cloud Alibaba?

问题描述:为什么我们需要 Spring Cloud Alibaba?

API接口文档-2

单体架构遇到的实际问题:

  • 发布频繁出错:一个小改动也可能牵一发而动全身。
  • 性能瓶颈明显:部分核心接口 QPS 超过临界点,系统开始卡顿甚至崩溃。
  • 缺乏服务治理:没有统一的服务发现、限流降级能力。
  • 团队协作困难:多个功能模块并行开发时冲突频发,分支管理成本高。

更糟的是,我们在高峰期遭遇了一次大规模雪崩故障,由于某个下游服务调用阻塞导致整个系统瘫痪。

我们需要一个轻量、灵活、国产化程度高且能与阿里云生态无缝集成的微服务解决方案——于是我们把目光投向了 Spring Cloud Alibaba


解决方案:基于 SCA 的微服务改造之路

API接口文档-1

解决方案:基于 SCA 的微服务改造之路

我们的目标很明确:将单体拆分为松耦合、独立部署的微服务,并通过合理的架构设计提升系统的稳定性、可维护性与扩展性

技术选型回顾:

组件 用途
Nacos 注册中心 + 配置中心
Sentinel 服务限流、熔断降级
Dubbo + RestTemplate 远程调用协议
RocketMQ 异步消息通信
Seata 分布式事务
Spring Cloud Gateway 网关聚合

我们并没有一开始就全部引入,而是循序渐进地进行微服务拆分,初期仅使用了 Nacos + Sentinel + Dubbo,后期逐步引入 Seata 和 RocketMQ 等组件。


关键实践:一步步落地微服务架构

关键实践:一步步落地微服务架构

第一步:服务注册发现 + 配置管理

我们选择了 Nacos,它不仅是注册中心,还充当配置中心,这对运维非常友好。以前我们用 Spring Cloud Config 做远程配置,但要搭配 Git + Bus Refresh,体验上不如 Nacos 实时推送来的便捷。

示例:Nacos 客户端启动类配置

spring:
  cloud:
    nacos:
      discovery:
        server-addr: nacos-host:8848
      config:
        server-addr: nacos-host:8848
        extension-configs:
          - data-id: application-${spring.profiles.active}.yaml
            group: DEFAULT_GROUP
            refresh: true

我们在项目中统一使用 @RefreshScope 来实现动态配置更新,例如:

@Component
@RefreshScope
public class OrderConfig {

    @Value("${order.expire-time}")
    private int expireTime;

    // ...
}

小插曲:最开始上线时,Nacos 集群因为数据同步延迟导致部分服务无法获取配置。我们调整了心跳间隔并做了健康检查的兜底逻辑才解决。


第二步:服务治理:限流、熔断、降级

有了服务发现之后,下一步就是确保服务之间的调用是稳定的。我们采用了 Sentinel,结合 Dubbo 提供了非常好的保护机制。

示例:方法级熔断规则定义

@SentinelResource(value = "queryOrderDetail", fallback = "fallbackQuery")
public OrderDTO queryOrder(String orderId) {
    return orderService.getOrder(orderId);
}

// 降级方法
public OrderDTO fallbackQuery(String orderId, Throwable ex) {
    log.warn("触发订单服务降级");
    return new OrderDTO().setFallback(true);
}

Sentinel Dashboard 是个好工具,可以实时看到 QPS、异常数、响应时间等指标。我们在压测阶段利用它做热点参数限流,防止恶意刷单行为带来的冲击。


第三步:服务间通信的选择

我们最初尝试过 Feign + LoadBalancer,但在高并发场景下出现了连接池打满的情况,后来转向了 Dubbo + Netty 构建的服务调用体系,性能更加稳定。

Dubbo 在异步编程模型、线程池管理方面比传统 HTTP 更加灵活,也更适合 Java 微服务之间高性能通信的需求。

Dubbo 接口定义:

@DubboReference(retries = 2)
private UserService userService;

我们同时保留了基于 RESTful 的对外 API,采用 Spring Cloud Gateway 进行统一聚合路由。


第四步:异步解耦与分布式事务

为了处理库存扣减、积分变动、通知推送等跨服务协同的操作,我们引入了 RocketMQ

对于一些强一致性要求的场景,比如支付成功后扣库存、更新订单状态等,我们使用了 Seata 来实现 TCC 模式下的分布式事务。

示例:TCC 分段提交

@TwoPhaseBusinessAction(name = "deductStock")
public boolean deductStock(BusinessActionContext ctx);

@Commit
public boolean commit(BusinessActionContext ctx);

@Rollback
public boolean rollback(BusinessActionContext ctx);

刚开始用 Seata 时,经常出现全局事务未提交导致数据锁住。经过排查发现是某些服务节点宕机未能正确上报状态。后来我们对事务协调器做了 HA 改造,并增加了超时自动回滚机制,效果显著。


踩坑经验分享:那些深夜调试的小故事

1. Dubbo 泛化调用 vs 参数类型丢失

某次灰度发布后,线上订单服务偶尔会抛出 “NoSuchMethod” 的错误。排查发现是因为某个服务消费者使用的泛化调用(GenericService),而提供方新增了重载方法但未做好兼容处理。

解决办法:给所有泛化调用添加唯一标识符(如 methodKey),并确保版本号变更时兼容处理。


2. Sentinel 控制台与本地配置优先级混乱

有一次上线后,限流规则失效,原因是本地配置文件里设置了相同的资源名,覆盖了 Sentinel 控制台下发的规则。

建议做法:控制台应设为最高优先级;如果希望保留部分静态规则,需明确命名空间与隔离策略。


3. Nacos 集群脑裂问题导致服务不可用

初期我们只用两个 Nacos 节点做集群,后来在压测期间发现有“脑裂”现象,即一部分节点失联后仍然认为自己处于“Leader”,从而造成数据不一致。

解决方案:改用三个节点部署,启用 Raft 协议,并关闭短连接模式。


效果总结:架构升级带来的实际收益

性能层面:

  • 平均响应时间从 150ms 降至 60ms;
  • 支持更高并发请求,QPS 提升约 30%;
  • 同时支持多环境部署,测试/预发/生产互不影响。

运维层面:

  • 发布效率提升明显,服务可独立部署,滚动升级平滑;
  • 系统容错能力增强,即使部分模块故障也不会导致整体瘫痪;
  • 监控体系完整,通过 Prometheus + Grafana 实现服务健康可视化。

团队协作层面:

  • 模块清晰划分,团队分工更明确;
  • 新人接入成本降低,文档+SDK 使用指南足够支撑日常开发。

我的经验与建议:给正在微服务化的你

1. 不要一开始就把所有组件都搭起来

我见过太多项目上来就搞 Nacos + Sentinel + Seata + RocketMQ + Zipkin,结果连基础服务调用都没跑通。先聚焦核心链路,解决最痛的问题

2. 微服务不是银弹,不要过度拆分

业务边界模糊、数据强关联的服务强行拆分会带来更高的维护成本。要权衡拆分粒度协作成本之间的关系。

3. 日志监控体系建设要前置

我建议尽早引入 ELK + SkyWalking,尤其是日志分析和全链路追踪。它们在排查线上问题时作用巨大。

4. 注意接口设计的契约性与向前兼容

接口版本控制很重要,尤其在多人协作时。我们早期犯过接口返回字段直接删除的错误,导致下游系统大面积报错。后来统一使用 Protocol Buffer 或 JSON Schema 定义接口规范。


结语:技术是手段,不是目的

Spring Cloud Alibaba 是一套非常好用的微服务框架,尤其适合国内团队。它融合了很多阿里内部的最佳实践经验,具备很强的可用性和灵活性。

但我始终相信,再好的技术也是服务于业务需求的。在我参与的这个项目中,真正的挑战从来都不是“会不会用 Dubbo”、“能不能对接 RocketMQ”,而是在不断变化的需求中找到“架构的平衡点”。

如果你也在做类似的转型或者准备踏入微服务的世界,希望这篇文章能带给你一些启发和底气。愿你在编码的路上越走越远,代码越写越稳!


📌 如果你也有关于微服务的实战问题,欢迎留言交流,我可以结合自己的经验一起探讨。

评论 0

最热最新
暂无评论
匿名用户Lv.1
0
影响力
0
文章
0
粉丝