深夜敲代码的我,如何用 Spring Cloud 把微服务从零搭起来?
上周五晚上十一点半,深圳南山科技园还亮着不少灯。我在工位上盯着屏幕,脑子里全是 DiscoveryClient 的报错日志,咖啡已经凉了第三杯。产品经理昨天刚提了个需求:“咱们能不能把下单和库存拆成两个服务?双 11 快到了,得扛住流量。”
说真的,一开始我是拒绝的——单体架构跑得好好的,何必自找麻烦?但转念一想:腾讯系公司现在哪个不是微服务?跳槽面试问 Spring Cloud 都成基础题了。再加上最近被 Cursor 和 Codeium 宠坏了,写点配置都靠 AI 提效,说不定真能搞定。
于是,我决定从零开始搞一套 Spring Cloud 微服务。不为别的,就为了下次线上事故时能理直气壮地说:“这锅不该我背,是注册中心挂了。”
起手式:为什么非得用微服务?
先别急着上 Eureka 或 Nacos。我踩过最大的坑,就是团队里没人搞清楚“我们到底需不需要微服务”。
去年有个项目,后端就仨人,硬是拆了六个服务,结果每天花两小时处理服务间调用超时、链路追踪缺失、配置同步失败……测试同学直接在群里@我:“你这接口返回 500,到底是哪个服务崩了?” 我只能苦笑:“建议重启宇宙。”
所以,微服务不是银弹,而是成本换弹性。如果你的系统:
- 用户量不大(比如日活 < 1万)
- 团队小(< 5人)
- 功能耦合深(改一个功能要动七八个模块)
那你可能更适合先优化单体架构,而不是一头扎进分布式地狱。
但如果你像我一样,在深圳这种卷王之城,老板开口闭口“高可用、弹性伸缩、秒级扩容”,那微服务就是必修课了。而且——实话实说——Spring Cloud 现在生态太成熟了,入门门槛比三年前低太多。
架构设计:别只想着“能跑就行”
我见过太多团队把微服务做成“分布式单体”:每个服务数据库还是共享的,API 接口随意调用,没有熔断降级,上线全靠手动改 YAML。结果一到大促,雪崩式宕机,运维半夜打电话骂人。
所以这次,我给自己定了三条铁律:
- 每个服务独享数据库(哪怕是同一个 MySQL 实例下的不同库)
- 服务间通信必须走 Feign + OpenFeign 声明式调用,禁止硬编码 IP
- 所有对外接口必须有熔断策略(Hystrix 或 Resilience4j)
顺便吐槽一句:有些老哥喜欢用 RestTemplate 手动拼 URL,还觉得自己很“底层”。拜托,2024 年了,声明式客户端它不香吗?而且配合 Cursor 写 Feign 接口,AI 直接根据 Swagger 自动生成,省下至少半小时。
从零搭建:我的最小可行微服务骨架
第一步:注册中心选型
Eureka vs Nacos?我选 Nacos。
原因很简单:
- 支持 AP + CP 切换(Eureka 只支持 AP)
- 自带配置中心(不用再搭 Spring Cloud Config)
- 控制台颜值高(程序员也是人,看界面舒服很重要)
启动 Nacos 很简单,Docker 一行命令:
docker run -d \
--name nacos \
-p 8848:8848 \
-e MODE=standalone \
nacos/nacos-server:v2.2.3
注:生产环境务必集群部署,别学我本地开发图省事用 standalone。
第二步:服务提供者(user-service)
建一个 Spring Boot 项目,加依赖:
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
application.yml 配置:
server:
port: 8081
spring:
application:
name: user-service
cloud:
nacos:
discovery:
server-addr: localhost:8848
写个简单的 Controller:
@RestController
@RequestMapping("/users")
public class UserController {
@GetMapping("/{id}")
public User getUser(@PathVariable Long id) {
// 实际应查数据库,这里简化
return new User(id, "张三", "zhangsan@example.com");
}
}
启动后,打开 http://localhost:8848/nacos,就能看到 user-service 已注册。
第三步:服务消费者(order-service)
同样引入 Nacos 依赖,然后用 OpenFeign 调用 user-service:
@FeignClient(name = "user-service")
public interface UserClient {
@GetMapping("/users/{id}")
User getUser(@PathVariable("id") Long id);
}
在 OrderService 里注入:
@Service
public class OrderService {
@Autowired
private UserClient userClient;
public Order createOrder(Long userId, String item) {
User user = userClient.getUser(userId); // 远程调用
if (user == null) {
throw new IllegalArgumentException("用户不存在");
}
return new Order(user.getId(), item, LocalDateTime.now());
}
}
这时候你可能会问:万一 user-service 挂了怎么办?
——这就是为啥要加熔断!
第四步:熔断与降级
我用了 Resilience4j(Hystrix 已停止维护):
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-circuitbreaker-resilience4j</artifactId>
</dependency>
改造 Feign 调用:
@Service
public class OrderService {
@Autowired
private CircuitBreakerFactory cbFactory;
public Order createOrder(Long userId, String item) {
CircuitBreaker cb = cbFactory.create("user-service");
User user = cb.run(
() -> userClient.getUser(userId),
throwable -> fallbackUser(userId) // 降级逻辑
);
return new Order(user.getId(), item, LocalDateTime.now());
}
private User fallbackUser(Long userId) {
return new User(userId, "未知用户", "unknown@example.com");
}
}
这样,即使 user-service 宕机,订单还能创建,只是用户信息显示“未知”——总比整个下单流程卡死强。
AI 提效:我的秘密武器
说实话,要是纯手敲这些配置和接口,我可能早就放弃回单体了。但自从用上 Cursor + Codeium,效率翻倍。
举个例子:我要写一个带分页的用户查询接口,以前得翻半天 MyBatis 文档。现在在 Cursor 里输入:
“用 Spring Data JPA 实现分页查询,按注册时间倒序”
AI 直接生成:
public interface UserRepository extends JpaRepository<User, Long> {
Page<User> findAllByOrderByCreatedAtDesc(Pageable pageable);
}
连 Pageable 参数怎么传都给你注释好了。Codeium 更狠,写到一半自动补全 Feign 接口方法签名,连泛型都不用自己敲。
我不是鼓吹“AI 替代程序员”,但重复性配置、样板代码、文档查阅这类脏活累活,交给 AI 真的香。省下来的时间,我可以多想想架构设计——比如“这个服务边界划得对不对?”、“要不要加缓存?”。
数据库设计:别让微服务变成数据孤岛
很多团队拆完服务就不管数据库了,结果:
- 订单服务查不到用户昵称
- 库存服务不知道商品是否已下架
- 对账系统天天跑批处理关联七八张表
我的做法是:每个服务只读写自己的库,但允许通过 API 查询其他服务的数据。
比如 order-service 需要知道用户名?调 user-service 的 /users/{id},而不是直接连 user_db。
听起来有点啰嗦?但换来的是:
- 数据所有权清晰(谁改数据谁负责)
- 表结构变更不会波及全系统
- 审计日志天然按服务隔离
当然,高频查询可以加本地缓存(Caffeine + Redis),但缓存一致性要用事件驱动(比如用 RocketMQ 发用户更新事件)。
生产环境那些坑
你以为本地跑通就万事大吉?Too young.
坑 1:服务注册慢
Nacos 默认心跳间隔 5 秒,服务刚启动时可能还没注册完就被调用,导致 404。
解决方案:在 consumer 加 @LoadBalanced 的 RestTemplate 或 Feign 时,设置重试:
spring:
cloud:
loadbalancer:
retry:
enabled: true
坑 2:配置热更新失效
改了 Nacos 上的配置,服务没生效?因为你没加 @RefreshScope!
@RestController
@RefreshScope // 关键!
public class ConfigController {
@Value("${app.feature.toggle:false}")
private boolean featureToggle;
}
坑 3:链路追踪缺失
没有 TraceID,排查跨服务问题像大海捞针。
赶紧集成 SkyWalking 或 Zipkin。Spring Cloud Sleuth + Zipkin 三行配置搞定:
spring:
sleuth:
enabled: true
zipkin:
base-url: http://zipkin:9411
书籍推荐:少走弯路
光看博客容易碎片化。这几本书帮我建立了系统认知:
| 书名 | 亮点 | 适合人群 |
|---|---|---|
| 《Spring Microservices in Action》 | 实战导向,代码完整 | 有 Spring Boot 基础者 |
| 《微服务架构设计模式》 | 讲透服务拆分、数据一致性等难题 | 架构师/技术负责人 |
| 《凤凰项目》 | 小说体讲 DevOps 和微服务落地 | 所有工程师(尤其推荐给产品经理看) |
特别是《凤凰项目》,看完你会理解:微服务不只是技术问题,更是协作流程的变革。
最后:微服务不是终点,而是起点
折腾两周后,我的 demo 终于跑起来了。虽然离生产级还有距离(比如没加 OAuth2、没做灰度发布),但至少证明了一件事:在 AI 工具加持下,一个人也能快速搭建微服务骨架。
当然,真正的挑战从来不是技术,而是:
- 如何定义服务边界?
- 如何保证跨团队协作效率?
- 如何让测试同学不再崩溃?
在深圳这座快节奏的城市,技术迭代太快,我们很容易陷入“学新框架—搭新项目—又出新框架”的循环。但底层逻辑不变:架构服务于业务,工具服务于人。
下次再有人问我“Spring Cloud 难不难”,我会说:不难,只要你愿意深夜加班,配上一杯瑞幸,再打开 Cursor。
毕竟,代码可以 AI 写,但架构思维,还得自己长。

评论 0