Spring Cloud从零开始:微服务入门指南

霸气终端
2025-12-17 02:42
阅读 292

去年双11前夜,我们组还在疯狂压测新上的微服务架构。运维同事突然在群里@我:“注册中心又崩了,你们这Spring Cloud写的啥玩意儿?” 我盯着满屏的Connection refused日志,手里的咖啡都凉了——那一刻真的想砸电脑。

作为GitHub Copilot付费用户(快两年了,真香警告⚠️),平时写CRUD全靠它续命;再加上重度依赖ChatGPT和Claude辅助开发,自以为能“优雅”地搞定一切。结果现实狠狠打了脸:微服务不是把单体拆开就完事了,网络分区、服务雪崩、配置漂移……这些坑一个没踩过,都不好意思说自己搞过后端。

最近在准备跳槽,边刷LeetCode边啃《Spring Cloud实战》,顺便把公司老项目重构了一遍。今天这篇技术分享,就是想给那些和我一样被领导“建议”转型微服务、或者为了求职突击Spring Cloud的兄弟们,少走点弯路。


为啥非得上微服务?别被忽悠了!

先泼盆冷水:不是所有项目都适合微服务

我们之前有个内部审批系统,用Python FastAPI写的,就仨接口,日活不到500。产品经理非要“拥抱云原生”,硬是让我拆成5个服务。结果呢?部署复杂度翻倍,本地调试要起8个容器,连改个字段都要跨三个Repo提PR。测试同学天天追着我问:“你这个服务挂了,是不是又改了API契约?”

所以,先问自己三个问题:

  • 单体应用是否已经大到编译一次要10分钟?
  • 团队是否超过10人,经常出现代码冲突?
  • 是否有明确的业务边界可以拆分(比如用户中心、订单、支付)?

如果答案都是NO,老老实实用单体吧,别为了简历好看瞎折腾。


从单体到微服务:我的血泪迁移路线

我们原来的电商后台是个典型的Spring Boot单体,数据库MySQL + Redis缓存,前端Vue。随着业务增长,订单模块和商品模块耦合严重,改个促销逻辑动不动就影响库存扣减。

领导拍板:“拆!用Spring Cloud!”
我内心OS:行吧,反正求职时写“主导微服务架构落地”比“维护老旧单体”听起来高大上多了。

第一步:服务拆分——别贪多!

很多人一上来就想拆10个服务,结果光服务发现就搞不定。我的建议是:先拆出2~3个核心服务,跑通整个链路再说。

我们第一步只拆了:

  • user-service(用户鉴权)
  • order-service(订单创建)
  • gateway(API网关)

其他功能暂时保留在老单体里,通过Feign调用新服务。这样既能验证架构,又不影响线上业务。

💡 Copilot小技巧:写Feign Client的时候,直接注释写“调用user-service的/v1/users/{id}接口”,Copilot秒生成带@PathVariable的接口定义,省得翻Swagger文档。

第二步:服务注册与发现——Eureka还是Nacos?

Spring Cloud官方推荐Eureka,但国内更多用Nacos(阿里开源,支持配置中心)。我们选了Nacos,原因很简单:一个组件搞定服务发现+配置管理,运维少骂我两句。

# bootstrap.yml (注意:必须是bootstrap,不是application!)
spring:
  application:
    name: order-service
  cloud:
    nacos:
      discovery:
        server-addr: nacos-server:8848
      config:
        server-addr: nacos-server:8848
        file-extension: yaml

踩坑预警
本地开发时,如果Nacos连不上,服务会直接启动失败(不像Eureka有自我保护模式)。后来我在application-local.yml里加了spring.cloud.nacos.discovery.enabled=false,本地调试再也不用开Nacos了。


关键组件实战:别只抄官网Demo

网关(Gateway)——你的流量总闸

以前所有请求直怼后端,现在必须经过网关。除了路由转发,我们还加了:

  • JWT鉴权(无效token直接拦截)
  • 限流(用Redis + Lua脚本,防刷)
  • 请求日志(记录traceId,方便链路追踪)
// 自定义GlobalFilter示例
@Component
public class AuthFilter implements GlobalFilter {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String token = exchange.getRequest().getHeaders().getFirst("Authorization");
        if (token == null || !validateToken(token)) {
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }
        return chain.filter(exchange);
    }
}

血泪教训
上周五晚上加班,因为网关的strip-prefix配错了,导致/api/order/create被转发成/order/create,下游服务404。测试环境没覆盖到,差点上线事故。永远不要相信默认配置!

服务调用——Feign vs RestTemplate

一开始图省事用RestTemplate,结果手动拼URL、处理异常,代码丑得没法看。换成OpenFeign后,配合@LoadBalanced,服务名直接当host用:

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

性能提示
Feign默认用JDK HttpURLConnection,吞吐量低。记得加上Ribbon(或Spring Cloud LoadBalancer)并替换为Apache HttpClient:

feign:
  httpclient:
    enabled: true

配置中心——告别application-prod.yml满天飞

以前改个数据库连接池大小,要重新打包部署。现在所有配置扔Nacos,动态刷新:

@RestController
@RefreshScope // 关键注解!
public class ConfigController {
    @Value("${app.max-retry:3}")
    private int maxRetry;
}

运维再也不用半夜爬起来改配置了(感动哭😭)。


容错与监控:别等线上炸了才后悔

Hystrix已死,Resilience4j当立

Spring Cloud Netflix全家桶基本停更了,Hystrix也进了坟墓。现在主流是Resilience4j,轻量级、函数式编程友好。

// 订单服务调用用户服务,带熔断
CircuitBreaker circuitBreaker = CircuitBreaker.ofDefaults("userService");
Supplier<UserDTO> decorated = CircuitBreaker
    .decorateSupplier(circuitBreaker, () -> userClient.getUser(userId));

try {
    return decorated.get();
} catch (CallNotPermittedException e) {
    // 熔断了,返回兜底数据
    return fallbackUser();
}

分布式链路追踪——Zipkin救我狗命

微服务最怕“请求丢了”。集成Sleuth + Zipkin后,每个请求生成唯一traceId,跨服务传递。排查问题时,直接搜ID就能看到完整调用链:

[order-service] --> [user-service] --> [auth-service]
     |                   |
     v                   v
 DB update           Cache hit

上次双11,发现某个接口慢,一看Zipkin:原来user-service调用了三次auth-service(循环依赖bug)。没这工具,光看日志得找到明年。


数据库设计:微服务的命门

每个服务必须独占数据库! 别再搞什么“共享用户表”了。

我们拆分时,把原单体的users表完整迁移到user-service的DB,其他服务通过API获取用户信息。虽然JOIN没了,但换来的是独立演进能力——user-service想换MongoDB?随便换,只要API契约不变。

接口设计原则

  • 返回DTO,别暴露Entity(避免耦合)
  • 版本化API(/v1/users
  • 错误码统一(用code字段,别只靠HTTP状态码)

生产环境避坑清单

问题 解决方案 教训来源
服务启动顺序依赖 @DependsOn或健康检查延迟 上线时order连不上user
配置未刷新 检查@RefreshScope + Nacos监听 改了超时时间没生效
网关内存溢出 调整Netty缓冲区 + 限流 压测时OOM
本地调试连不上Nacos spring.profiles.active=local 凌晨三点debug

和Python项目的协作?别慌!

虽然主栈是Java,但我们有些AI模型服务是用Python写的(比如推荐算法)。怎么让Spring Cloud调用它们?

  • 方案1:Python服务也注册到Nacos(用nacos-sdk-python
  • 方案2:通过API网关暴露HTTP接口,Java服务用Feign调

我们选了方案2,因为Python团队不想碰服务注册。网关统一做认证+限流,两边都省心。


给求职者的真心话

最近面了几家公司,面试官一听“Spring Cloud”,必问:

  • 服务雪崩怎么防?
  • 配置中心如何保证高可用?
  • 网关和Nginx有什么区别?

别只会背概念! 结合你的真实项目讲:

“我们在订单服务加了Resilience4j熔断,阈值设为失败率50%,窗口10秒。双11期间user-service抖动,自动降级到缓存数据,没影响下单。”

这种回答,比“Hystrix可以熔断”强100倍。


最后:微服务不是银弹

折腾半年,系统确实更灵活了——用户模块用Kotlin重写,订单服务上了ShardingSphere分库,互不影响。但代价是:本地开发环境要起10个服务,CI/CD流水线复杂到运维想辞职。

记住
微服务解决的是组织扩展性问题,不是技术炫技。如果你的团队就3个人,单体+模块化可能是更好的选择。

不过嘛……既然要求职,简历上不写点“微服务”“云原生”,HR筛简历那关都过不了(笑)。所以,该学还得学,但心里要有数。


搞定这套架构后,上周终于把简历更新了:“主导Spring Cloud微服务架构设计与落地”。投出去3天,猎头电话就没停过。看来这波血泪没白流啊!

(P.S. 感谢Copilot帮我写了80%的样板代码,不然光配YAML就得秃了。)

评论 0

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