Spring Cloud从零开始:微服务入门指南
早上8点,成都的天刚蒙蒙亮,我已经坐在工位上泡好一杯速溶咖啡——别笑,我们中台团队最近项目排得紧,连买手冲的时间都没有了。上周五晚上加班到十一点,就为了赶在双11前把新模块上线,结果测试同学凌晨两点发消息说“注册中心挂了”,我当时真的想砸电脑。
但事情总得解决。作为公司技术中台的一员,我们的核心任务就是支撑各业务线快速迭代,而微服务架构正是这几年我们主推的方向。去年领导拍板要全面拥抱 Spring Cloud,理由很直白:“隔壁大厂都在用,咱不能掉队。”于是,我这个早起型选手(以及被逼无奈的学习者)硬着头皮从零开始啃文档、搭环境、踩坑、填坑……今天写这篇文章,既是复盘,也是给后来人少走点弯路。
为什么是 Spring Cloud?不是 Dubbo,也不是自己造轮子?
先说背景。我们公司早期是单体架构,一个 Java 应用包打天下,数据库一张表动辄几千万行。产品经理每次提需求都像在拆炸弹——改个字段,说不定就炸了支付模块。运维兄弟天天盯着 CPU 和 GC 日志,嘴里念叨着“再这样下去我要去送外卖了”。
后来搞了微服务拆分,一开始用的是简单的 HTTP + Nginx 转发,结果服务一多,配置爆炸,调用链乱成毛线团。这时候,Spring Cloud 的优势就出来了:它不是从零造轮子,而是基于 Netflix OSS、Consul、RabbitMQ 等成熟组件,提供了一套开箱即用的微服务治理方案,而且和 Spring Boot 天然集成,对我们这种 Java 技术栈为主的团队非常友好。
顺便吐槽一句:前端同事看我们折腾服务注册发现,一脸不屑:“你们后端怎么连个地址都要动态找?我们前端打包完扔 CDN 就完事了。” 哼,等哪天他们要搞微前端+动态路由+灰度发布,就知道什么叫“痛并快乐着”了。
动手!从零搭建一个最简微服务系统
第一步:服务注册与发现 —— Eureka 登场
微服务的核心是“服务能互相找到”。Spring Cloud 默认推荐 Eureka(虽然现在官方已进入维护模式,但对我们内部小规模系统完全够用)。
新建一个 eureka-server 项目:
<!-- pom.xml -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
# application.yml
server:
port: 8761
eureka:
client:
register-with-eureka: false # 服务端不注册自己
fetch-registry: false
server:
enable-self-preservation: false # 开发环境关掉自我保护
启动类加上 @EnableEurekaServer,搞定。访问 http://localhost:8761 就能看到 Eureka 控制台。
生产经验:线上环境一定要开启
enable-self-preservation,否则网络抖动时 Eureka 会疯狂剔除实例,导致雪崩。我们去年双11就吃过这亏。
第二步:写一个用户服务(user-service)
@RestController
public class UserController {
@GetMapping("/user/{id}")
public User getUser(@PathVariable Long id) {
// 这里其实应该查数据库,为了演示先 mock
return new User(id, "张三", "zhangsan@example.com");
}
}
关键是要让它能注册到 Eureka:
# user-service 的 application.yml
spring:
application:
name: user-service
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
加上 @EnableDiscoveryClient,启动后刷新 Eureka 页面,就能看到 USER-SERVICE 上线了!
第三步:订单服务调用用户服务 —— Feign 客户端
订单服务需要获取用户信息,传统做法是写 RestTemplate + URL 硬编码,但这样耦合死了。Spring Cloud 提供了声明式 HTTP 客户端 Feign:
@FeignClient(name = "user-service")
public interface UserClient {
@GetMapping("/user/{id}")
User getUser(@PathVariable("id") Long id);
}
在订单服务里直接注入 UserClient,调用就像本地方法一样:
@Service
public class OrderService {
@Autowired
private UserClient userClient;
public Order createOrder(Long userId) {
User user = userClient.getUser(userId); // 自动负载均衡 + 服务发现
return new Order(user.getId(), "订单123");
}
}
踩坑提醒:Feign 默认不支持
@PathVariable不加value,必须写成@PathVariable("id"),否则报错Method has too many Body parameters。我第一次遇到时还以为是版本冲突,查了半小时源码。
配置中心?网关?熔断?一个都不能少
光有服务注册还不够。想象一下:50 个微服务,每个都要改数据库密码,难道挨个改配置重启?所以 Spring Cloud Config 必须上。
我们把配置文件扔到 GitHub 私有仓库(对,就是那个全球程序员的社交平台),Config Server 指向它:
# config-server
spring:
cloud:
config:
server:
git:
uri: https://github.com/your-company/microservice-configs
username: your-bot
password: your-token
其他服务通过 bootstrap.yml 拉取配置:
# user-service 的 bootstrap.yml
spring:
application:
name: user-service
cloud:
config:
uri: http://config-server:8888
这样,改个数据库连接字符串,只需 push 到 GitHub,然后发个 /actuator/refresh 请求(配合 @RefreshScope),服务就热更新了。再也不用求运维半夜重启服务了!
关于“前端、区块链、Python”的强行关联(老板要求的关键词 😅)
我知道你在想:“说好的前端、区块链、Python 呢?”
前端:我们的微服务 API 最终都是给前端消费的。前端团队用 Vue 写 SPA,通过 Nginx 反向代理到 Spring Cloud Gateway(替代 Zuul 的新一代网关)。Gateway 统一做鉴权、限流、路径重写。比如
/api/user/**路由到user-service,前端完全不用关心后端有几个服务。区块链:咳咳……我们公司确实有个区块链项目组,但他们用的是 Hyperledger Fabric,跟 Spring Cloud 没半毛钱关系。不过有一次他们想调用我们的用户服务做 KYC 验证,我们就通过 Feign 暴露了一个只读接口。所以,微服务的好处之一就是异构系统也能轻松集成——哪怕对方在挖矿。
Python:数据团队用 Python 写模型,训练完要部署成服务供业务调用。我们给他们开了个规范:用 Flask 写 REST API,注册到 Eureka(通过
eureka-client的 Python 版本),然后我们的 Java 服务就能像调用普通微服务一样调用它。虽然性能差点,但胜在灵活。毕竟,在真实世界里,技术栈统一是理想,混搭才是常态。
生产环境血泪教训
1. 服务雪崩 vs Hystrix 熔断
有次用户服务数据库慢查询,导致订单服务大量线程阻塞。幸好我们加了 Hystrix 熔断:
@FeignClient(name = "user-service")
public interface UserClient {
@GetMapping("/user/{id}")
@HystrixCommand(fallbackMethod = "getDefaultUser")
User getUser(@PathVariable("id") Long id);
default User getDefaultUser(Long id) {
return new User(id, "匿名用户", "");
}
}
当错误率超过阈值,Hystrix 自动熔断,返回兜底数据,避免拖垮整个系统。熔断不是万能的,但没有熔断是万万不能的。
注:Hystrix 已停止维护,新项目建议用 Resilience4j,但我们老系统还没迁移……
2. 链路追踪不能少
微服务调用链太深,出问题根本找不到源头。我们接入了 Sleuth + Zipkin,每个请求自动带上 traceId,日志里一搜就知道完整路径。运维同学终于不用问“哪个服务又慢了?”了。
3. 数据库设计要提前规划
微服务意味着每个服务独占数据库。我们早期没注意,订单服务和用户服务共用一个库,结果事务跨服务没法搞。后来拆库时,光数据迁移脚本就写了两周。教训:拆服务前先拆库!
性能与监控:别等线上炸了才看
我们用 Prometheus + Grafana 监控所有 Spring Boot Actuator 暴露的指标:JVM、HTTP 请求数、Feign 调用延迟等。
关键配置:
management:
endpoints:
web:
exposure:
include: health,info,metrics,prometheus
metrics:
tags:
application: ${spring.application.name}
配合 Kubernetes 的 HPA(水平扩缩容),CPU 超过 70% 自动加 Pod。自动化运维才是微服务的终极护城河。
总结:微服务不是银弹,但值得拥有
从零开始搞 Spring Cloud,前期投入确实大:要学一堆组件,要改开发习惯,要和运维磨合部署流程。但一旦跑顺了,好处显而易见:
- 业务线可以独立开发、独立部署(再也不用等“全量发布日”)
- 故障隔离(一个服务挂了不影响全局)
- 技术异构(Python、Go 也能接入)
- 弹性伸缩(大促前自动扩容)
当然,如果你只有两个服务,别硬上微服务——单体应用 + 良好模块化,可能更香。
最后说句实在话:学 Spring Cloud 不是为了跳槽(虽然简历确实加分),而是为了让每天的工作少一点“救火”,多一点“创造”。毕竟,谁不想下班前喝着茶看系统稳稳跑着,而不是在群里狂刷“@所有人,线上挂了!”呢?
作者:某上市公司技术中台搬砖工,坐标成都,早起但不一定高效。GitHub 上有些 demo 代码(搜
spring-cloud-zero-to-hero),欢迎 star(不 star 也行,反正我又不靠这个涨工资)。

评论 0