用 Spring Cloud Alibaba 撸一套稳定、可扩展的微服务架构

半杯咖啡写代码
2025-06-15 23:30
阅读 690

背景与起因:为什么我们会选择 Spring Cloud Alibaba?

事情要从去年说起。我们公司在那会儿正处于业务快速增长阶段,原来基于单体架构的系统已经明显力不从心了。响应变慢、功能迭代困难、部署风险大等一系列问题接踵而来。于是我们决定进行一次全面的技术重构,目标是将原来的系统拆分为多个微服务,并引入更成熟的分布式治理方案。

在调研主流技术栈的时候,Spring Cloud 的确是一个不错的选择,但随着深入分析我们的需求和团队情况,我们也发现一些痛点:

  • Spring Cloud Netflix(比如 Zuul、Ribbon)部分组件更新慢甚至进入维护状态;
  • 需要在国内环境下良好支持国产云生态(例如阿里云);
  • 希望集成消息队列、配置中心等常见基础设施时能有开箱即用的体验。

这时候我们就把目光转向了 Spring Cloud Alibaba(以下简称 SC Alibaba),这个由阿里开源并持续维护的微服务生态项目。

项目背景简述

服务器部署方案-1

项目背景简述

这次我们要重构的是一个电商中台系统,涉及商品管理、库存、订单、促销等多个核心模块。系统需要支持高并发、快速上线能力以及良好的监控运维手段。

我们的目标很明确:

  1. 实现服务之间的解耦与独立部署;
  2. 提升整体系统的稳定性;
  3. 构建一个可持续演进的基础平台。

整个项目大约由6个主要服务组成,每个服务采用 Spring Boot 构建,配合 Nacos 作为注册中心和服务配置中心,Dubbo + Feign 两种方式做服务间通信,Sentinel 控制流量降级熔断,Seata 处理分布式事务。

可以说,我们几乎使用到了 SC Alibaba 的“全家桶”。

遇到的挑战与问题

遇到的挑战与问题

尽管 Spring Cloud Alibaba 文档齐全,社区活跃,但在生产实践中我们还是遇到了不少坑。下面我重点讲几个最影响项目推进的关键问题。

1. 注册中心选型之困:Eureka?Consul?还是 Nacos?

我们在早期尝试过 Eureka,结果发现它的延迟较高,尤其在集群节点变更时,服务列表更新不及时,容易导致调用失败;Consul 性能不错,但安装部署复杂,对于我们想迅速上线的目标来说略显拖沓。

最后选定 Nacos,不仅因为它可以同时满足注册中心 + 配置中心的能力,而且和 Dubbo 亲和性特别好。更重要的是,它在国内的应用非常广泛,文档丰富,社区活跃。

不过刚上手时,Nacos 的一些机制不太直观,比如健康检查、临时实例 vs 持久化实例的区别,都让我们走了点弯路。

2. 服务间通信的抉择:Feign 还是 Dubbo?

刚开始我们统一用了 Feign 做远程调用,毕竟它是 Spring Cloud 的标准做法,写法简单、集成方便。但随着业务复杂度提升和调用量增大,出现了两个比较明显的问题:

  • 性能瓶颈:Feign 底层依赖 HTTP 协议,在频繁的内部调用中会带来一定延迟;
  • 协议约束:HTTP 接口定义不够严格,服务提供方与消费方容易因为参数格式问题出错。

后来我们做了折中处理:关键服务之间采用 Dubbo + Protobuf 的 RPC 调用模式,非核心、外部调用继续保留 Feign,这样既保证了核心路径的性能,也保留了开发上的灵活性。

3. 分布式事务难题:如何处理跨服务操作?

举个例子:当用户下单的时候,订单服务要创建订单,同时库存服务需要扣减库存,这两个操作必须要么一起成功,要么一起回滚。

我们一开始尝试的是本地事务+消息最终一致性,但实现起来太复杂,尤其是在网络异常或服务宕机的情况下,经常会出现数据不一致的问题。

后来引入了 Seata,通过 AT 模式实现了对数据库的全局事务控制。虽然初期搭建 Seata Server 有一些配置细节需要注意,但一旦跑通之后,代码侵入性并不大,对开发人员比较友好。

4. 熔断限流怎么做?Hystrix 不再推荐!

我们知道 Hystrix 已经不再更新,而 Spring Cloud Gateway 自带的限流也不是那么灵活。这个时候我们选择了 Sentinel,这是阿里巴巴出品的一款轻量级的限流降级中间件,支持 QPS 限制、线程隔离、热点防护等功能。

但真正开始集成 Sentinel 到生产的时候,我们才发现:

  • 默认的规则保存在内存里,重启后就没了;
  • 生产环境下必须结合持久化 + 动态推送机制;
  • DashBoard 只是辅助工具,不能直接用于动态下发规则。

我们最终的解决方案是:自己搭了一套基于 Nacos 的规则同步逻辑,配合 Sentinel Dashboard 来做实时查看,从而达到了动态配置 + 持久化的双重能力。


我们的解决方案设计

我们的解决方案设计

基于上面提到的各种挑战,我们的架构大致如下图所示:

┌──────────┐       ┌─────────────┐
│ 用户请求 │──────▶│ API Gateway │
└──────────┘       └─────────────┘
                              │
         ┌────────────────────┴────────────────────┐
         ▼                    ▼                   ▼
   ┌─────────┐      ┌─────────────┐     ┌────────────┐
   │ 订单服务 │────▶│ 商品服务    │────▶│ 库存服务   │
   └─────────┘      └─────────────┘     └────────────┘
         │                    │
         ▼                    ▼
  ┌────────────┐     ┌─────────────┐
  │ 支付服务   │────▶│ 优惠券服务  │
  └────────────┘     └─────────────┘

整个体系围绕着以下几大核心组件构建:

组件名 功能
Nacos 服务注册中心 + 配置中心
Sentinel 流量控制、降级、热点防护
Seata 分布式事务协调器
Dubbo / Feign 服务间通信
RocketMQ / Kafka 异步消息通知

此外,所有服务的日志统一接入 ELK,链路追踪则采用 SkyWalking,加上 Grafana + Prometheus 做监控告警,整个体系才算闭环。


核心代码实践示例

下面分享一些真实项目中的代码和配置片段,帮助你了解如何快速搭建这些组件。

1. Nacos 注册中心配置(application.yml

server:
  port: 8080

spring:
  application:
    name: order-service
  cloud:
    nacos:
      discovery:
        server-addr: nacos-server:8848
      config:
        server-addr: nacos-server:8848
        file-extension: yaml
        namespace: your-namespace-id  # 如果开启了命名空间
        extension-configs:
          - data-id: common.yaml
            group: DEFAULT_GROUP
            refresh: true

2. Sentinel 熔断配置(Java 配置类)

@Configuration
public class SentinelConfig {
    
    @PostConstruct
    public void init() {
        // 为某个资源设置默认降级策略
        DegradeRuleManager.loadRules(Collections.singletonList(
            new DegradeRule("order-create")
                .setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO)
                .setCount(0.5) // 错误率超过50%就熔断
                .setTimeWindow(30) // 熔断时间窗口30秒
        ));
    }
}

3. Seata 全局事务入口(Controller 示例)

@RestController
@RequiredArgsConstructor
public class OrderController {

    private final OrderService orderService;

    @PostMapping("/order")
    @GlobalTransactional // 开启全局事务
    public Result createOrder(@RequestBody CreateOrderDTO dto) {
        return Result.success(orderService.create(dto));
    }
}

注意:Seata 要求数据库表加行锁支持,且 undo_log 表结构要手动创建。

4. Dubbo RPC 接口定义

// 接口定义
@DubboService
public class InventoryServiceImpl implements InventoryService {
    @Override
    public boolean deductStock(String productId, int quantity) {
        // 扣减逻辑
    }
}

// 消费方调用
@DubboReference
private InventoryService inventoryService;

踩过的坑 & 经验总结

服务器部署方案-2

这里我想分享一下那些让我熬夜加班的小坑,希望你能少走些弯路。

1. Nacos 本地缓存失效引发服务不可达

有一次发布新版本服务后,旧版本的服务被下架了,但新的服务启动得很慢,导致网关还在尝试调用旧服务,结果出现大量超时错误。

后来排查发现是因为 Nacos 客户端开启了本地缓存(出于性能考虑),但未开启自动刷新,这就导致客户端没有及时感知到服务变动。

解决办法是:

spring.cloud.nacos.discovery.
  ephemeral: true # 临时实例,便于故障清理
  metadata:
    preservestaticfilecache: false # 关闭静态缓存

同时建议在部署脚本里加入等待探针健康的逻辑,避免服务启动完成前就被注册。

2. Dubbo 启动报 “No provider available” 问题

这个问题在我刚迁移到 Dubbo 的时候出现得特别多,原因其实很简单——消费者比提供者先启动了,无法发现服务。

为了避免这种问题,我们做了两件事:

  • 在 Kubernetes 中为 Dubbo 服务设置 readiness probe,确保服务完全初始化后再开放流量;
  • 使用 dubbo.application.name 做服务分组管理,避免混淆不同环境的服务。

3. Sentinel 规则未持久化导致重启丢失

早期测试环境中我们只是通过 Sentinel Dashboard 添加了几个规则,没做持久化存储,结果每次服务重启规则都没了。

后来我们采用了一个基于 Nacos 的 Sentinel Rule Push 方案:

  • Sentinel DashBoard 改造成可以从 Nacos 读取配置;
  • 所有规则保存在 Nacos DataID 中;
  • Sentinel 客户端监听该 DataID,实现规则热加载。

这对我们后续的灰度发布和弹性伸缩也非常有用。


最终效果与收益

自从这套架构上线以来,我们的整体系统表现稳定多了,尤其是在双十一这类大促期间也没有出现重大故障。

具体收益如下:

维度 改善
平均响应时间 从 800ms 降低至 300ms 内
服务可扩展性 可随时横向扩容新服务副本
上线速度 模块化后,功能上线周期缩短 50%
故障隔离 出现问题基本定位明确,影响范围可控
运维效率 基于 Sentinel+Nacos 的配置中心节省了大量重复工作
团队协作 接口边界清晰,联调对接更顺畅

给新手的一些建议

如果你也打算用 Spring Cloud Alibaba 做架构设计,下面几点建议或许对你有帮助:

✅ 把 Nacos 当成标配来用

无论是注册中心还是配置中心,Nacos 都提供了极强的易用性,值得投入精力去掌握。特别是配置中心 + 动态刷新的功能,是未来服务自治的重要组成部分。

✅ 微服务通信方式要合理选用

  • 小规模、轻量级交互优先用 Feign;
  • 高并发、低延迟场景建议上 Dubbo;
  • 对接口强类型要求的可以用 Protobuf + Dubbo;
  • 外部调用建议保留 RESTful,兼容 OpenAPI。

✅ 别急着上 Seata,除非真的需要

Seata 的确强大,但也增加了不少复杂度。如果你的业务可以通过本地事务 + MQ 做最终一致性,就没必要一开始就搞分布式事务。

✅ 监控、日志、链路跟踪要尽早规划

别等到系统出问题再去补这些东西。越早整合 SkyWalking、Prometheus 和 ELK,越早发现问题、优化性能。

✅ 结合 Kubernetes 做容器化部署更有优势

SCA 的各个组件天然适配 K8s,你可以用 Operator 方式部署 Nacos、Sentinel Dashboard,甚至 Seata Server,大大简化了部署流程。


写在最后:关于技术选型的感悟

说实话,Spring Cloud Alibaba 并不是银弹,它只是一个工具集合。真正决定成败的,是我们如何理解业务、规划架构、设计服务边界、保障线上运行。

记得项目上线前夜,我和同事盯着监控面板反复刷屏看 QPS 和成功率,心里七上八下的。那一刻才深刻体会到,“稳定压倒一切”,不是一句口号,而是实打实的经验教训。

希望这篇实战经验文章能帮你在踏上微服务之路前,看清一些可能的坑,找到一些合适的答案。也希望我们能在未来的项目中共同成长!

欢迎留言交流你的微服务实践心得,一起进步!

评论 0

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