Spring Cloud从零开始:微服务入门指南
去年冬天,我还在成都某个县城的出租屋里裹着毯子敲代码。窗外是淅淅沥沥的小雨,B站上放着Lo-fi beats,手边泡着一壶茉莉花茶——典型的小镇做题家日常。
彼时我在一家小公司远程打工,项目组就三个人:一个产品经理(兼老板)、一个测试(也是老板)、还有一个运维(还是老板)。我的任务?把一套老旧的单体系统拆成微服务,理由是“隔壁老王说现在面试都问这个”。
于是,在Deadline压顶、KPI催命的背景下,我硬着头皮踏上了Spring Cloud之路。今天这篇笔记,既是给想入坑微服务的朋友一点参考,也算是自己踩坑半年后的血泪总结。
为什么非得搞微服务?
说实话,刚开始我是抗拒的。原来的Spring Boot单体应用跑得好好的,数据库连着MySQL,Redis缓存扛住大部分压力,日活也就几万,真没必要上微服务。但老板说了:“我们要为未来百万用户做准备!”(后来才知道他刚看了某大厂架构分享PPT)
不过回头想想,微服务确实有它的道理:
- 独立部署:某个模块改了不用全量发布
- 技术栈灵活:比如新功能用Go写个轻量服务
- 容错隔离:订单崩了不影响用户登录
当然,代价也很明显:复杂度爆炸。注册中心、配置中心、网关、熔断、链路追踪……光是这些名词就能劝退一批人。更别说本地调试时N个服务同时启动,内存直接飙到16G。
面试题预警:“微服务解决了什么问题?带来了什么问题?” 这题我面了三家都遇到,答不全基本凉一半。
架构设计:别一上来就上全套
很多教程一上来就给你整Eureka + Zuul + Hystrix + Sleuth全家桶,搞得像在搭乐高。但实际项目中,最小可行架构才是王道。
我第一版只做了三件事:
- 服务拆分:按业务域切,比如 user-service、order-service、product-service
- 服务注册与发现:用 Nacos(比 Eureka 更现代,支持配置中心)
- 服务间调用:Feign + Ribbon,简单好用
其他高级功能(比如熔断、限流)先不上,等线上出问题再补——典型的“先跑起来,再优化”思路。
# bootstrap.yml 示例(user-service)
spring:
application:
name: user-service
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848 # 本地起个 Nacos 就行
config:
server-addr: 127.0.0.1:8848
file-extension: yaml
注意:bootstrap.yml 要放在 classpath 根目录,否则 Nacos 配置拉不下来,我当时卡了整整一个下午,最后发现是文件放错位置了……
服务通信:REST 还是 RPC?
我们内部争论过要不要上 gRPC。毕竟 Go 团队那边已经在用,性能好、协议清晰。但考虑到团队全是 Java 背景,最终还是选了 Feign + JSON。
// order-service 调用 user-service
@FeignClient(name = "user-service")
public interface UserClient {
@GetMapping("/users/{id}")
User getUserById(@PathVariable("id") Long id);
}
虽然性能不如 gRPC,但胜在开发快、调试方便。而且加上 OpenFeign 的重试和超时配置,基本够用:
feign:
client:
config:
default:
connectTimeout: 5000
readTimeout: 10000
retryer: com.example.config.CustomRetryer
吐槽一句:产品经理总以为“服务拆了就能并行开发”,结果两个服务接口对不上,联调三天没进展。最后我写了个 Swagger + Postman 共享文档,才勉强稳住局面。
数据库设计:别让事务变成噩梦
微服务最头疼的不是调用,而是分布式事务。
比如下单流程:扣库存 → 创建订单 → 扣用户余额。这三个操作分布在三个服务,传统 @Transactional 直接失效。
我们没上 Seata(太重),也没搞 TCC(太复杂),而是用了最终一致性 + 补偿机制:
- 订单服务发消息到 RocketMQ
- 库存服务消费消息,扣库存
- 如果失败,发“回滚”消息,订单状态变“取消”
// 伪代码:下单
@Transactional
public void createOrder(Order order) {
orderRepository.save(order);
mqProducer.send("ORDER_CREATED", order.getId());
// 不直接调用库存服务!
}
这种方式虽然有延迟,但系统简单、可追溯。线上跑了几个月,补偿成功率 99.9%,剩下的 0.1% 人工处理——反正用户量不大,老板也能接受。
配置管理:别再 hardcode 了!
以前单体时代,配置全写在 application.yml 里,改个数据库密码就得重新打包。现在用 Nacos 做配置中心,动态刷新简直爽飞:
@RestController
@RefreshScope // 关键注解!
public class ConfigController {
@Value("${app.feature.new-ui:false}")
private boolean newUiEnabled;
}
在 Nacos 控制台改个开关,服务自动生效,不用重启!上周五晚上产品经理突然说“双11要上线新皮肤”,我改个配置就搞定了,十点准时下班——这种成就感,谁懂?
性能与监控:别等线上炸了才看
微服务调用链长,一个请求可能经过 5 个服务。不出问题还好,一出问题就是“到底哪一环慢?”
我们加了 Spring Cloud Sleuth + Zipkin,链路追踪一目了然:
| 服务 | 平均耗时 | 错误率 |
|---|---|---|
| gateway | 12ms | 0% |
| user-service | 45ms | 0.1% |
| order-service | 210ms | 2% ← 重点优化! |
果然,订单服务查数据库没加索引,慢查询拖垮整个链路。加个联合索引后,TP99 从 800ms 降到 120ms。
另外,健康检查也别忘:
management:
endpoints:
web:
exposure:
include: health,info,metrics
endpoint:
health:
show-details: always
运维(也就是老板)终于能在 Grafana 上看到服务状态了,再也不用半夜打电话问我“系统是不是挂了”。
面试题高频考点整理
学完这套,我面了两家,以下问题几乎必问:
| 问题 | 我的回答要点 |
|---|---|
| Spring Cloud 和 Dubbo 区别? | SC 基于 HTTP/REST,生态全;Dubbo 是 RPC,性能高但绑定 Java |
| Feign 和 RestTemplate 区别? | Feign 声明式,集成 Ribbon/Hystrix;RestTemplate 更底层 |
| 服务雪崩怎么防? | 熔断(Hystrix/Sentinel)+ 降级 + 限流 |
| 配置中心怎么保证高可用? | Nacos 集群部署,本地缓存兜底 |
| 微服务下如何做权限控制? | 网关统一鉴权(JWT),服务间用 Token 传递 |
血泪教训:别死记概念,一定要结合你自己的项目讲。比如我说“我们用 Nacos 做配置中心,有一次网络抖动导致配置拉取失败,后来加了本地 fallback 文件”,面试官眼睛都亮了。
最后:微服务不是银弹
折腾半年下来,我最大的感悟是:微服务不是技术升级,而是组织升级。
如果你团队就几个人,业务也不复杂,硬上微服务只会增加维护成本。我们现在的架构其实还是“伪微服务”——服务拆了,但数据库还是共用一个 MySQL 实例(只是不同 schema),CI/CD 也还是手动打包上传。
但没关系,适合当前阶段的架构才是好架构。
最近听说老板又想搞 Service Mesh,还买了本《云原生实战》……算了,等他看完再说吧。我先去听听歌,写写 Go —— 毕竟隔壁 Go 服务才 20MB 内存,而我的 Spring Boot 动不动 500MB,属实有点惭愧。
写在结尾:技术没有高低贵贱,只有合适不合适。在县城远程办公的日子,让我更明白:稳定、可维护、能按时下班的系统,才是好系统。至于那些 fancy 的架构图?留着面试吹牛用就好 😄

评论 0