从0到1:我在项目中使用 Spring Cloud Alibaba 的实战经验分享

半栈青年
2025-06-17 20:47
阅读 346

大家好,我是某互联网公司的一名后端架构师,平时主要负责微服务系统的架构设计和开发工作。今天我想聊聊自己在项目中实际使用 Spring Cloud Alibaba 的经历——包括我为什么选择它、遇到了哪些问题、如何解决的,以及最后取得的效果。

这篇文章不会是那种干巴巴的技术文档风格,而是一篇带有“人味儿”的技术分享。我会尽量用我们日常交流的口吻来写,把那些踩过的坑和走过的弯路讲清楚,希望对正在做微服务选型或者已经遇到瓶颈的同学有所帮助。

背景介绍:为什么我们要转向 Spring Cloud Alibaba?

背景介绍:为什么我们要转向 Spring Cloud Alibaba?

事情要回到两年前,我们团队在做一个面向B端用户的企业级平台,业务模块逐渐增多,系统拆分势在必行。最初我们采用的是 Spring Cloud Netflix 套件(Eureka + Feign + Ribbon + Zuul),这套组合在国内也相当流行,确实帮我们快速搭建起了一个初步的微服务体系。

但随着业务发展,几个问题开始浮现:

  • Netflix 组件维护停滞:比如 Eureka、Zuul 等已经很久没有重大更新;
  • 中文社区支持力度不够:很多国内特有的场景支持不足;
  • 分布式配置中心、限流熔断等功能缺失或实现复杂
  • 性能瓶颈显现:特别是在高并发场景下,Ribbon + Feign 的调用链略显冗长,响应时间偏慢。

这时候,阿里开源的 Spring Cloud Alibaba(SCA) 引起了我们的注意。它基于阿里巴巴内部多年的生产实践,整合了 Nacos、Sentinel、Seata、RocketMQ 等一系列成熟中间件,同时又完美兼容 Spring Cloud 标准接口,对我们来说是一个非常有吸引力的选择。

我们决定尝试逐步迁移至 SCA,并在一个新上线的子系统中完全使用它进行重构。接下来我将详细说说这个过程中遇到的挑战、解决方案,以及一些关键代码和经验教训。


遇到的主要挑战和问题

遇到的主要挑战和问题

1. 微服务注册发现不稳定

我们在测试环境中部署多个服务实例后,有时会出现服务注册失败、元数据不同步、服务调用方无法获取最新实例列表的情况。起初怀疑是网络问题,但在排查后确认是 Nacos Server 配置不当 导致的问题。

2. 分布式配置中心的同步延迟

我们使用了 Nacos Config 作为配置中心,初期为了图方便,把所有环境(dev、test、prod)都放在同一个 DataId 下区分命名空间。结果发现配置刷新不及时,甚至出现某些服务读取错误环境配置的情况,导致功能异常。

3. 接口限流和降级难以统一管理

原来的系统里我们用了 Hystrix 做服务降级,但由于 Hystrix 已经不再更新,加上粒度不够细,很多时候需要手动编写代码做兜底逻辑。而在迁移到 Sentinel 后,发现默认规则加载方式太死板,不能满足动态调整需求。

4. 数据一致性难保证

订单服务与库存服务之间存在跨服务的数据变更操作,我们需要引入分布式事务。之前试过本地事务+消息队列补偿机制,但运维复杂,出错后很难回滚。后来我们想试试 Seata,但上手成本较高,而且与数据库连接池、事务传播等机制有冲突。


我们采用的 Spring Cloud Alibaba 技术方案

我们采用的 Spring Cloud Alibaba 技术方案

面对这些问题,我们逐步完善了自己的技术栈,以下是最终采用的核心组件和策略:

组件 用途说明
Nacos 服务注册发现 + 配置中心
Sentinel 接口限流与熔断
Seata 分布式事务
OpenFeign + LoadBalancer 接口调用 + 负载均衡
RocketMQ 异步消息解耦

整体架构如下图所示(简化版):

[Gateway] --> [User Service] <--> [Order Service]
                    |                |
                    v                v
                  [Nacos Config]  [Sentinel Dashboard]
                          \         /
                           \       /
                            [MySQL + Seata RM]

这套架构既保留了 Spring Cloud 的生态兼容性,又能借助阿里系中间件带来的高性能和稳定性,是我们结合实际业务做出的折中选择。


关键代码实践和配置示例

下面我会挑几个比较核心的部分,给出代码片段和配置建议。

1. 使用 Nacos 注册服务

pom.xml 中添加依赖:

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

然后在 application.yml 中配置服务注册信息:

server:
  port: 8080
spring:
  application:
    name: order-service
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.1.100:8848 # 指定 Nacos 地址

启动类加上注解开启服务注册:

@SpringBootApplication
@EnableDiscoveryClient // 开启服务注册
public class OrderApplication {
    public static void main(String[] args) {
        SpringApplication.run(OrderApplication.class, args);
    }
}

这样你的服务就会自动注册到 Nacos 了。


2. 使用 Sentinel 实现限流降级

引入 Sentinel starter:

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

然后在 application.yml 中配置:

spring:
  cloud:
    sentinel:
      transport:
        dashboard: 192.168.1.101:8080 # Sentinel 控制台地址
      filter:
        enabled: true # 开启 Web 请求拦截

在 Controller 方法上加上限流注解:

@RestController
@RequestMapping("/order")
public class OrderController {

    @GetMapping("/{id}")
    @SentinelResource(value = "getOrderById", blockHandler = "handleBlockException")
    public ResponseEntity<Order> getOrderById(@PathVariable String id) {
        // 正常业务逻辑
        return ResponseEntity.ok(orderService.getOrder(id));
    }

    // 限流处理函数
    public ResponseEntity<String> handleBlockException(BlockException ex) {
        return ResponseEntity.status(HttpStatus.TOO_MANY_REQUESTS).body("请求频繁,请稍后再试");
    }
}

通过 Sentinel Dashboard 动态设置 QPS 规则,就可以轻松实现流量控制。


3. 使用 Seata 实现分布式事务

Seata 的集成相对麻烦一点,这里简要列出几个关键点:

  1. 添加 Seata Starter 依赖:

    <dependency>
        <groupId>io.seata</groupId>
        <artifactId>seata-spring-boot-starter</artifactId>
        <version>1.5.2</version>
    </dependency>
    
  2. 配置 Seata 客户端:

    seata:
      enabled: true
      application-id: ${spring.application.name} # 应用ID
      tx-service-group: my_tx_group # 事务组名称
      service:
        vgroup-mapping:
          my_tx_group: default # 映射TC集群
        grouplist:
          default: 192.168.1.102:8091 # TC地址
      config:
        type: nacos
        nacos:
          server-addr: 192.168.1.100:8848
          group: SEATA_GROUP
          data-id: seataServer.properties
    
  3. 在服务方法上添加全局事务注解:

    @GlobalTransactional
    public void createOrderWithDeductionInventory() {
        // 创建订单
        orderService.createOrder();
    
        // 扣减库存
        inventoryService.reduceStock();
    }
    

需要注意的地方是:必须使用 Seata 自带的数据源代理类(DataSourceProxy),否则事务不会生效。我们一开始没改数据源,导致 Seata 不起作用,排查了好久才发现。


4. 配置中心与环境隔离

为了避免多个环境配置混乱,我们为每个环境建立了单独的命名空间:

spring:
  cloud:
    nacos:
      config:
        server-addr: 192.168.1.100:8848
        extension-configs:
          - data-id: application.yaml
            group: DEFAULT_GROUP
            namespace: dev-namespace-id  # dev环境命名空间ID

命名空间ID可以在 Nacos 控制台中创建并获取,这样就能做到不同环境互不影响。


踩坑经验分享

这部分可能是最实用的内容,因为这些都是我在开发过程中真真切切踩过的坑,有些甚至是导致线上故障的。

✅ 坑一:Feign Client 默认不启用负载均衡

刚开始我们将服务调用从 RestTemplate 改为 Feign 时,发现调用的服务始终指向 localhost,而不是其他节点。后来才知道,默认情况下 Feign 并不会启用负载均衡,需要在配置中手动打开:

feign:
  client:
    config:
      default:
        http-replace-url: true
ribbon:
  eureka:
    enabled: false # 关闭原生 Eureka 负载均衡
loadbalancer:
  ribbon:
    enabled: false
spring:
  cloud:
    loadbalancer:
      enabled: true

同时需要确保引入了 spring-cloud-loadbalancer 这个包。

✅ 坑二:Sentinel Dashboard 无法持久化规则

我们当时每次重启 Sentinel Dashboard 都会丢失规则,调试了很久才发现默认规则存储是内存模式。需要修改 sentinel-dashboard 启动参数启用持久化:

-Dproject.name=sentinel-dashboard -Dcsp.sentinel.dashboard.server=localhost:8080 -Dcsp.sentinel.db.refresh=true

然后还需要在 Nacos 中创建相应的规则 DataId 和 Group,让 Sentinel 能够自动拉取和保存规则。

✅ 坑三:Seata 对数据库连接池的限制

我们使用的是 Druid 数据库连接池,在集成 Seata 时发现事务无法正常提交,报错信息显示“Branch session not found”。经过排查发现,Druid 默认开启了 autoCommit,而 Seata 要求整个事务保持手动提交状态。

解决办法是在 Seata 初始化时替换掉原始的 DataSource:

@Bean
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource druidDataSource() {
    return DataSourceBuilder.create().build();
}

@Bean
public DataSource dataSource(DataSource druidDataSource) {
    return new DataSourceProxy(druidDataSource); // 替换为Seata代理数据源
}

这个改动很小,但影响极大,建议所有使用 Seata 的同学一定要注意这一点。


效果总结:我们得到了什么

经过一段时间的稳定运行,我们明显感受到以下几个方面的提升:

  • 服务注册/发现更稳定:Nacos 的健康检查和容错机制比 Eureka 更加灵活,尤其是在多数据中心环境下;
  • 限流和熔断控制更加精细:Sentinel 提供了可视化界面,让我们可以随时调整规则,应急能力大大增强;
  • 配置管理更加清晰:不同环境独立配置,配合 RefreshScope 实现热更新,省去了很多重启的成本;
  • 分布式事务有了标准方案:Seata 成为我们解决跨服务数据一致性的首选工具,虽然初期学习曲线较陡,但一旦搭起来就很稳定;
  • 整体架构可扩展性增强:有了 Spring Cloud Alibaba 的支撑,后续接入更多中间件如 RocketMQ、Dubbo 等变得更加容易。

更重要的是,这些变化帮助我们顺利支撑了几次大促活动,扛住了突发的大流量冲击。


经验分享与建议

如果你也在考虑是否使用 Spring Cloud Alibaba 或者已经在路上,以下是我总结的一些经验和建议:

🧠 一、选型前务必明确业务需求

  • 如果你只需要基本的微服务功能,完全可以继续使用官方 Spring Cloud。
  • 如果你有高并发、强一致性、限流熔断等诉求,那么 Spring Cloud Alibaba 是更好的选择。

🔧 二、重视基础设施建设

  • 千万不要忽视 Nacos、Sentinel Dashboard、Seata Server 的部署和监控。
  • 这些组件不是附属品,而是整套体系的重要组成部分。做好它们的 HA、备份和日志收集工作至关重要。

📊 三、关注可观测性

  • 推荐集成 SkyWalking 或 Zipkin 等 APM 工具,监控服务调用链路,及时发现性能瓶颈。
  • Sentinel + Metrics + Prometheus + Grafana 是一套不错的组合。

🛠 四、规范和工具先行

  • 制定统一的编码规范,比如 Feign Client 的写法、Sentinel Rule 的命名方式等。
  • 搭建配置中心自动化脚本,避免手动操作带来风险。

结语:技术没有银弹,只有合适与否

最后我想说的是,技术方案没有绝对的好坏,只有适不适合。Spring Cloud Alibaba 在我们这个项目中发挥了很大作用,但也并不是所有场景都适用。

作为架构师,我们要做的不仅是选择合适的技术,更要理解它们背后的原理和局限,才能在关键时刻做出最优决策。

如果你也在使用 Spring Cloud Alibaba,欢迎留言交流;如果是刚刚接触,也可以告诉我你遇到的问题,我可以尽力帮你一起分析和解决。

技术这条路,大家一起走得更远。


作者:一名热爱架构设计与后端开发的技术工作者
联系方式:欢迎关注我的 GitHub / 微信公众号 @TechGrower
文章版本:2025年更新版,适用于 Spring Boot 2.7.x + Spring Cloud Alibaba 2021.x 及以上版本

(全文共约 3958 字)

评论 0

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