Spring Cloud 微服务入门:别再被产品经理当工具人了

张刚
2025-12-21 17:08
阅读 402

去年双11前两周,我们组接了个“简单”需求:把老掉牙的单体电商系统拆成微服务。PM一脸轻松地说:“就是换个架构嘛,你们后端不是天天吹微服务吗?”我差点当场表演一个原地去世。

我在这家外包公司干了快四年,带过实习生、熬过通宵、背过锅,也写过无数个“明天上线”的需求。最近两年一直在同一个客户项目里打转,技术栈还是Spring Boot那一套。但这次,甲方爸爸明确要求用 Spring Cloud 搭建微服务体系,还甩过来一堆“高可用、低延迟、弹性伸缩”的 PPT 话术。

说实话,一开始我是拒绝的。毕竟我们团队连 Redis 都还在用 3.2,运维大哥看到 YAML 文件就头疼。但想到简历上还缺个“微服务实战”经历,加上最近在偷偷研究 Rust(觉得 Go 太卷了,Rust 内存安全真香),心想:不如趁机搞点硬核东西,说不定能跳槽拿个好 offer。


为啥选 Spring Cloud?而不是 Go?

先说结论:不是技术最优,而是团队最熟

我知道现在很多人吹 Go 在微服务场景下性能更好、编译快、部署轻。面试题挑战里也老问“Go 和 Java 做微服务哪个强”。但现实是——我们组五个后端,三个只会 Java,一个会 Python,剩下一个实习生还在学 MyBatis。

换 Go?除非甲方愿意多付三倍预算重写所有业务逻辑,外加培训三个月。而 Spring Cloud 虽然“笨重”,但它和我们现有的 Spring Boot 无缝衔接,Eureka、Feign、Hystrix 这些组件文档齐全,Stack Overflow 上问题一搜一大把。对,我们就是那种“宁可慢十倍,不愿踩新坑”的保守派外包团队。

不过我也做了对比调研,列了个小表格:

维度 Spring Cloud (Java) Go + Gin/Echo
学习成本 低(团队已熟悉) 中高(需学新语言+生态)
启动速度 慢(JVM 冷启动 2-5s) 极快(毫秒级)
内存占用 高(通常 512MB+) 低(50MB 足够)
生态成熟度 极高(Netflix 套件+阿里增强) 快速成长但碎片化
调试体验 IDEA 一键 Debug Delve 工具链稍弱
面试题挑战热度 高(大厂必问) 上升中

最后拍板:用 Spring Cloud。老板要的是“稳”,不是“酷”。


实战:从零搭起服务注册与调用

第一步当然是服务发现。我选了 Eureka,虽然 Consul 更强大,但 Eureka 对新手友好,而且我们不需要多数据中心同步这种高级功能。

# eureka-server 的 application.yml
server:
  port: 8761

eureka:
  client:
    register-with-eureka: false
    fetch-registry: false

启动后访问 http://localhost:8761,看到那个熟悉的蓝色界面,心里踏实了——至少没报错。

接着是用户服务(user-service)和订单服务(order-service)。关键配置:

# user-service
spring:
  application:
    name: user-service
server:
  port: 8081

euryka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/

然后用 OpenFeign 调用:

@FeignClient(name = "user-service")
public interface UserClient {
    @GetMapping("/users/{id}")
    User getUserById(@PathVariable("id") Long id);
}

看起来很美好,对吧?结果上周五晚上测试时炸了——订单服务调 user-service 报 Load balancer does not contain an instance for the service user-service

查了俩小时,才发现是 服务名大小写问题!YAML 里写的是 user-service,但 Feign 注解里手误写成 User-Service。Spring Cloud 默认区分大小写,直接找不到实例。当时真的想砸键盘。

教训:服务名统一用小写+短横线,团队约定死


容错与熔断:别让一个服务拖垮全家

微服务最怕雪崩。用户服务挂了,订单服务跟着崩,支付服务也挂……去年我们就因为没做熔断,导致整个系统瘫痪 40 分钟,被甲方扣了 20% 尾款。

这次我果断加上 Resilience4j(替代老旧的 Hystrix):

@FeignClient(name = "user-service")
public interface UserClient {

    @CircuitBreaker(name = "userService", fallbackMethod = "fallbackGetUser")
    @GetMapping("/users/{id}")
    User getUserById(@PathVariable("id") Long id);

    default User fallbackGetUser(Long id, Exception ex) {
        log.warn("UserService 熔断,返回默认用户", ex);
        return new User(id, "DELETED_USER");
    }
}

配合配置:

resilience4j.circuitbreaker:
  instances:
    userService:
      failure-rate-threshold: 50
      minimum-number-of-calls: 5
      wait-duration-in-open-state: 10s

测试时故意 kill 掉 user-service,订单服务立刻返回兜底数据,日志里清清楚楚。运维大哥看了都说:“这回稳了。”


资源消耗?别只盯着 CPU

很多人以为微服务只是代码拆分,其实 资源规划 才是坑。我们最初给每个服务分配 1G 内存,结果压测时频繁 Full GC。

后来调整策略:

  • 核心服务(如支付):2G 内存 + G1 GC
  • 边缘服务(如通知):512MB + ZGC(Java 17)
  • 所有服务启用 -XX:+UseContainerSupport,适配 Docker 内存限制

另外,数据库也得重新设计。以前单体用一张大表,现在 user-service 只管用户信息,order-service 自己维护订单表,通过 Saga 模式事件驱动 保证最终一致性。别再想着跨库 join 了,那都是上个时代的幻觉。


为什么我不推荐新人直接上 Spring Cloud?

写到这里,突然想起上周实习生问我:“哥,我准备面试,是不是得把 Spring Cloud 全家桶背下来?”

我苦笑:“背不如懂。面试题挑战里问你 Nacos 和 Eureka 区别,你答‘Nacos 支持 AP/CP 切换,Eureka 只是 AP’,但如果你没在线上被注册中心脑裂搞崩溃过,根本体会不到 CP 的价值。”

Spring Cloud 学起来容易,但 生产环境的水太深

  • 网络抖动导致服务误剔除
  • 配置中心刷新不生效
  • 链路追踪 Span ID 丢失
  • 网关路由规则冲突

这些都是外包项目里血泪教训。所以我建议:先用单体跑通业务,等流量真上来、团队真壮大了,再拆微服务。别为了“架构先进”而架构。


最后:关于 Go 和未来的碎碎念

虽然这次用了 Spring Cloud,但我没放弃 Go。最近用它写了个内部日志收集 agent,内存占用只有 Java 版的 1/5,启动快得飞起。也许下次项目,如果甲方预算充足、时间宽松,我会力推 Go + gRPC + etcd 的组合。

但在当下这个“周五提需求周一上线”的外包世界里,能快速交付、稳定运行、让 PM 闭嘴的技术,才是好技术

Spring Cloud 不完美,但它让我们在 deadline 前活了下来。这就够了。

对了,如果你也在外包公司挣扎,欢迎交流。顺便,有没有招 Rust 后端的?我简历 ready 了 😅

评论 0

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