深夜敲代码的我,如何用 Spring Cloud 把微服务从零搭起来?

宋建国
2026-04-11 14:37
阅读 291

上周五晚上十一点半,深圳南山科技园还亮着不少灯。我在工位上盯着屏幕,脑子里全是 DiscoveryClient 的报错日志,咖啡已经凉了第三杯。产品经理昨天刚提了个需求:“咱们能不能把下单和库存拆成两个服务?双 11 快到了,得扛住流量。”

说真的,一开始我是拒绝的——单体架构跑得好好的,何必自找麻烦?但转念一想:腾讯系公司现在哪个不是微服务?跳槽面试问 Spring Cloud 都成基础题了。再加上最近被 Cursor 和 Codeium 宠坏了,写点配置都靠 AI 提效,说不定真能搞定。

于是,我决定从零开始搞一套 Spring Cloud 微服务。不为别的,就为了下次线上事故时能理直气壮地说:“这锅不该我背,是注册中心挂了。”


起手式:为什么非得用微服务?

先别急着上 Eureka 或 Nacos。我踩过最大的坑,就是团队里没人搞清楚“我们到底需不需要微服务”。

去年有个项目,后端就仨人,硬是拆了六个服务,结果每天花两小时处理服务间调用超时、链路追踪缺失、配置同步失败……测试同学直接在群里@我:“你这接口返回 500,到底是哪个服务崩了?” 我只能苦笑:“建议重启宇宙。”

所以,微服务不是银弹,而是成本换弹性。如果你的系统:

  • 用户量不大(比如日活 < 1万)
  • 团队小(< 5人)
  • 功能耦合深(改一个功能要动七八个模块)

那你可能更适合先优化单体架构,而不是一头扎进分布式地狱。

但如果你像我一样,在深圳这种卷王之城,老板开口闭口“高可用、弹性伸缩、秒级扩容”,那微服务就是必修课了。而且——实话实说——Spring Cloud 现在生态太成熟了,入门门槛比三年前低太多。


架构设计:别只想着“能跑就行”

我见过太多团队把微服务做成“分布式单体”:每个服务数据库还是共享的,API 接口随意调用,没有熔断降级,上线全靠手动改 YAML。结果一到大促,雪崩式宕机,运维半夜打电话骂人。

所以这次,我给自己定了三条铁律:

  1. 每个服务独享数据库(哪怕是同一个 MySQL 实例下的不同库)
  2. 服务间通信必须走 Feign + OpenFeign 声明式调用,禁止硬编码 IP
  3. 所有对外接口必须有熔断策略(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,排查跨服务问题像大海捞针。

赶紧集成 SkyWalkingZipkin。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

最热最新
暂无评论
匿名用户Lv.1
0
影响力
0
文章
0
粉丝