Spring Cloud 从零开始:一个真实微服务项目的起步与探索
引言:为什么我要写这篇文章

作为一名全栈开发工程师,这些年参与了不少前后端分离项目,但真正让我印象深刻的,是一个从零开始搭建的基于 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-service 的 application.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