前几天晚上加班到快十一点,我在公司楼下抽烟,跟我们组的小李聊起最近的项目,说实话那一刻我挺有感触的。我们这个系统啊,一开始是用传统的 Spring Boot 单体架构跑起来的,后来业务越来越多,接口调用越来越复杂,测试环境都能卡得半死。最后没办法,只能硬着头皮上 Spring Cloud 微服务,再用 Kubernetes(K8S) 去撑住。今天就把这个过程梳理一下,算是血泪经验吧。

为什么要上Spring Cloud

你想啊,一个单体项目,最早的时候就是 mvn clean package 打个 fat jar,扔到服务器上跑就行。但当服务动不动就十几个模块,甚至几十个模块的时候,问题就来了:

  • 一个小改动都得全量打包,上线慢得要死。

  • 部署全靠人肉,机器多了分分钟出错。

  • 某个模块挂了,整站都得跟着遭殃。

这时候,Spring Cloud 就显得特别合适。它给我们带来的核心能力主要是这几个:服务注册发现、负载均衡、配置中心、链路追踪、熔断降级。比如我们用 Eureka 或者 Nacos 做注册中心,用 Feign 来做服务调用,用 Spring Cloud Config 或者 Nacos 配置中心 来管配置。

代码例子随便贴一个,大家能感受到就行:

@FeignClient(name = "order-service")
public interface OrderClient {
    @GetMapping("/orders/{id}")
    Order getOrder(@PathVariable("id") Long id);
}

像上面这样,你在用户服务里直接调 orderClient.getOrder(1L),它底层帮你去注册中心找可用的服务实例,还能做负载均衡,贼省心。

微服务带来的“坑”

不过别以为用 Spring Cloud 就完事了,我刚上手的时候踩了不少坑。比如服务之间相互依赖严重,A 调 B,B 又调 C,结果链路一长,问题就复杂得要死。这个时候我们就必须配合 链路追踪(像 Sleuth + Zipkin 或者 SkyWalking)。不然出问题的时候,日志翻到怀疑人生。

还有就是 配置管理。以前我们写 application.properties,结果几十个微服务一多,哪台机器的配置忘了改,生产就出 bug。后来都改成 Nacos 配置中心,一处改全局生效。

上K8S是转折点

Spring Cloud 解决了服务治理问题,但部署还是个麻烦事。以前我们还用过 Docker Compose,一台机器跑几个容器勉强能撑住。但真到线上流量一上来,机器调度、自动扩缩容完全搞不定。那时候运维天天骂我们。

后来,我们一咬牙就上了 K8S。不得不说,K8S 真的改变了我的工作方式。你把每个微服务都打成一个 Docker 镜像,写个 Deployment + Service 配置,交给 K8S 去调度。再配上 Ingress 做流量入口,整个集群就跑起来了。

举个我们常用的 Deployment 配置:

apiVersion: apps/v1
kind:Deployment
metadata:
name:user-service
spec:
replicas:3
selector:
    matchLabels:
      app:user-service
template:
    metadata:
      labels:
        app:user-service
    spec:
      containers:
      -name:user-service
        image:my-registry/user-service:1.0.0
        ports:
        -containerPort:8080

这东西的妙处就在于:你不用再关心到底跑在哪台机器上,K8S 会自动分配节点、监控存活状态,挂了还能自动拉起来。

Spring Cloud + K8S怎么结合

有同学会问:Spring Cloud 不是已经有服务发现了吗?K8S 里不是也有 Service 吗?这俩会不会打架?

实际上,它们各有分工。K8S 自带的 Service + DNS 可以搞定服务发现,但 Spring Cloud 里的 Feign、Ribbon、Sentinel 这些生态能力还是得用。我们当时的做法是:用 Spring Cloud Alibaba + Nacos 做配置和注册,但底层容器编排完全交给 K8S。

这样有几个好处:

  1. 容器调度和扩缩容交给 K8S,我们只要写明副本数,剩下的不用管。

  2. 配置中心和熔断降级还是走 Spring Cloud,这样开发习惯不需要大改。

  3. 入口流量用 Ingress,再接上 Spring Cloud Gateway,既能做统一网关,也能利用 K8S 的流量管理。

一个真实的场景

我印象最深的一次是去年“618”,我们的订单系统被打爆了。当时用户量是平时的十倍以上。要是单体架构,早就跪了。那天晚上,我们只是在 K8S 控制台把 order-service 的副本数从 5 提到 20,集群自己把 Pod 分配到不同节点,几分钟流量就稳住了。整个过程开发几乎没动手,都是靠平台自动扩缩容。

这就是 K8S 的牛逼之处,它把“运维”这事儿做到了极致,开发只要关心业务代码。

CI/CD流水线的必要性

光有 K8S 还不够,你总不能每次改个代码都手动 docker build,然后再 kubectl apply 吧。我们后来接了 Jenkins + Harbor + K8S 一套流水线:

  1. 开发提交代码到 Git。

  2. Jenkins 自动打包,生成 Docker 镜像,推到 Harbor。

  3. Jenkins 再调用 kubectl apply,更新 Deployment。

  4. K8S 检测到新镜像,滚动更新服务。

整个过程全自动化,谁上线都不用盯着,回滚也就一条命令的事。

Java代码和K8S探针结合

在 K8S 里,最常见的就是 livenessProbe 和 readinessProbe。这个要跟 Java 应用结合,不然会出大事。

比如我们在 Spring Boot 里加个健康检查接口:

@RestController
public class HealthController {

    @GetMapping("/actuator/health")
    public String health() {
        return "OK";
    }
}

然后在 Deployment 里这样写:

livenessProbe:
  httpGet:
    path: /actuator/health
    port: 8080
  initialDelaySeconds: 10
  periodSeconds: 5

这样 K8S 就能定时探测你的服务,如果接口挂了,会自动重启容器。我们有一次就是靠这个救了命,要不然整个支付链路可能全崩。

监控和日志

Spring Cloud + K8S 要真正跑起来,监控和日志一定得跟上。不然线上出问题你连 Pod 都找不到。

我们后来用了这套:

  • 日志收集:EFK(Elasticsearch + Fluentd + Kibana)

  • 监控告警:Prometheus + Grafana

  • 链路追踪:SkyWalking

有了这些东西,你就能从调用链、容器运行情况、日志里快速定位问题。比如某个服务 QPS 突然飙升,Prometheus 告警一响,我们就知道是哪个 Pod 出了问题。

总结下来一句话:Spring Cloud 解决的是微服务开发层面的问题,K8S 解决的是运维和部署层面的问题。两者配合起来,才能把微服务真正跑稳。

当然,这条路也不是一蹴而就的。我们一路踩过的坑数不清:配置同步失败、Pod 滚动更新失败、镜像版本混乱……这些问题都得慢慢解决。

不过现在回头看,Spring Cloud + K8S 确实是目前最靠谱的一套微服务落地方案。它不像一些“纯理论”的框架,是真正经历过大流量考验的。

Logo

码道开发者社区,聚焦华为云码道 CodeArts 代码智能体,沉淀 Agent、Skill、鸿蒙开发实战内容,供开发者查阅资料、交流技术、分享工程实践

更多推荐