Spring Cloud 从零开始:我的微服务成长之路
引言:为什么选择 Spring Cloud 来构建微服务?

去年公司接了一个比较大的项目,目标是重构一个已经运行了多年的单体应用。这个老系统是 Java 技术栈写的,业务模块之间耦合严重,部署和上线周期长,每次改动一个小功能都要提心吊胆地回归测试一轮。
随着用户量的快速增长,我们明显感觉到传统单体架构在性能、可维护性以及团队协作方面越来越吃力。技术总监提出要转向微服务架构,并且优先考虑使用 Spring Cloud 去实现。
说实话,当时我内心是有点抵触的 —— 毕竟 Spring Cloud 那么多组件(Eureka、Feign、Gateway、Config、Sleuth…),光是记名字都觉得头疼。再加上没有实际落地的经验,很多问题听起来都知道原理,但真动手时才发现根本不是那么回事。
不过也正是这段经历,让我从最初的懵懂到现在能够独立规划整套微服务架构,也积累了不少实战经验和踩过的坑。这篇文章我就结合自己参与的实际项目,和大家分享一下 Spring Cloud 从零搭建微服务的心路历程。
项目背景:老系统拆分的艰难转型

我们要重构的是一个电商平台的核心系统,包括用户中心、订单系统、商品中心、支付服务等多个模块。原系统代码行数超过百万级,数据库有几百张表,每天处理几万订单。
虽然代码结构混乱,但系统的稳定性要求极高,任何改造都不能影响线上业务的正常运作,因此必须采用灰度方式逐步拆分,而不是推倒重来。
我们在内部成立了“微服攻坚小组”,目标是用半年时间将核心业务拆分为独立的微服务,并基于 Spring Cloud 实现服务注册发现、统一网关路由、链路追踪等功能。
第一阶段:微服务拆分与基础架构搭建
初期挑战:服务怎么拆?粒度太粗 or 太细?
第一个问题就是 服务如何拆分。我们的做法是以业务边界为单位进行划分,比如:
- 用户相关功能 → user-service
- 商品管理 → product-service
- 订单逻辑 → order-service
- 支付对接 → payment-service
这一步其实是最难的,因为有些功能横跨多个领域,比如库存系统既服务于订单,又服务于商品展示。最后我们决定采用“先大后小”的策略,把通用能力抽出来作为公共服务。
另外还有一个误区就是刚开始就把服务拆得特别细,导致后续维护成本飙升。经验告诉我们:初期保持适中粒度,根据实际负载再进一步细分。
技术选型:Spring Boot + Spring Cloud 的组合拳
我们选择的是 Spring Boot + Spring Cloud 的技术栈,理由很简单:
- 团队熟悉 Java 和 Spring,学习曲线低;
- 社区活跃,文档齐全;
- 各个组件配合良好,开箱即用;
- 真实大规模生产案例众多。
注册中心的选择:Eureka 还是 Nacos?
最初我们选用了 Netflix 的 Eureka 作为服务注册中心,但后来被阿里开源的 Nacos 完美取代。原因有三:
- Nacos 自带配置中心功能,省去了额外引入 Spring Cloud Config;
- 支持 DNS 和 API 多种服务发现方式,扩展性强;
- 可视化控制台更友好,运维同学表示好评。
现在回过头来看,如果项目一开始就使用 Nacos,可能能少走不少弯路。
接口设计:RESTful 是基本标准
为了保证各个服务之间通信清晰,我们统一使用 RESTful API,通过 Swagger UI 文档化接口。每新增一个服务,都需要提供一份完整的 OpenAPI Spec,方便前端和其他服务对接。
接口设计上遵循以下几点原则:
- 路径命名清晰表达语义(例如:
GET /api/v1/order/{id}); - 使用标准 HTTP 方法(GET/POST/PUT/DELETE);
- 统一错误返回格式,包含
code,message,data; - 所有请求都经过 Gateway(后面会讲到)做鉴权和限流。
第二阶段:微服务治理能力建设
挑战 1:服务调用怎么保障可靠性?
服务拆分以后,A 调 B 成了常态。最开始我们直接用 RestTemplate 发起调用,结果一旦某个服务慢下来或挂掉,整个调用链就会雪崩式失败。
为了解决这个问题,我们引入了 Feign + Hystrix:
- Feign 提供声明式客户端调用,简化开发;
- Hystrix 提供熔断降级机制,保护系统不崩溃。
举个小例子,假设用户服务调用订单服务获取最近订单:
@FeignClient(name = "order-service")
public interface OrderServiceClient {
@GetMapping("/orders/latest")
List<Order> getLatestOrders(@RequestParam String userId);
}
然后在调用的地方设置 fallback:
@GetMapping("/user/{userId}")
public UserWithOrders getUserWithOrders(@PathVariable String userId) {
try {
return new UserWithOrders(user, orderServiceClient.getLatestOrders(userId));
} catch (Exception e) {
// fallback 返回默认值或缓存数据
return new UserWithOrders(user, Collections.emptyList());
}
}
不过 Hystrix 已经不再更新了,现在我们正在迁移到 Resilience4j,它更轻量,也更容易集成到 Spring 中。
挑战 2:调用链跟踪怎么做?
微服务环境下,一个用户请求可能会涉及多个服务调用,排查问题变得异常困难。我们采用了 Spring Cloud Sleuth + Zipkin 来解决这个问题:
- Sleuth 会在每个请求中生成 traceId 和 spanId;
- Zipkin 负责收集日志并展示完整的调用树。
效果非常明显:以前需要人工查多张日志表才能定位问题,现在只需打开 Zipkin 就能清晰看到整个请求流程、耗时节点。
挑战 3:统一认证怎么设计?
我们采用的是 JWT + OAuth2 方案,在网关层统一做认证鉴权。具体做法如下:
- 用户登录后由认证服务生成 JWT Token;
- 所有请求都需携带此 Token;
- 网关验证 Token 合法性,合法后放行;
- 用户信息写入上下文,供下游服务使用。
Token 存储方案起初我们用 Redis 缓存,后来改为无状态的 JWK 签名 + 本地校验,减少依赖项。
挑战 4:分布式事务怎么办?
这是所有微服务绕不开的话题。我们的订单创建过程涉及库存冻结、账户扣款、积分变更等操作,需要保证最终一致性。
目前的做法是:
- 关键路径使用 Saga 分布式事务模式(自定义补偿机制);
- 非关键路径采用 异步消息+定时对账;
- 未来考虑引入 Seata 或 RocketMQ 半消息机制。
虽然这些都不是银弹,但在现有业务场景下已经能满足需求。
第三阶段:生产环境运维与性能优化
性能瓶颈分析:别让网关拖累整体性能!
我们使用的 Zuul 一开始表现尚可,但随着服务数量增加,QPS 上不去,CPU 使用率飙高。于是我们果断切到了 Spring Cloud Gateway。
Zuul 是同步阻塞模型,而 Gateway 是基于 Netty 的响应式编程模型,在并发能力上有质的提升。
切换前后性能对比:
| 框架 | QPS(压测) | CPU 使用率 |
|---|---|---|
| Zuul | ~800 | ~65% |
| Gateway | ~2800 | ~30% |
建议:尽早使用 Spring Cloud Gateway,避免后期迁移痛苦。
数据库设计:别把锅甩给微服务
服务拆分后数据库也要拆。我们采用了按服务单独数据库 + 最终一致性的方式:
- 每个服务拥有自己的数据库实例;
- 不同服务之间的数据交互通过 API 或 MQ;
- 对于报表类强一致性需求,定期拉取其他服务数据写入本地。
不过这种做法也有代价:需要更多数据库资源,也需要良好的数据同步机制。
我们还做了两件事:
- 给每张表加上 service_name 字段,用于区分归属;
- 所有 SQL 都要经过 Review,禁止全表扫描等操作。
日志集中化与监控报警体系
我们使用 ELK(Elasticsearch + Logstash + Kibana)集中化采集日志,并接入了 Prometheus + Grafana 做指标监控。
几个关键指标监控:
- 请求成功率、响应时间;
- JVM 内存 GC 情况;
- 数据库慢查询;
- 网络连接数、线程池状态;
并且我们设置了告警规则,当某服务错误率超过阈值时自动触发企业微信通知。
技术总结:我的几点经验分享
✅ 推荐做法
- 不要盲目追求服务拆分数量,而是以业务职责为核心;
- 使用 Spring Cloud Gateway 替代 Zuul,性能更好;
- 尽早接入服务链路追踪(Sleuth + Zipkin);
- 采用统一网关做身份认证,避免重复劳动;
- 数据库拆分时预留中间层或同步机制,应对复杂查询场景。
❌ 常见陷阱
- 过度依赖 Ribbon + RestTemplate,不如直接使用 Feign;
- 忽视服务容错,导致系统稳定性差;
- 前期没想好服务边界,后期拆分痛苦;
- 不做日志集中化和指标监控,出了问题只能靠祈祷。
📦 生产注意事项
- 所有微服务必须有健康检查端点(如
/actuator/health); - 配置文件尽量使用 Nacos 管理,动态热更新很重要;
- 微服务之间尽量避免循环依赖;
- 所有服务部署在同一集群,降低网络延迟影响;
- 定期清理服务注册列表,防止僵尸服务堆积。
写在最后:微服务不是终点,而是新的起点
回顾这一年的微服务演进,最大的感受就是 微服务从来不是一个“银弹”解决方案,而是一场组织、技术、认知的全面升级。
Spring Cloud 提供了非常棒的基础组件,但也正因为其强大的灵活性,很容易让人陷入“组件依赖症”或者“过度设计”的陷阱。我们需要始终记住:
微服务的本质在于解耦,而非拆分本身。
现在的我们还在探索服务网格(Istio)、容器化编排(K8s)的路上继续前行,希望有一天能把这套体系更加云原生地运行起来。
如果你也在微服务这条路上迷茫,不妨从最简单的几个服务开始,慢慢摸索出属于自己的“最佳实践”。
共勉。
如果你感兴趣的话,我可以后续继续分享我们在服务网格、分布式事务、灰度发布等方面的实战经验,欢迎留言讨论~

评论 0