Spring Cloud从零开始:微服务入门指南
上周五晚上十点半,我坐在成都家里阳台的小桌子前,泡了杯速溶咖啡——别笑,咱国企程序员不讲究这些花里胡哨的,能提神就行。窗外锦江边上夜跑的人还不少,而我正对着电脑屏幕,调试一个本地跑不通的 Eureka 注册中心。这场景要是被产品经理看到了,怕是要感动得热泪盈眶:“你看人家多敬业!”
但说实话,我根本不是“加班”,纯粹是自己想搞明白 Spring Cloud。毕竟在我们这种双休雷打不动、下班六点准时锁门的国企,项目节奏慢得像树懒走路。可我也不想躺平啊,尤其看到隔壁组老王跳槽去了字节,薪资翻倍,心里那个痒啊……
于是上个月,我给自己立了个 flag:用 Spring Cloud 搭一套完整的微服务 Demo,就当是为下一次面试攒点干货。顺便——你懂的——万一哪天想跑路呢?
为啥要折腾微服务?真不是闲得慌
去年双11前,我们部门接了个“数字化转型”项目(领导原话),说是要把原来那个巨石应用拆成微服务。听起来高大上,实际上就是个内部审批系统,用户量不到一千,QPS 峰值也就 20。运维同事私下吐槽:“这拆微服务,纯属给蚊子装火箭推进器。”
但既然领导拍板了,那就干呗。问题是,团队里除了我,其他人连 Feign 和 Ribbon 都分不清。测试妹子甚至问我:“微服务是不是跟区块链一样,都是炒概念的?” —— 我当场差点一口茶喷出来。
说到区块链,其实跟本文关系不大,但我得按要求提一嘴:别被忽悠了,90% 的业务根本用不上区块链。微服务也一样,不是银弹。但如果你的系统确实有模块解耦、独立部署、弹性扩缩容的需求(比如我们后来真的接了个对接外部支付平台的子系统),那 Spring Cloud 真香。
从零开搞:注册中心 + 服务提供者 + 消费者
我决定从最基础的三件套开始:Eureka(注册中心) + 两个 Spring Boot 应用(一个提供者,一个消费者)。目标很简单:消费者能通过服务名调用提供者的接口。
第一步:搭 Eureka Server
新建一个 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,熟悉的蓝色界面出现,那一刻,我仿佛回到了大学做课程设计的日子——简单,但踏实。
第二步:写个服务提供者(user-service)
再建一个 user-service,引入:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
配置文件:
server:
port: 8081
spring:
application:
name: user-service # 服务名,消费者靠它找你
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
写个简单的 Controller:
@RestController
public class UserController {
@GetMapping("/user/{id}")
public String getUser(@PathVariable Long id) {
return "User-" + id; // 假数据,别较真
}
}
启动后刷新 Eureka 页面,USER-SERVICE 出现在 Instances 下,绿色 UP 状态。稳了!
第三步:消费者(order-service)调用它
新建 order-service,同样引入 Eureka Client,配置类似,端口改成 8082,服务名叫 order-service。
关键来了:怎么调用 user-service?
早期可以用 RestTemplate + @LoadBalanced,但现在更推荐 OpenFeign(声明式 HTTP 客户端)。
先加依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
启动类加 @EnableFeignClients。
然后定义 Feign 接口:
@FeignClient(name = "user-service") // 对应 provider 的 spring.application.name
public interface UserClient {
@GetMapping("/user/{id}")
String getUser(@PathVariable("id") Long id);
}
在 OrderController 里注入使用:
@RestController
public class OrderController {
@Autowired
private UserClient userClient;
@GetMapping("/order/{userId}")
public String createOrder(@PathVariable Long userId) {
String user = userClient.getUser(userId);
return "Created order for " + user;
}
}
启动 order-service,访问 http://localhost:8082/order/123,返回 Created order for User-123。完美!
踩过的坑 & 面试题预警
你以为这就完了?Too young.
坑1:服务注册延迟
本地开发时,服务启动后 Eureka 页面要等 30 秒才显示?因为默认心跳间隔是 30 秒。开发环境可以调快点:
eureka:
instance:
lease-renewal-interval-in-seconds: 5
lease-expiration-duration-in-seconds: 10
但生产环境千万别乱改!否则可能引发误判下线。
坑2:Feign 超时
有一次线上调用突然超时,查了半天发现 Feign 默认超时只有 1 秒。赶紧配:
feign:
client:
config:
default:
connectTimeout: 5000
readTimeout: 10000
坑3:服务雪崩
没加熔断,一个服务慢,整个链路卡死。后来上了 Resilience4j(Hystrix 已停更),加 fallback:
@FeignClient(name = "user-service", fallback = UserClientFallback.class)
public interface UserClient { ... }
@Component
public class UserClientFallback implements UserClient {
@Override
public String getUser(Long id) {
return "Default User"; // 降级返回
}
}
性能优化:别只顾着功能,忘了 QPS
作为对性能优化有点执念的人,我顺手压测了一下。
用 JMeter 模拟 100 并发,直接调 order-service:
| 场景 | 平均响应时间 (ms) | 错误率 |
|---|---|---|
| 单体应用(模拟) | 45 | 0% |
| 微服务(无优化) | 120 | 0% |
| 微服务 + Feign 连接池 | 78 | 0% |
Feign 默认用的是 JDK 的 HttpURLConnection,性能一般。换成 OkHttp:
feign:
httpclient:
enabled: false
okhttp:
enabled: true
并加连接池配置:
okhttp:
max-connections: 200
max-connections-per-route: 50
效果立竿见影。后端开发不能只写 CRUD,得关心网络开销、序列化效率、连接复用。
关于 Python 和跨语言调用
有朋友问:我们团队主要用 Python,能和 Spring Cloud 互通吗?
答案是:可以,但别硬融。
Eureka 支持非 Java 客户端(比如 py-eureka-client),Consul 或 Nacos 更友好。但如果你的 Python 服务只是偶尔调用 Java 微服务,不如走 API Gateway(比如 Spring Cloud Gateway)暴露 REST 接口,简单可靠。
微服务的核心是解耦,不是技术栈统一。强行让 Python 服务注册到 Eureka,后期维护成本可能高于收益。
生产环境那些事儿
在我们国企,上线流程比代码还复杂。但微服务上线,我总结了几条血泪经验:
- 每个服务必须有健康检查接口(Spring Boot Actuator
/actuator/health) - 日志必须带 traceId,用 Sleuth + Zipkin 链路追踪,不然排查问题靠猜
- 配置中心用 Nacos 或 Apollo,别把数据库密码写死在 yml 里
- 不要过度拆分!我们一开始拆了 8 个服务,结果 CI/CD 流水线跑一次 20 分钟,测试环境资源不够,天天吵架
最后:这玩意儿面试真考
最近帮几个朋友模拟面试,Spring Cloud 高频面试题基本逃不开:
- Eureka 和 Zookeeper 的 CAP 区别?
- Feign 的工作原理?怎么实现负载均衡?
- 服务雪崩怎么预防?Hystrix 和 Resilience4j 选哪个?
- 网关的作用?为什么不用 Nginx 直接做?
这些问题,光背八股文没用。你得真搭过、真踩过坑,才能答出细节。比如被问“Feign 超时怎么配”,如果你只说 readTimeout,面试官可能觉得你纸上谈兵;但如果你补充一句“我们线上因为没配,导致支付回调超时,后来加了 OkHttp 连接池和重试机制”,那印象分直接拉满。
写在最后
折腾这套 Demo 花了我三个深夜,但值了。不仅搞懂了 Spring Cloud 的核心组件,还顺手整理了一份可复用的脚手架模板。现在每次新项目,直接 clone 改改就能用,再也不用求着架构组给模板了。
虽然我们国企项目节奏慢,但技术不能停。谁知道哪天政策一变,或者自己想换个赛道呢?保持手感,永远比抱怨环境有用。
对了,如果你也在成都,又对微服务或性能优化感兴趣,欢迎一起喝杯茶(或者火锅)聊聊。反正周末我不加班,有的是时间。
—— 一个在锦江边写代码的国企程序员,于 2024 年初夏

评论 0