从零开始 Spring Cloud:我的微服务实战之旅
引言:为什么选择Spring Cloud?

大家好,我是某互联网公司的一名后端技术负责人。今天想和大家分享一下我第一次主导使用 Spring Cloud 构建微服务架构的全过程。这段经历对我影响深远,不仅让我更深入地理解了分布式系统的复杂性,也让我在团队协作、系统稳定性设计上有了很多新的思考。
故事要从两年前说起。那时我们团队接到了一个全新的项目:为公司核心业务构建一套可扩展、高可用、易维护的服务化中台系统。初期我们评估过多个方案——从传统的单体架构到简单的模块化拆分,最终一致认为,使用 Spring Cloud 搭建微服务架构是最适合当下需求的选择。
不过说实话,在刚开始的时候,我对 Spring Cloud 的了解也不深。虽然之前做过一些 Java Web 应用开发,但面对“注册中心”、“配置中心”、“网关”、“链路追踪”这些新概念,心里还是有点打鼓。但正因如此,我才觉得这是一次难得的学习机会。
接下来我就结合这个真实的项目,分享一下如何从零开始搭建基于 Spring Cloud 的微服务系统,以及我在过程中踩过的坑和积累的经验。
项目背景与初始挑战

项目目标
- 将原有多个单体应用的功能模块拆分为独立服务;
- 实现服务之间的高效通信;
- 提供统一的鉴权和服务治理机制;
- 支持快速迭代和灰度发布;
- 需要满足未来3年的业务增长预期。
我们当时的技术栈主要是基于 Spring Boot,所以在选型上决定继续围绕 Spring 家族生态进行延展,最终选择了 Spring Cloud。
初始面临的几个关键问题:
- 如何管理多个服务?
- 如何实现服务之间的发现与通信?
- 如何统一分发配置文件?
- 权限控制如何做?
- 服务上线之后,怎么监控和追踪异常?
带着这些问题,我们开始了探索之路。
我们的技术选型与实施思路

技术选型一览表
| 功能模块 | 技术/组件 |
|---|---|
| 服务注册中心 | Eureka |
| 配置中心 | Spring Cloud Config + Git |
| 网关路由 | Zuul / 后期换成了 Gateway |
| 服务通信 | Feign + Ribbon |
| 权限控制 | OAuth2 + JWT |
| 链路追踪 | Sleuth + Zipkin |
| 熔断降级 | Hystrix |
| 日志聚合 | ELK(Elasticsearch + Logstash + Kibana) |
| 数据库 | MySQL + MyBatis Plus |

注:现在有些组件已不再推荐使用,例如 Eureka 停止维护,Zuul 被 Gateway 取代等。我们在后期也逐步进行了替换,下文会提到踩坑经历。
核心实践:Spring Cloud 微服务架构落地
我们一共划分了大约8个核心服务模块,每个模块独立部署,并通过 Spring Cloud 的组件协同工作。
下面我重点讲几个最核心的部分是如何落地的。
1. 服务注册与发现 —— Eureka Client
每个服务启动时自动向 Eureka Server 注册元数据(IP、端口、服务名、状态等),其他服务通过 Eureka 获取当前可用实例进行调用。
# application.yml 示例
server:
port: 8081
spring:
application:
name: order-service
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
Eureka 作为注册中心本身也是 Spring Boot 应用,可以非常方便地集成进来:
@EnableEurekaServer
@SpringBootApplication
public class EurekaApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaApplication.class, args);
}
}
2. 服务通信 —— Feign + LoadBalancer(Ribbon)
早期使用的是 Feign,后来升级到了 OpenFeign,并配合 Ribbon 实现客户端负载均衡。
@FeignClient(name = "product-service")
public interface ProductServiceClient {
@GetMapping("/products/{id}")
Product getProduct(@PathVariable("id") Long id);
}
需要注意的是:一定要开启 @EnableFeignClients,并在配置文件中启用 Feign:
feign:
client:
config:
default-config:
logger-level: full
3. 统一网关入口 —— Zuul → Gateway 替换记
一开始我们使用了 Zuul 作为网关,但在实际压测中发现其性能瓶颈较大(尤其在并发请求高时)。后来果断换成 Spring Cloud Gateway。
Gateway 支持异步非阻塞 I/O,底层使用 Netty,响应更快,资源消耗更低。以下是一个简单路由配置示例:
spring:
cloud:
gateway:
routes:
- id: order-service
uri: lb://order-service
predicates:
- Path=/api/order/**
filters:
- StripPrefix=1
这里用了 lb 表示 LoadBalancer,即根据注册中心找到对应服务并转发。
4. 配置中心 —— 使用 Spring Cloud Config 接管全局配置
我们把所有服务的配置文件统一托管到 Git 中,Config Server 按需拉取配置:
spring:
cloud:
config:
server:
git:
uri: https://github.com/your-company/config-repo.git
search-paths: config
然后各个子服务通过如下方式获取配置:
spring:
application:
name: order-service
profiles:
active: dev
cloud:
config:
uri: http://config-server:8888
fail-fast: true
这样就可以做到一次更新,全服务热加载配置(当然需要配合 Actuator 和 RefreshScope 使用)。
5. 权限控制 —— OAuth2 + JWT 的结合使用
我们采用自定义认证中心 + JWT Token 的方式来实现权限控制。认证中心负责颁发 Token,其他服务通过拦截器验证 Token 并提取用户信息。
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/public/**").permitAll()
.anyRequest().authenticated()
.and()
.oauth2ResourceServer()
.jwt();
return http.build();
}

JWT 解析部分我们自定义了一个 JwtAuthenticationTokenFilter,用于从 Header 提取 Token 并设置上下文。
6. 链路追踪与日志监控 —— Sleuth + Zipkin
为了排查服务间的调用链问题,我们集成了 Sleuth 和 Zipkin。Sleuth 会在每次请求中生成唯一 TraceId,并传递给下游服务,Zipkin 收集后展示完整调用链。
spring:
sleuth:
sampler:
probability: 1.0 # 采样率,1代表全部采集
zipkin:
base-url: http://localhost:9411
配合 ELK(Elasticsearch + Logstash + Kibana)使用,能够快速定位日志中的具体异常。
开发过程中的坑与经验总结

✅ 踩坑一:服务启动慢?原来 Eureka 心跳机制拖慢了速度!
初期有个问题困扰我们很久:本地跑多个服务时,总是要等待几分钟才能正常调用,否则会报找不到服务。
后来发现是 Eureka 默认的心跳检查频率和缓存时间太长了。生产环境一般没问题,但在开发测试阶段就显得很鸡肋。
解决方案是在开发环境中调整如下参数:
eureka:
instance:
lease-expiration-duration-in-seconds: 10
lease-renewal-interval-in-seconds: 5
client:
registry-fetch-interval-seconds: 5
这样大大缩短了服务注册和发现的延迟。
❌ 踩坑二:Feign 默认不支持 GET 请求传 POJO 参数!
这个问题我们被坑惨了。有一段代码始终拿不到参数:
@GetMapping("/user")
User getUser(UserQuery query); // 不行!
原因是 Feign 在 GET 请求中默认不会将对象序列化成 URL 查询字符串。解决方法有两个:
- 拆分成单个字段;
- 使用注解手动转换(需要配合 QueryMap);
- 更推荐的方式是:引入 Spring Cloud OpenFeign + Decodeable,并使用 FeignForm 插件支持对象转换。
@RequestLine("GET /user?name={name}&age={age}")
User getUser(@Param("name") String name, @Param("age") Integer age);
或者自定义 Decoder。
🧨 踩坑三:Hystrix 已经被弃用了?别再用它!
我们项目中期突然收到团队提醒:“你们还在用 Hystrix,是不是不知道它已经废弃了?”确实,Netflix 早在 2018 年就宣布停止维护 Hystrix,现在主流推荐 Resilience4j 或 Sentinel。
教训是:在技术选型时要关注官方动态和社区活跃程度。Hystrix 的 fallback 机制很好,但我们后来切换成 Resilience4j,同样实现了熔断限流功能。
成果与收获
经过三个月的努力,整个平台顺利上线。上线后我们做了以下几个优化:
- 服务粒度清晰:各模块职责明确,便于管理和维护;
- 接口稳定:Feign+Ribbon+Fallback 保障高可用;
- 运维友好:ELK、Prometheus + Grafana 实现实时监控;
- 快速发布:结合 Jenkins CI/CD 流程,每日可完成多次部署;
- 成本可控:按需扩容缩容,节省资源开销。
更重要的是,整个团队在过程中掌握了分布式系统的核心能力:
- 如何拆分服务边界;
- 如何设计 API;
- 如何保证系统健壮性;
- 如何进行故障隔离;
- 如何处理并发与一致性问题。
写给读者的经验建议
如果你正在尝试从头搭建微服务架构,以下是几点我亲身总结的经验,希望能帮到你:
1. 服务拆分不是越细越好,先画好边界!
初期不要盲目拆分成几十个服务,要以业务为核心进行划分。比如订单、支付、库存、用户等功能模块,都是天然的服务边界。
2. 技术选型要务实,优先考虑成熟度和可维护性
很多新技术看起来很酷炫,但如果没有足够文档或社区支持,落地时容易踩坑。宁愿稍微“保守”一点,也不要盲目追求新奇。
3. 先做好基础能力建设,比如日志、监控、熔断、重试机制
这些看似“辅助”的东西,才是真正保障系统稳定的根基。没有它们,线上出问题你会抓狂。
4. 多写自动化脚本,少点手动操作
尤其是部署、回滚、健康检查这类操作。我们后来搞了一套统一部署脚本和健康检查探针,极大提升了效率。
5. 学会“退一步”,有时候单体反而更合适
并不是所有项目都适合微服务。如果你的业务复杂度还没到一定级别,微服务只会增加你的维护成本。
结语:Spring Cloud 是起点,而不是终点
这篇文章写了这么多,其实只是我和团队在 Spring Cloud 微服务路上的一小段经历。回头看看,当初那个面对“注册中心”一脸懵的新手程序员,如今也能游刃有余地讲解服务治理、熔断降级、链路追踪这些概念了。
Spring Cloud 是一个非常强大的框架,它帮助我们解决了大量分布式系统开发的难题。但它不是银弹,更不是万能工具箱。真正重要的,是我们是否具备系统思维、是否懂得权衡利弊、是否能从一次次实践中不断成长。
希望这篇真实、接地气的文章,能帮你迈出第一步,少走些弯路。如果能在评论区看到你的反馈,我会非常开心 😄
愿你在技术之路上走得更稳、更远。

评论 0