Spring Cloud 从零开始:一个真实微服务项目的起步与探索

代码与远方
2025-06-28 22:46
阅读 717

引言:为什么我要写这篇文章

引言:为什么我要写这篇文章

作为一名全栈开发工程师,这些年参与了不少前后端分离项目,但真正让我印象深刻的,是一个从零开始搭建的基于 Spring Cloud 的微服务架构系统。这个项目一开始只是一个小模块,后来因为业务扩展迅速演变成一个多服务、多环境的中型系统。在这个过程中,我们踩了不少坑,也积累了宝贵的经验。

这篇文章我将用第一人称的方式,和你分享那段从无到有搭建微服务架构的真实经历,包含项目背景、遇到的问题、解决过程,以及一些关键代码片段和运维建议。希望能给正在或者准备踏入 Spring Cloud 领域的朋友提供一些参考和启发。


项目背景:为什么需要微服务?

项目背景:为什么需要微服务?

那是在一家初创电商公司,初期我们的后端系统是单体应用(Spring Boot + MySQL),前端则是 Vue.js 单页应用。随着业务增长,订单、库存、用户、支付等模块之间耦合严重,改一个小功能都要牵一发动全身。特别是发布上线时经常出问题,排查也很困难。

老板拍板要做服务化改造,目标很明确:

  • 模块解耦,便于团队并行开发
  • 提高系统的可维护性和可扩展性
  • 为后续云原生部署打基础

于是,Spring Cloud 成为了我们的首选方案。


遇到的问题与挑战

在真正开始之前,我做了不少技术调研,对比了几个主流的微服务框架,比如 Dubbo 和 gRPC,最终还是选择了 Spring Cloud Alibaba(Nacos) 方案。以下是我们在落地过程中遇到的核心问题:

1. 服务注册发现怎么做?选 Eureka 还是 Nacos?

起初想用 Eureka,毕竟 Spring 官方推荐,社区成熟。但在实际测试中发现:

  • Eureka 不支持配置中心
  • 健康检查不如 Nacos 精细
  • 后续如果要结合 Sentinel、Gateway 等组件,生态不够统一

所以我们转向了 Nacos,它同时支持服务注册和服务配置管理,集成起来更方便。

2. 多个服务间如何通信?Feign 还是 OpenFeign?还是 RestTemplate?

最开始用的是 RestTemplate,手动调用接口,写了很多重复代码不说,服务地址还需要硬编码,极其不便。

后面我们换成了 OpenFeign,配合 Ribbon 做客户端负载均衡,实现服务间的远程调用,大大减少了网络处理的复杂度。

小插曲:刚开始 Feign 报错“LoadBalancerException”,查了半天才发现是没有引入 spring-cloud-starter-loadbalancer,真是汗颜。

3. 接口权限如何统一处理?网关 Gateway vs Zuul

我们考虑过 Zuul,但由于其性能和更新缓慢的问题,最后选择了 Spring Cloud Gateway。它基于 Netty,非阻塞 IO,适合高并发场景。

结合 OAuth2 实现了统一鉴权,所有请求都经过网关验证 token 合法性后再路由到下游服务。

4. 日志追踪怎么办?有没有像样的链路追踪工具?

这个问题一度让我们头疼。多个服务调用链交错,出了问题是很难定位到具体哪个环节的问题。后来我们引入了 Sleuth + Zipkin,实现了完整的请求链路追踪。


我们的技术选型方案

综合以上问题,我们确定了如下的技术栈:

组件 技术选型 说明
服务注册发现 Nacos Server 支持配置管理,生态丰富
服务通信 OpenFeign + Ribbon 简洁高效的声明式调用方式
网关路由 Spring Cloud Gateway 性能好、易于扩展
链路追踪 Sleuth + Zipkin 完整的调用链分析
分布式配置 Nacos Config 与注册中心统一,管理方便
限流熔断 Sentinel 支持实时监控和规则动态调整
数据库 MySQL + MyBatis Plus 主流搭配,ORM 层开发效率高

项目结构设计与实践

整个项目采用 Maven 多模块结构组织如下:

spring-cloud-demo/
├── common/                  # 公共工具类、常量、异常封装
├── config-center/             # 配置文件抽取,用于本地调试
├── gateway/                   # 网关模块,负责路由转发与鉴权
├── user-service/              # 用户服务模块
├── order-service/             # 订单服务模块
├── product-service/           # 商品服务模块
├── nacos-server/              # Nacos 服务器(Docker部署)
└── zipkin-server/             # Zipkin 服务器(Docker部署)

每个微服务通过独立数据库支撑,避免数据共享带来的耦合问题,这也是微服务设计中一个核心原则。


核心实现与关键代码示例

1. Nacos 服务注册与发现

user-serviceapplication.yml 中添加以下内容:

server:
  port: 8081

spring:
  application:
    name: user-service
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848

在启动类上加上注解即可完成注册:

@EnableDiscoveryClient
@SpringBootApplication
public class UserServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(UserServiceApplication.class, args);
    }
}

2. Feign 接口远程调用

定义 Feign Client:

@FeignClient(name = "order-service")
public interface OrderServiceClient {

    @GetMapping("/orders/{userId}")
    List<Order> getOrdersByUserId(@PathVariable("userId") Long userId);
}

调用方式很简单,在 Controller 或 Service 中注入该 client 即可使用。

3. 网关路由配置

gateway 模块中的 application.yml

spring:
  cloud:
    gateway:
      routes:
        - id: user-service
          uri: lb://user-service
          predicates:
            - Path=/users/**
          filters:
            - StripPrefix=1

        - id: order-service
          uri: lb://order-service
          predicates:
            - Path=/orders/**
          filters:
            - StripPrefix=1

这样就可以实现 /users/** 路由到用户服务,去掉前缀进行匹配。

4. 链路追踪整合 Sleuth + Zipkin

只需在 pom.xml 中加入依赖:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-sleuth-zipkin</artifactId>
</dependency>

再配置一下 Zipkin 地址即可:

zipkin:
  base-url: http://localhost:9411
sleuth:
  sampler:
    probability: 1.0  # 采样率设置为100%

访问 Zipkin 页面可以看到完整调用链。


开发过程中的一些“坑”和解决方案

坑一:Feign 调用失败,“No instances available for service…”

这是典型的负载均衡器无法找到对应实例的问题。原因可能是:

  • Nacos 服务未正常注册
  • 服务名称拼写错误或大小写不一致
  • Ribbon 缓存导致没有及时刷新实例列表

解决方案: 检查服务是否已成功注册到 Nacos,并确保服务名准确无误;可以尝试重启服务或清除 Ribbon 缓存。

坑二:Gateway 网关在 Linux 上启动报错“No such file or directory”

是因为某些系统路径兼容问题导致。Spring Boot 应用在 Windows 下运行没问题,到了 Linux 环境却报错,原因是某个 shell 脚本或日志目录权限问题。

解决方案: 统一用 Docker 容器化部署,或者在启动脚本里明确指定工作目录和日志路径。

坑三:Zipkin 链路信息丢失,部分请求没出现在追踪界面

这是因为默认采样率不是 100%,在测试环境中我们应改为 1.0:

sleuth:
  sampler:
    probability: 1.0

效果总结:服务化后的变化

从最初的一个单体项目到现在拆分成 5 个服务,虽然开发工作量增加了,但在以下几个方面有了明显提升:

  • 开发效率提高:各模块独立开发部署,互不影响
  • 运维成本下降:服务故障时影响范围可控
  • 弹性扩展增强:热点服务可按需扩容
  • 线上排障效率提升:借助 Zipkin 快速定位问题
  • 团队协作更顺畅:不同团队维护不同服务,职责明确

更重要的是,整个架构具备向 Kubernetes 平滑迁移的基础能力。


给读者的经验与建议

如果你也在考虑或者正在构建自己的微服务系统,以下几点建议希望对你有所帮助:

✅ 微服务不是银弹,先搞清楚为什么要服务化

别被“微服务”这个词冲昏头脑。一定要从业务出发,看看当前是否真的存在服务治理的痛点。否则单体应用反而更简单高效。

✅ 服务拆分要小步快跑,不要急于求成

我们当初试图一次性把系统完全拆开,结果带来很多混乱。建议采取渐进式拆分,先提取出核心独立模块(比如订单、用户),逐步过渡。

✅ 技术选型要统一生态,减少杂糅

Spring Cloud Alibaba 的生态系统非常强大,尤其是整合了 Sentinel、Nacos、Seata 等,建议优先选择它们,不要轻易掺杂其他框架。

✅ 关注分布式事务与一致性问题

微服务下数据库分散后,跨服务数据一致性是个大问题。我们当时只做了一半就遇到了转账失败回滚难题。建议尽早评估是否需要引入 Seata 这样的分布式事务框架。

✅ 监控与日志体系必须同步建立

服务多了以后,光靠日志文件去查问题是不行的。建议一开始就引入链路追踪(如 Zipkin)+ 日志聚合(ELK)+ 实时监控(Prometheus + Grafana)。


写在最后

这是我亲身经历的一次微服务架构转型的过程。它不是完美无缺的,中间也走过弯路,但从结果来看确实带来了实实在在的收益。如果你也在学习 Spring Cloud,我鼓励你动手搭建一个小项目试试看,从注册中心到 Feign 调用再到 Gateway 路由,一步步来,你会发现它的魅力所在。

微服务之路或许漫长,但我相信,只要你愿意坚持走下去,终将收获属于自己的那一份自由与掌控。


作者简介
我是老胡,一名热爱技术、热衷于折腾的全栈开发者,喜欢把复杂的知识讲得简单易懂。欢迎关注我的博客或者 GitHub,一起交流学习。

评论 0

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