Spring Cloud从零开始:微服务实战手记
初衷与背景

2019年我刚加入一家中型互联网创业公司,当时我们整个后台是一个典型的单体架构(Monolith),部署在一台云服务器上。随着业务增长,系统频繁出现接口响应变慢、上线影响全功能、数据库锁竞争等问题。技术负责人果断决定重构,目标是引入微服务架构,用 Spring Cloud 来搭建一套可扩展的后端体系。
那时候,我对 Spring Cloud 的理解还停留在“听说过”、“学过一些 Demo”的阶段,真正动手做项目完全是摸着石头过河。本文就结合那段真实的项目经历,谈谈我是怎么一步步从零开始搭建基于 Spring Cloud 的微服务体系的。
问题描述:传统架构的瓶颈

我们的原始系统结构非常简单,一个 Java Web 应用,集成了支付、用户中心、商品管理等多个模块。随着功能增加和并发量上升,主要出现了以下几个问题:
- 部署复杂:每次上线都要全量更新,风险大。
- 模块耦合严重:改一个功能可能影响另一个完全无关的功能。
- 性能瓶颈明显:一个接口卡住,整个应用都拖慢。
- 数据库压力大:所有请求都打在一个数据库上,索引爆炸。
最让我印象深刻的一次,是我们上线了一个商品推荐的新算法逻辑,结果把整个数据库表加锁了,造成首页加载超时。那一次事故之后,老板说:“必须拆微服务。”
解决方案:搭建 Spring Cloud 微服务架构

我们选择了 Spring Cloud + Spring Boot 的组合来实现微服务架构,原因很简单:团队对 Spring 比较熟悉,生态完整,社区活跃,文档丰富,而且可以跟已有的代码较好兼容。
架构设计概览
整体上我们采用的是经典的 Spring Cloud 分布式架构模式,主要包括以下组件:
- Eureka:服务注册与发现
- Feign / OpenFeign:服务间通信
- Zuul / Gateway:API 网关
- Config Server:统一配置管理
- Sleuth / Zipkin:链路追踪(后来才加上)
- Ribbon:负载均衡(配合 Feign 使用)
我们先将原来的几个核心模块拆分成独立的服务:
- 用户服务(User Service)
- 商品服务(Product Service)
- 订单服务(Order Service)
- 支付服务(Payment Service)
这些服务通过 Eureka 注册到同一个服务注册中心,使用 Feign 完成跨服务调用,外部请求则走 API Gateway 统一入口。
实践落地:关键代码片段
下面是我印象比较深的一些核心代码片段,都是实际生产项目中用过的,不是什么官方示例。
1. 服务注册(以商品服务为例)
# application.yml
server:
port: 8082
spring:
application:
name: product-service
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
// 启动类添加 @EnableEurekaClient
@SpringBootApplication
@EnableEurekaClient
public class ProductServiceApplication {
public static void main(String[] args) {
SpringApplication.run(ProductServiceApplication.class, args);
}
}
启动后,可以在 Eureka 控制台看到注册成功的信息。
2. 跨服务调用(用户服务调用商品服务)
我们早期用的 Feign,后来切换到了 OpenFeign,这里给个基础的例子:
// ProductClient.java
@FeignClient(name = "product-service")
public interface ProductClient {
@GetMapping("/products/{id}")
Product getProductById(@PathVariable("id") Long id);
}
这个接口被注入到 UserService 中使用:
@Service
public class UserService {
private final ProductClient productClient;
public UserService(ProductClient productClient) {
this.productClient = productClient;
}
public void doSomething(Long productId) {
Product p = productClient.getProductById(productId);
// ...
}
}
注意:为了启用 Feign Client,需要在启动类或配置类上加 @EnableFeignClients。
3. API 网关路由(Gateway 示例)
spring:
cloud:
gateway:
routes:
- id: user-service
uri: lb://user-service
predicates:
- Path=/api/users/**
filters:
- StripPrefix=1
- id: order-service
uri: lb://order-service
predicates:
- Path=/api/orders/**
filters:
- StripPrefix=1
这样设置之后,外部访问 /api/users/123 就会转发到 user-service 的 /users/123 接口,路径中的 /api/users 前缀会被自动去掉。
开发过程中的坑与解法
微服务听起来很美好,但在真实开发中还是踩了不少坑,这里分享几个典型问题。
问题1:服务调用超时与失败传递
刚开始,我们没配置超时参数,有时候一个服务挂掉,会导致整条链路瘫痪。比如:用户服务调订单服务,订单服务调支付服务,支付服务出问题,用户服务就跟着卡死。
解决方案:
我们逐步引入了 Hystrix 断路器,并设置了合理的超时时间:
feign:
client:
config:
default:
connectTimeout: 5000
readTimeout: 5000
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 8000
同时,每个 Feign Client 添加 fallback:
@FeignClient(name = "product-service", fallback = ProductClientFallback.class)
fallback 类处理异常情况下的降级逻辑。
问题2:数据库隔离不彻底
最初为了方便,多个服务共用了同一张数据库表。结果某个服务修改数据结构,导致其他服务报错。教训很大!
解决方案:
每个服务拥有自己的数据库实例,必要时同步数据用 Kafka 或者异步 Job 处理。例如:
- 用户服务操作完用户数据后,发送事件到 Kafka。
- 订单服务监听该事件,更新本地缓存。
这样保证了数据一致性的同时,也做到了数据库级别的隔离。
问题3:日志混乱 & 链路追踪缺失
前期我们没有统一的日志格式和链路追踪,出了问题很难定位。尤其跨服务的时候,根本不知道哪一步出错了。
解决方案:
引入 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 地址:
spring:
zipkin:
base-url: http://localhost:9411
然后每个请求都会生成唯一的 traceId,我们日志里带上它就能快速串联所有服务。
效果总结:为什么值得?
微服务改造上线后,效果还是很明显的:
- 部署灵活:不同服务可以独立部署、滚动升级。
- 性能提升:拆分后热点接口的压力分散了。
- 故障隔离:一个服务挂不影响整体系统。
- 扩展能力强:后续加新功能只需要新增服务模块即可。
特别是当我们在双十一高峰期扩容时,得益于服务拆分,我们只针对高并发的订单和支付服务进行了水平扩容,而无需全局加机器,节省了不少成本。
经验分享:几点建议
如果你也在考虑入门 Spring Cloud,或者准备搭建第一个微服务项目,我有几点真心建议:
✅ 1. 不要盲目追求新技术
Spring Cloud 虽好,但不是万能的。你得先明确你的业务是否真的需要微服务。如果只是一个小项目,或者初期用户不多,不如先把单体架构优化好,等真正遇到瓶颈再拆也不迟。
✅ 2. 拆服务别太细,先从核心边界入手
不要一开始就按“每个人一个服务”去拆。我们一开始也犯了这个问题,导致服务太多反而难以维护。建议从业务边界清晰的地方拆起,比如用户、订单、支付这三个自然区隔的领域。
✅ 3. 提前规划好监控和日志体系
否则,线上一出问题,你就只能靠猜了。我见过太多团队微服务上线后,连哪个服务在哪台机器上运行都不清楚,排查效率极低。
✅ 4. 重视 DevOps 和自动化部署
微服务意味着部署频率提高,手动部署很容易出错。我们后期引入了 Jenkins + Docker + Kubernetes 自动化流程,效率提升了数倍。
✅ 5. 学会接受“最终一致性”
微服务之间不可能强一致,尤其涉及数据库时。你需要学会接受并处理“最终一致性”,合理使用消息队列、补偿机制等方式确保系统稳定。
结语:微服务是一种演化,不是终点
回头看,我们并不是一开始就做得很好,很多设计也是在一次次踩坑中打磨出来的。Spring Cloud 是个很好的工具集,但它不是银弹。真正的挑战从来不在框架本身,而是在如何设计合理的架构、组织服务、处理分布式事务、保障稳定性。
微服务不是一蹴而就的东西,更像是一种架构思维的演化。希望这篇文章能帮你少走些弯路。如果你现在正在学习 Spring Cloud 或者准备动手实践,不妨把它当成一次旅程——每解决一个问题,就会多一分底气。
最后送大家一句话,也是我当时写在项目笔记里的话:
“服务小了,心要更大。”
欢迎留言交流,一起进步!

评论 0