从零开始,用 Spring Cloud 构建第一个微服务系统 —— 我的实战之路
开篇:为什么选择写这样一篇文章?

去年我在公司参与了一个全新的项目,背景是一个大型电商平台要进行整体架构升级。之前所有的功能都跑在一个单体应用中,部署复杂、版本迭代慢、故障隔离差。于是团队决定转向微服务架构,使用 Spring Cloud 作为技术栈。
这对我们来说是一次全新的尝试。我负责整个后端的架构设计和核心模块开发,过程中踩了不少坑,也收获了很多宝贵的经验。今天想借这篇文章,结合真实的项目经历,跟大家聊聊如何从零开始搭建一个 Spring Cloud 的微服务系统。
希望它不仅仅是一份技术文档,更像是一位老程序员在茶余饭后的分享。如果你是刚开始接触微服务的新手,或者正在规划类似的系统,这篇文章或许能帮你少走些弯路。
项目背景介绍

这个项目的目标是为平台重新构建用户中心、商品中心和订单中心三个核心模块,并逐步从单体迁移到微服务架构。
当时我们面临几个关键问题:
- 不同业务模块之间存在较强的依赖关系
- 原有的单体系统已经难以支撑日益增长的流量
- 缺乏统一的服务治理机制
- 各个业务模块的技术栈差异大,维护成本高
考虑到未来扩展性和团队的技术积累,我们最终选定了基于 Spring Boot + Spring Cloud 的技术方案,并决定以 Nacos 作为注册中心和服务配置中心,Ribbon 做客户端负载均衡,Feign 实现服务通信,加上 Gateway 做网关路由。
挑战一:如何迈出第一步?“微服务”到底怎么拆分?
最开始摆在我们面前最大的问题是——服务该怎么拆?
很多人以为只要把各个模块打成不同的 jar 包就叫微服务了,其实这只是表面功夫。我们当时的误区就是直接照搬原来的包结构,导致服务间调用混乱,接口定义不清晰。
比如原来的系统里,用户和订单是放在同一个数据库中的,现在如果只是简单地切分成两个微服务,那订单服务访问用户信息时就要跨服务调用了。但如果没有一个好的远程调用方式和服务治理机制,整个系统的性能和可靠性都会大打折扣。
我们总结出一套实践方法:
- 先做业务领域的划分(DDD 领域驱动设计的思想),确保每个服务职责单一;
- 设计好服务之间的边界和接口规范,不能出现循环依赖;
- 尽量避免共享数据表,除非有强一致性需求;
- 优先考虑 API 兼容性设计,方便后续升级。
举个例子,我们在定义用户和订单的交互时,只暴露用户的基本信息查询接口,而不是直接让订单服务去访问用户的数据库。这样既保持了解耦,也能在将来引入缓存或权限控制时不改动下游服务。
技术方案选型与搭建思路
确定好服务划分之后,我们就开始搭建基础设施了。
注册中心选型:Nacos 还是 Eureka?
我们一开始尝试过 Netflix 的 Eureka,发现它在服务健康检查上不够灵活,而且 UI 功能比较简陋。后来试了阿里开源的 Nacos,发现它除了注册中心之外还集成了配置中心的功能,可以动态更新配置而无需重启服务,这对我们的运维非常友好,于是决定采用。
服务间的通信:Feign 还是 RestTemplate?
我们最初用的是 RestTemplate,写起来很繁琐,还要自己处理负载均衡和异常。后来改用 Feign,配合 Ribbon 使用后,代码简洁很多,也更容易管理。
@FeignClient(name = "user-service")
public interface UserServiceClient {
@GetMapping("/users/{id}")
User getUserById(@PathVariable Long id);
}
这就是一个典型的服务调用接口。通过 @FeignClient 直接声明对哪个服务发起调用,接口方法会自动被包装成远程调用。
不过要注意的是,Feign 默认使用 JDK 的 HttpURLConnection,性能一般。我们在生产环境中换成了 Apache HttpClient 来提升性能。
网关的选择:Spring Cloud Gateway
我们最终选用的是 Spring Cloud Gateway,它是官方推荐的网关组件,底层使用 WebFlux 和 Reactor,支持异步非阻塞处理。
我们在网关层做了以下几件事:
- 统一路由配置(避免服务暴露细节)
- 请求鉴权、限流、日志记录等横切关注点
- 多版本 API 路由支持(灰度发布基础)
例如,下面是网关的一个简单路由配置:
spring:
cloud:
gateway:
routes:
- id: user-service
uri: lb://user-service
predicates:
- Path=/api/users/**
filters:
- StripPrefix=1
这段配置表示,所有请求 /api/users/** 的路径都会被路由到 user-service,并去掉前缀。
代码实践:搭一个简单的微服务结构
下面我会展示一下我们搭建的第一个微服务示例,包括注册中心 Nacos Server、用户服务、订单服务以及网关的启动类和关键配置。
用户服务启动类
@SpringBootApplication
@EnableDiscoveryClient
public class UserServiceApplication {
public static void main(String[] args) {
SpringApplication.run(UserServiceApplication.class, args);
}
}
Feign 客户端调用订单服务
@FeignClient(name = "order-service")
public interface OrderServiceClient {
@GetMapping("/orders/user/{userId}")
List<Order> getOrdersByUserId(@PathVariable("userId") Long userId);
}
Nacos Server 启动命令(简化版)
sh startup.sh -m standalone # 单机模式启动 nacos-server
踩坑经验分享:那些年我们掉过的坑
任何技术落地都不是一帆风顺的,特别是微服务这种复杂的体系结构,更是充满了“惊喜”。
1. 服务注册失败?别忘了网络问题!
有一次上线新服务时,服务总是注册不到 Nacos 上。排查半天发现是因为服务器防火墙限制了 Nacos 的端口,导致服务无法正常连接。
建议: 在部署初期就把相关端口全部开放,并且在服务日志中加入注册状态的日志,便于排查。
2. Feign 调用超时怎么办?
我们在测试阶段遇到一个问题:某个服务调用另一个服务时经常超时,但是单独测试目标服务又是正常的。
最后发现,默认的 Feign 超时时间只有几秒,而在高并发下,某些服务响应较慢,就会触发超时。
解决办法:
在 application.yml 中增加如下配置:
feign:
client:
config:
default:
connectTimeout: 5000
readTimeout: 10000
3. 分布式事务怎么办?我们选择了“妥协”
由于微服务之间数据库是独立的,所以在订单创建需要同时操作用户余额和库存这两个服务时,遇到了一致性问题。
我们没有立即上分布式事务框架(如 Seata),因为担心引入更多复杂性。最后采取了一个折中策略:
- 订单创建先记录预扣库存和用户冻结金额(通过乐观锁)
- 异步补偿机制定期比对数据,发现问题及时修复
- 提供人工干预工具处理极少数异常情况
虽然不是完美的 ACID,但在实际场景中足够应对绝大多数情况,还能保证高性能。
效果总结:微服务真的带来了哪些改变?
经过半年多的开发和优化,整个平台完成了初步的微服务化改造。效果还是很明显的:
- 部署更加灵活:每个服务可以独立部署、回滚、扩缩容
- 故障隔离性增强:某一个服务宕机不会影响整个平台
- 运维效率提升:通过网关统一接入,监控报警也更集中
- 版本迭代更快:不同服务并行开发,减少了协作阻力
当然也有代价,比如:
- 初期学习曲线陡峭,团队花了大量时间研究各种组件
- 日志聚合、链路追踪等配套设施也需要同步完善
- 测试环境需要模拟多个服务共存的状态,增加了复杂性
但从长远来看,这些投入是值得的。
经验分享:给新手的一些建议
如果你也打算开始自己的微服务项目,这里是我的一些肺腑之言:
1. 别一上来就搞全套组件,先跑通最基本的服务注册/发现就够了
我们一开始把 Sentinel、Sleuth、Zipkin、Config Server 都集成进去,结果调试花的时间比写业务逻辑还长。
建议做法: 先搞定 Nacos + Feign + Gateway 这三件套,等服务能跑通再说下一步。
2. 接口设计一定要慎重,不然以后改起来太痛苦
我们最早在用户服务上提供的一个接口是返回所有用户字段的 UserVO,但随着业务发展,有些服务只需要部分字段,结果不得不加参数区分,甚至重构了多个版本。
建议做法: 接口按需设计,返回结构尽可能细化,提供多种接口组合,避免大而全的数据传输对象。
3. 日志和监控必须前置考虑,否则后期补救很麻烦
刚开始我们没怎么在意日志输出格式,结果到了生产环境排查问题时完全抓瞎。
建议做法:
- 统一日志格式(比如 JSON 格式)
- 加入 traceId、spanId 等链路信息(可通过 Sleuth 自动注入)
- 使用 ELK 收集日志,用 Prometheus 做指标监控
- 配合 Grafana 展示服务运行状态
结语:微服务不是银弹,但值得深入
写了这么多,其实也只是抛砖引玉。微服务的世界远比我们想象的复杂,每一个组件背后都有大量的知识等待我们去挖掘。
对我来说,微服务不仅是一种架构风格,更是一种组织思维的转变。它教会我们如何拆分责任、如何协同作战、如何快速交付价值。
如果你也在尝试这条路,记得不要急着追求“炫技”,先把最基本的稳定性、可维护性和可观测性做好。等你真正驾驭了微服务这套体系,你会发现——它真的是现代互联网架构的基石。
感谢你读到这里。如果这篇文章能帮你在微服务的路上少走一段弯路,那我的分享就有意义了。
加油吧,朋友们!

评论 0