文章

云原生与微服务面试题 —— 从容器化到 Service Mesh 的深度问答

覆盖微服务架构、服务发现、API 网关、服务通信(gRPC/MQ)、Docker、Kubernetes、云原生(12-Factor/CNCF)、Service Mesh、可观测性、CI/CD 十大核心主题,30 道高频面试题附架构图解

云原生与微服务面试题 —— 从容器化到 Service Mesh 的深度问答

云原生和微服务是现代后端工程师面试的高频主题——不仅考察你对单个技术的理解,更考察你如何将容器、编排、网关、服务网格等组件组合成一个弹性、可观测、易迭代的系统

这篇文章的组织思路:每道题先给出”一句话记忆点”,再展开原理和架构思考,最后给出面试回答要点。侧重”为什么这么设计”而非死记硬背。


第一部分:微服务架构基础

Q1:单体架构和微服务架构有什么区别?什么时候该用微服务?

记忆点:单体是所有功能打包成一个进程部署,微服务是按业务能力拆分为多个独立部署的小服务。不要为了微服务而微服务——团队小、业务简单时单体更高效。

维度单体架构微服务架构
部署整体打包,一次部署各服务独立部署
技术栈统一各服务可选不同语言/框架
扩展整体水平扩展按服务粒度独立扩展
故障隔离一个模块崩溃全部挂故障隔离在单个服务
开发效率小团队快,大团队慢大团队并行开发效率高
运维复杂度高(需要服务发现、链路追踪等基础设施)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
单体架构:
┌─────────────────────────────────┐
│           单体应用               │
│  ┌──────┐ ┌──────┐ ┌──────┐    │
│  │用户模块│ │订单模块│ │支付模块│    │
│  └──┬───┘ └──┬───┘ └──┬───┘    │
│     └────────┴────────┘         │
│          共享数据库              │
│       ┌──────────┐              │
│       │  MySQL   │              │
│       └──────────┘              │
└─────────────────────────────────┘

微服务架构:
┌──────┐    ┌──────┐    ┌──────┐
│用户服务│    │订单服务│    │支付服务│
└──┬───┘    └──┬───┘    └──┬───┘
   │           │           │
┌──┴──┐    ┌──┴──┐    ┌──┴──┐
│UserDB│    │OrderDB│   │PayDB│
└─────┘    └──────┘    └─────┘
每个服务有自己的数据库(Database per Service)

什么时候从单体转微服务:

  1. 团队规模超过 2 个 Pizza Team(>10 人),代码冲突频繁
  2. 部分模块需要独立扩展(如搜索服务 CPU 密集,订单服务 IO 密集)
  3. 需要不同技术栈(如 ML 模块用 Python,核心业务用 Java)
  4. 发布周期需要解耦(A 功能不应等 B 功能一起上线)

面试加分: 微服务不是银弹。它引入了分布式事务、网络延迟、数据一致性、运维复杂度等问题。正确的路径是:先做好单体的模块化,再按需拆分。Martin Fowler 称之为”Monolith First”。

Q2:微服务拆分的原则是什么?怎么确定服务边界?

记忆点:按业务能力(Business Capability)拆分,而非按技术层拆分。每个服务对应一个限界上下文(Bounded Context),拥有独立的数据和生命周期。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
✗ 错误拆分(按技术层):
  ┌──────────────┐
  │  前端服务     │
  ├──────────────┤
  │  业务逻辑服务  │  ← 所有业务逻辑混在一起
  ├──────────────┤
  │  数据访问服务  │
  └──────────────┘

✓ 正确拆分(按业务领域):
  ┌──────┐  ┌──────┐  ┌──────┐  ┌──────┐
  │用户域 │  │商品域 │  │订单域 │  │支付域 │
  │      │  │      │  │      │  │      │
  │API   │  │API   │  │API   │  │API   │
  │Logic │  │Logic │  │Logic │  │Logic │
  │Data  │  │Data  │  │Data  │  │Data  │
  └──────┘  └──────┘  └──────┘  └──────┘
  每个域是自治的垂直切片

拆分原则:

  1. 单一职责:一个服务只做一件事(用户管理、库存管理)
  2. 高内聚低耦合:服务内部高度相关,服务之间交互最少
  3. 数据自治:每个服务管自己的数据,不直接读别人的数据库
  4. 可独立部署:修改一个服务不需要重新部署其他服务

面试加分: DDD(领域驱动设计)是微服务拆分的最佳理论工具。通过事件风暴(Event Storming)识别领域事件和聚合根,自然就能划出限界上下文。

Q3:微服务之间如何处理分布式事务?

记忆点:微服务中避免使用 2PC(两阶段提交),通常用 Saga 模式——把一个全局事务拆成多个本地事务,每个本地事务有对应的补偿操作。失败时反向执行补偿。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
Saga 编排模式(Choreography):
  订单服务        库存服务        支付服务
     │              │              │
     │ 创建订单      │              │
     ├─── OrderCreated 事件 ──────→│
     │              │              │
     │              │← 扣减库存     │
     │              ├── StockReserved ──→│
     │              │              │
     │              │              │← 扣款
     │              │              ├── PaymentDone
     │              │              │
  成功:三个本地事务都完成
  失败:如果支付失败 → 发 PaymentFailed 事件
        → 库存服务执行补偿(回滚库存)
        → 订单服务执行补偿(取消订单)

Saga 编排模式(Orchestration):
  ┌────────────┐
  │  Saga 编排器 │  ← 中心协调者
  └─────┬──────┘
        │ 1. 创建订单
        ├──→ 订单服务
        │ 2. 扣减库存
        ├──→ 库存服务
        │ 3. 扣款
        ├──→ 支付服务
        │ 失败时反向补偿
        └──→ ...
方案一致性复杂度适用场景
2PC(两阶段提交)强一致性高,阻塞单数据中心、传统数据库
TCC(Try-Confirm-Cancel)强一致性高,侵入业务金融、资金场景
Saga最终一致性电商、订单等大多数场景
本地消息表最终一致性简单场景

面试加分: Saga 的关键挑战是幂等性——补偿操作可能被重复调用,每个参与者必须保证幂等。常用手段:唯一事务 ID + 状态机。


第二部分:服务发现与注册

Q4:什么是服务发现?为什么微服务需要它?

记忆点:微服务实例的 IP 和端口是动态变化的(容器重启、自动扩缩容),不能硬编码地址。服务发现让消费者能动态找到提供者的地址——分为客户端发现和服务端发现两种模式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
客户端发现(Client-Side Discovery):
  ┌──────┐    1. 查询      ┌────────────┐
  │消费者 │ ──────────────→ │ 服务注册中心  │
  │      │ ←────────────── │(Eureka/Nacos)│
  │      │  2. 返回实例列表  └────────────┘
  │      │                     ↑
  │      │  3. 客户端负载均衡   │ 心跳注册
  │      │     选择一个实例     │
  │      │ ──→ Provider-1    Provider-1
  └──────┘                   Provider-2
                             Provider-3

服务端发现(Server-Side Discovery):
  ┌──────┐    1. 请求     ┌───────────┐    2. 路由    ┌──────────┐
  │消费者 │ ────────────→ │ 负载均衡器  │ ──────────→ │Provider-X│
  └──────┘               │(Nginx/ALB) │              └──────────┘
                         └─────┬─────┘
                               │ 查询注册中心
                         ┌─────┴──────┐
                         │ 服务注册中心  │
                         └────────────┘
注册中心一致性模型语言生态特点
EurekaAP(最终一致)Java/Spring Cloud自我保护机制,停止维护
NacosAP + CP 可切换Java 为主,多语言 SDK同时支持服务发现和配置管理
ConsulCP(Raft)多语言内置健康检查、KV 存储、多数据中心
etcdCP(Raft)Go/K8s 生态K8s 底层存储,轻量级
ZooKeeperCP(ZAB)Java老牌,Kafka/Hadoop 依赖

面试加分: K8s 环境下通常不需要独立的注册中心——K8s Service + CoreDNS 已经实现了服务发现。Pod 通过 service-name.namespace.svc.cluster.local 即可访问目标服务。

Q5:服务注册中心的健康检查机制是怎样的?

记忆点:注册中心通过心跳(Heartbeat)或主动探测(Health Check)判断实例是否存活。心跳超时则剔除实例。Eureka 有自我保护机制——短时间大量实例掉线时不剔除,防止网络抖动导致误删。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
健康检查流程:
  Provider ──心跳(每30s)──→ 注册中心
                              │
                    超过 90s 未收到心跳?
                     ┌────┴────┐
                     │ 是      │ 否
                 标记为不健康   继续
                 从服务列表剔除

Eureka 自我保护:
  最近 15 分钟心跳成功比例 < 85%?
  → 开启自我保护模式
  → 不剔除任何实例(宁可访问到不健康的,也不全部摘除)
  → 网络恢复后自动退出保护模式

三种健康检查方式:

  1. 客户端心跳(Eureka/Nacos):服务主动上报,注册中心被动接收
  2. 服务端探测(Consul):注册中心主动调用服务的 /health 接口
  3. TTL 模式:服务定期续约 TTL,过期自动删除(类似 Redis 过期)

Q6:配置中心的作用和实现原理?

记忆点:配置中心把散落在各服务的配置文件集中管理,支持动态更新、灰度发布、环境隔离。核心原理是”推”或”拉”——客户端定期拉取或服务端主动推送配置变更。

1
2
3
4
5
6
7
8
9
10
11
12
13
配置中心架构:
  ┌──────────────────────────────────┐
  │          配置中心(Nacos/Apollo)   │
  │  ┌───────┐ ┌───────┐ ┌───────┐  │
  │  │dev 环境│ │test环境│ │prod环境│  │
  │  └───────┘ └───────┘ └───────┘  │
  │         修改配置 → 推送变更        │
  └──────┬─────────┬─────────┬──────┘
         │         │         │
    ┌────┴──┐ ┌───┴───┐ ┌──┴────┐
    │服务 A  │ │服务 B  │ │服务 C  │
    │热更新   │ │热更新   │ │热更新   │
    └───────┘ └───────┘ └───────┘
配置中心推/拉模式特点
Nacos长轮询(Long Polling)服务发现+配置一体化
Apollo推+拉结合灰度发布、权限管理、审计
Spring Cloud Config拉(需配合 Bus 推送)基于 Git 存储
etcd/Consul KVWatch 机制轻量级,适合 K8s

面试加分: 配置中心的核心挑战是一致性——修改配置后,所有实例什么时候生效?Apollo 的做法是:管理员发布 → 通知 Config Service → 实时推送到客户端(<1s 生效),同时客户端每 5 分钟兜底拉取。


第三部分:API 网关与服务通信

Q7:API 网关的作用是什么?和反向代理有什么区别?

记忆点:API 网关是微服务的统一入口,不仅做反向代理(路由转发),还承担认证鉴权、限流熔断、协议转换、日志监控等横切关注点。反向代理只管转发,网关管”治理”。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
没有网关:
  客户端需要知道每个服务的地址
  ┌──────┐ ──→ 用户服务 :8001
  │ 客户端 │ ──→ 订单服务 :8002
  │      │ ──→ 支付服务 :8003
  └──────┘ ──→ 商品服务 :8004

有网关:
  客户端只需要知道网关地址
  ┌──────┐     ┌──────────────┐     ┌──────────┐
  │ 客户端 │────→│   API 网关    │────→│ 用户服务   │
  └──────┘     │              │────→│ 订单服务   │
               │ • 路由转发     │────→│ 支付服务   │
               │ • 认证鉴权     │────→│ 商品服务   │
               │ • 限流熔断     │     └──────────┘
               │ • 请求聚合     │
               │ • 协议转换     │
               │ • 日志监控     │
               └──────────────┘
网关语言特点
KongLua/OpenResty插件生态丰富,性能高
Spring Cloud GatewayJavaSpring 生态原生,响应式
APISIXLua/OpenResty国产,动态路由,Dashboard
EnvoyC++云原生标配,Istio 数据面
Nginx + LuaC/Lua轻量,需自行实现治理功能

面试加分: BFF(Backend For Frontend)模式——为不同客户端(Web/App/小程序)设置不同的网关层,每个 BFF 聚合后端服务并裁剪数据格式,避免”一个接口适配所有端”。

Q8:gRPC 和 REST 的区别?什么场景用 gRPC?

记忆点:REST 用 HTTP/1.1 + JSON,人类可读但性能一般。gRPC 用 HTTP/2 + Protobuf,二进制序列化性能高,支持双向流式通信。微服务内部通信优先用 gRPC,对外暴露用 REST。

维度RESTgRPC
协议HTTP/1.1(也可 HTTP/2)HTTP/2
数据格式JSON(文本)Protobuf(二进制)
性能一般高(序列化快 5-10x,体积小 3-5x)
流式通信不支持(需 WebSocket)原生支持四种模式
浏览器支持原生支持需要 gRPC-Web 代理
可读性低(二进制)
代码生成手动写自动生成客户端/服务端代码
1
2
3
4
5
gRPC 四种通信模式:
  1. Unary(一元):    客户端 ──请求──→ 服务端 ──响应──→ 客户端
  2. Server Stream:   客户端 ──请求──→ 服务端 ═══多条响应═══→ 客户端
  3. Client Stream:   客户端 ═══多条请求═══→ 服务端 ──响应──→ 客户端
  4. Bidirectional:   客户端 ═══请求═══⇄═══响应═══ 服务端

适用场景:

  • 用 gRPC:微服务间高频内部调用、实时数据流、低延迟要求
  • 用 REST:对外 API、第三方集成、浏览器直接调用、简单 CRUD

面试加分: Protobuf 的向前/向后兼容性很好——新增字段用新编号,旧客户端忽略未知字段,新客户端对缺失字段用默认值。这在微服务独立部署时非常重要。

Q9:消息队列在微服务中扮演什么角色?

记忆点:消息队列实现服务间的异步解耦——生产者不需要等消费者处理完,削峰填谷应对流量突增,还能保证消息不丢失实现最终一致性。核心场景:异步处理、解耦、削峰。

1
2
3
4
5
6
7
8
9
10
11
12
同步调用的问题:
  用户下单 → 订单服务 → 同步调用库存服务 → 同步调用支付服务 → 同步调用通知服务
  总延迟 = 50ms + 80ms + 200ms + 100ms = 430ms
  任一服务挂掉,整个链路失败

异步消息队列:
  用户下单 → 订单服务 → 发消息到 MQ → 返回用户(50ms)
                          │
                ┌─────────┼─────────┐
                ↓         ↓         ↓
            库存服务   支付服务   通知服务
            异步消费   异步消费   异步消费
消息队列吞吐量延迟特点
Kafka极高(百万/s)ms 级日志、大数据、事件流
RocketMQ高(十万/s)ms 级事务消息、延时消息、电商场景
RabbitMQ中(万/s)μs 级路由灵活、协议丰富、中小规模
Pulsar极高ms 级存算分离、多租户、云原生

消息可靠性三板斧:

  1. 生产者确认:消息写入 Broker 后返回 ACK
  2. Broker 持久化:消息落盘 + 副本同步
  3. 消费者手动 ACK:处理完再确认,失败重试

面试加分: 消息队列要防止重复消费——网络抖动可能导致同一条消息被投递多次。解决方案:消费者做幂等处理(数据库唯一键、Redis 去重、状态机)。


第四部分:容器化与 Docker

Q10:Docker 的核心概念是什么?容器和虚拟机有什么区别?

记忆点:Docker 容器是进程级别的隔离,共享宿主机内核,启动秒级、体积 MB 级。虚拟机是操作系统级别的隔离,有独立内核,启动分钟级、体积 GB 级。容器 = 应用 + 依赖,虚拟机 = 应用 + 依赖 + 完整 OS。

1
2
3
4
5
6
7
8
9
10
11
12
13
虚拟机 vs 容器:
┌─────────────────┐     ┌─────────────────┐
│   App A │ App B  │     │  App A │ App B   │
├─────────┤────────┤     ├────────┤─────────┤
│ Bins/Libs│Bins/Libs│    │Bins/Libs│Bins/Libs│
├─────────┤────────┤     ├────────┴─────────┤
│ Guest OS│Guest OS│     │   Docker Engine   │
├─────────┴────────┤     ├──────────────────┤
│   Hypervisor     │     │    Host OS        │
├──────────────────┤     ├──────────────────┤
│   Hardware       │     │   Hardware        │
└──────────────────┘     └──────────────────┘
    虚拟机                      容器

Docker 三大核心概念:

  • 镜像(Image):只读模板,分层存储(UnionFS),类比”类”
  • 容器(Container):镜像的运行实例,可写层,类比”对象”
  • 仓库(Registry):存储和分发镜像的服务(Docker Hub、Harbor)

Docker 的隔离原理:

  • Namespace:隔离进程 ID、网络、文件系统、用户等(看不到别的容器)
  • Cgroups:限制 CPU、内存、IO 资源(不能用超)
  • UnionFS:分层文件系统,镜像层共享 + 容器层可写

Q11:Dockerfile 的最佳实践有哪些?

记忆点:减少镜像层数、利用构建缓存、多阶段构建减小体积、不用 root 运行、用 .dockerignore 排除无关文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# ✗ 不好的 Dockerfile
FROM ubuntu:latest
RUN apt-get update
RUN apt-get install -y python3
RUN apt-get install -y pip
COPY . /app
RUN pip install -r requirements.txt
CMD ["python3", "app.py"]
# 问题:层太多、基础镜像太大、用了 latest 标签、root 运行

# ✓ 优化后的 Dockerfile(多阶段构建)
FROM python:3.12-slim AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

FROM python:3.12-slim
WORKDIR /app
RUN useradd -r appuser
COPY --from=builder /usr/local/lib/python3.12/site-packages /usr/local/lib/python3.12/site-packages
COPY . .
USER appuser
EXPOSE 8080
CMD ["python3", "app.py"]

核心原则:

  1. 基础镜像用 slim/alpine:减小体积(从 ~1GB 到 ~100MB)
  2. 多阶段构建:编译阶段和运行阶段分离,最终镜像不含编译工具
  3. 利用缓存:把不常变的层(如依赖安装)放前面,常变的(如代码)放后面
  4. 不用 root:创建专用用户运行应用
  5. 固定版本:不用 latest 标签,用具体版本号

面试加分: Docker 镜像的分层机制让多个容器可以共享底层镜像层(如 python:3.12-slim),只有顶部的可写层是各容器独立的,大幅节省磁盘和部署时间。

Q12:Docker 网络模式有哪些?

记忆点:四种网络模式——bridge(默认,容器通过虚拟网桥通信)、host(共享宿主机网络)、none(无网络)、overlay(跨主机通信,Swarm/K8s 用)。微服务本地开发用 bridge + docker-compose,生产用 overlay 或 K8s 网络。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Bridge 模式(默认):
  ┌─────────── 宿主机 ───────────────┐
  │                                  │
  │  ┌────────┐    ┌────────┐       │
  │  │容器 A   │    │容器 B   │       │
  │  │172.17.0.2│   │172.17.0.3│      │
  │  └────┬───┘    └────┬───┘       │
  │       │             │            │
  │  ┌────┴─────────────┴────┐      │
  │  │      docker0 bridge    │      │
  │  │      172.17.0.1        │      │
  │  └───────────┬───────────┘      │
  │              │ NAT               │
  │         ┌────┴────┐             │
  │         │  eth0   │             │
  └─────────┴─────────┴─────────────┘
模式隔离性性能适用场景
bridge有 NAT 开销默认,单机多容器
host最高(无 NAT)对网络性能敏感的应用
none完全隔离-安全敏感的批处理
overlay有封装开销多主机集群通信

第五部分:Kubernetes 核心概念

Q13:Kubernetes 的整体架构是怎样的?

记忆点:K8s 是 Master-Worker 架构。Master(控制面)负责调度决策,包含 API Server、Scheduler、Controller Manager、etcd。Worker(数据面)运行业务容器,包含 kubelet、kube-proxy、容器运行时。所有组件通过 API Server 通信。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
K8s 架构:
┌────────────────── Master Node(控制面)──────────────────┐
│                                                         │
│  ┌────────────┐  ┌───────────┐  ┌──────────────────┐   │
│  │ API Server │  │ Scheduler │  │Controller Manager│   │
│  │  集群入口   │  │ 调度 Pod   │  │ 维护期望状态     │   │
│  └─────┬──────┘  └─────┬─────┘  └────────┬─────────┘   │
│        │               │                  │              │
│        └───────────────┼──────────────────┘              │
│                        │                                 │
│                  ┌─────┴─────┐                           │
│                  │   etcd    │                            │
│                  │ 集群状态存储│                            │
│                  └───────────┘                            │
└──────────────────────────────────────────────────────────┘
           │                         │
┌──────────┴──── Worker Node 1 ──┐  ┌┴──── Worker Node 2 ──┐
│  ┌─────────┐  ┌────────────┐  │  │                       │
│  │ kubelet │  │ kube-proxy │  │  │  (同样的组件)           │
│  │管理 Pod  │  │网络代理/LB │  │  │                       │
│  └────┬────┘  └────────────┘  │  └───────────────────────┘
│       │                       │
│  ┌────┴──────────────────┐    │
│  │  Pod    Pod    Pod    │    │
│  │ ┌───┐ ┌───┐  ┌───┐   │    │
│  │ │app│ │app│  │app│   │    │
│  │ └───┘ └───┘  └───┘   │    │
│  └───────────────────────┘    │
└───────────────────────────────┘

各组件职责:

  • API Server:集群的唯一入口,所有操作都经过它(RESTful API)
  • etcd:分布式 KV 存储,保存集群所有状态数据
  • Scheduler:决定 Pod 调度到哪个 Node(根据资源、亲和性等)
  • Controller Manager:确保实际状态 = 期望状态(如 Deployment 维持副本数)
  • kubelet:Node 上的代理,负责启停 Pod、健康检查、上报状态
  • kube-proxy:维护 Node 上的网络规则,实现 Service 的负载均衡

Q14:Pod 是什么?为什么不直接管理容器?

记忆点:Pod 是 K8s 最小调度单元,包含一个或多个共享网络和存储的容器。不直接管理容器因为有些应用需要紧密协作的辅助容器(如日志收集 Sidecar),它们必须在同一个 Node、共享 localhost 和 Volume。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Pod 内部结构:
┌────────────── Pod ──────────────┐
│                                 │
│  ┌──────────┐  ┌──────────┐    │
│  │ 主容器    │  │ Sidecar  │    │
│  │ (app)    │  │ (日志收集) │    │
│  │ :8080    │  │ :9090    │    │
│  └────┬─────┘  └────┬─────┘    │
│       │              │          │
│  共享 Network Namespace         │
│  (同一个 IP, 通过 localhost 通信) │
│                                 │
│  共享 Volume                     │
│  ┌───────────────────────┐      │
│  │   /var/log/app        │      │
│  └───────────────────────┘      │
│                                 │
│  Pause 容器(维持网络命名空间)    │
└─────────────────────────────────┘

Pod 的生命周期: Pending → Running → Succeeded/Failed

常见 Sidecar 模式:

  1. 日志收集:Filebeat/Fluentd 收集应用日志
  2. 代理:Envoy/Istio Sidecar 处理流量
  3. 配置热加载:监听 ConfigMap 变化并通知主容器

面试加分: Pod 中所有容器共享同一个 Network Namespace(通过 Pause 容器实现),所以容器间用 localhost:port 通信,对外则共享一个 Pod IP。

Q15:Deployment、Service、Ingress 分别是什么?

记忆点:Deployment 管”应用怎么跑”(副本数、滚动更新),Service 管”怎么找到应用”(稳定的虚拟 IP + 负载均衡),Ingress 管”外部怎么访问”(域名路由 + HTTPS 终止)。三者组合:Ingress → Service → Deployment → Pod。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
流量路径:
  用户请求 api.example.com/users
         │
  ┌──────┴──────┐
  │   Ingress   │  ← 域名路由 + TLS
  │  /users → ? │
  └──────┬──────┘
         │
  ┌──────┴──────┐
  │   Service   │  ← ClusterIP: 10.96.0.100
  │  user-svc   │     负载均衡到后端 Pod
  └──────┬──────┘
    ┌────┼────┐
    ↓    ↓    ↓
  ┌───┐┌───┐┌───┐
  │Pod││Pod││Pod│  ← Deployment 管理 3 个副本
  └───┘└───┘└───┘

Deployment 的核心功能:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
apiVersion: apps/v1
kind: Deployment
metadata:
  name: user-service
spec:
  replicas: 3              # 维持 3 个副本
  strategy:
    type: RollingUpdate     # 滚动更新
    rollingUpdate:
      maxUnavailable: 1     # 更新时最多 1 个不可用
      maxSurge: 1           # 更新时最多多 1 个
  selector:
    matchLabels:
      app: user-service
  template:
    spec:
      containers:
      - name: user
        image: user-service:v2.0
        resources:
          requests:
            cpu: 100m
            memory: 128Mi
          limits:
            cpu: 500m
            memory: 512Mi

Service 的四种类型:

类型作用场景
ClusterIP集群内部虚拟 IP(默认)服务间内部调用
NodePort在每个 Node 上开放端口(30000-32767)开发测试
LoadBalancer创建云厂商的外部负载均衡器生产环境对外暴露
ExternalName映射到外部 DNS 名称访问集群外部服务

面试加分: Ingress 本身只是一组路由规则,需要 Ingress Controller(如 Nginx Ingress、Traefik)来实际执行。可以实现基于路径和域名的路由、TLS 终止、灰度发布等。

Q16:K8s 的滚动更新和回滚是怎么实现的?

记忆点:Deployment 通过创建新 ReplicaSet 并逐步增加新 Pod、减少旧 Pod 来实现滚动更新。每次更新都会保留旧的 ReplicaSet(默认保留 10 个),回滚就是把副本数切回旧 ReplicaSet。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
滚动更新过程(replicas=3, maxSurge=1, maxUnavailable=1):

阶段1:创建新 ReplicaSet,启动 1 个新 Pod
  旧 RS: [v1] [v1] [v1]    新 RS: [v2]
  可用: 3 → 满足 maxUnavailable=1

阶段2:终止 1 个旧 Pod
  旧 RS: [v1] [v1] [  ]    新 RS: [v2]
  可用: 3

阶段3:启动 1 个新 Pod + 终止 1 个旧 Pod
  旧 RS: [v1] [  ] [  ]    新 RS: [v2] [v2]
  可用: 3

阶段4:启动 1 个新 Pod + 终止最后旧 Pod
  旧 RS: [  ] [  ] [  ]    新 RS: [v2] [v2] [v2]
  完成!旧 RS 保留(replicas=0)用于回滚

回滚命令:

1
2
3
4
5
6
7
8
# 查看历史版本
kubectl rollout history deployment/user-service

# 回滚到上一个版本
kubectl rollout undo deployment/user-service

# 回滚到指定版本
kubectl rollout undo deployment/user-service --to-revision=2

面试加分: 生产环境可以配合 readinessProbe 确保新 Pod 健康后才接收流量,避免滚动更新期间把流量路由到还没准备好的 Pod。

Q17:K8s 的资源调度机制是怎样的?

记忆点:Scheduler 分两步——过滤(Filter)排除不满足条件的 Node,打分(Score)在剩余 Node 中选最优。常用调度策略:资源请求/限制、节点亲和性(Node Affinity)、Pod 反亲和性(Anti-Affinity)、污点容忍(Taint/Toleration)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
调度流程:
  新 Pod 创建 → 进入调度队列
       │
  ┌────┴────── 过滤阶段 ──────┐
  │ Node-A: CPU 不足    ✗     │
  │ Node-B: 满足条件    ✓     │
  │ Node-C: 满足条件    ✓     │
  │ Node-D: 有污点不容忍 ✗     │
  └────┬──────────────────────┘
       │
  ┌────┴────── 打分阶段 ──────┐
  │ Node-B: 资源均衡 80分      │
  │ Node-C: 亲和性匹配 90分    │  ← 选 Node-C
  └────┬──────────────────────┘
       │
  绑定 Pod → Node-C

核心调度策略:

  • requests/limits:保证最小资源和上限,超出 limits 会被 OOM Kill
  • nodeSelector:简单的标签匹配调度(如 disk: ssd
  • Node Affinity:更灵活的节点亲和规则(软/硬约束)
  • Pod Anti-Affinity:同一服务的 Pod 分散到不同 Node(高可用)
  • Taint/Toleration:Node 打污点驱逐 Pod,特定 Pod 可容忍污点(如 GPU 节点只跑 ML 任务)

第六部分:云原生理念

Q18:什么是云原生?CNCF 是什么?

记忆点:云原生是一套方法论——利用容器、微服务、服务网格、不可变基础设施、声明式 API 等技术,构建弹性、可观测、易变更的分布式系统。CNCF(Cloud Native Computing Foundation)是云原生的标准制定者和项目孵化器。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
CNCF 云原生全景图(核心层):
┌────────────────────────────────────────────────┐
│                  应用定义与开发                   │
│     Helm │ Kustomize │ Operator Framework       │
├────────────────────────────────────────────────┤
│                  编排与管理                      │
│     Kubernetes │ Scheduling │ Service Discovery │
├────────────────────────────────────────────────┤
│                  运行时                          │
│     containerd │ CRI-O │ gVisor │ Kata          │
├────────────────────────────────────────────────┤
│                  配置与安全                      │
│     Vault │ OPA │ Cert-Manager │ SPIFFE         │
├────────────────────────────────────────────────┤
│                  可观测与分析                     │
│     Prometheus │ Grafana │ Jaeger │ OpenTelemetry│
├────────────────────────────────────────────────┤
│                  服务网格                        │
│     Istio │ Linkerd │ Envoy                     │
└────────────────────────────────────────────────┘

云原生的四大支柱:

  1. 容器化:统一打包和运行环境
  2. 动态编排:K8s 自动调度、扩缩容、自愈
  3. 微服务化:按业务拆分,独立迭代
  4. DevOps + CI/CD:自动化交付流水线

Q19:12-Factor App 是什么?

记忆点:12-Factor 是 Heroku 总结的 12 条 SaaS 应用开发最佳实践。核心思想:应用与基础设施解耦,配置与代码分离,无状态设计,适合在云平台上运行。

因素原则要点
1. Codebase一份代码,多处部署一个 repo 对应一个应用
2. Dependencies显式声明依赖package.json / go.mod / requirements.txt
3. Config配置存环境变量不在代码中硬编码数据库地址、密钥
4. Backing Services后端服务当附加资源数据库/MQ/缓存通过 URL 连接,可随时替换
5. Build/Release/Run严格分离构建、发布、运行CI 构建 → 打镜像 → 部署运行
6. Processes无状态进程不在本地存会话,用 Redis/DB 存状态
7. Port Binding端口绑定导出服务应用自带 HTTP 服务器,不依赖外部容器
8. Concurrency通过进程模型扩展水平扩展多实例而非垂直加配置
9. Disposability快速启动,优雅停止秒级启动,SIGTERM 时清理资源
10. Dev/Prod Parity开发与生产尽量一致Docker + docker-compose 保证环境一致
11. Logs日志当事件流输出到 stdout,由平台收集(不写本地文件)
12. Admin Processes管理任务当一次性进程数据库迁移用 kubectl exec 或 Job

面试加分: 12-Factor 是 2011 年提出的,后来有人补充了 3 条形成”15-Factor”:API First、Telemetry(可观测性)、Authentication(安全)。

Q20:不可变基础设施(Immutable Infrastructure)是什么意思?

记忆点:不可变基础设施 = 不修改已部署的实例,而是用新镜像创建新实例替换旧实例。类比:不是修补旧衣服(Mutable),而是直接换新衣服(Immutable)。Docker 镜像 + K8s 滚动更新就是这个理念的实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
可变基础设施(传统):
  服务器 A(已运行 3 个月)
  → SSH 上去打补丁
  → 手动改配置
  → 安装新依赖
  → 每台服务器状态都不一样(Configuration Drift)

不可变基础设施(云原生):
  1. 修改代码/配置
  2. 构建新镜像 v2.1
  3. K8s 用新镜像滚动更新
  4. 旧 Pod 销毁,新 Pod 运行
  → 所有实例状态一致,可重复创建

好处:

  • 消除环境漂移:没有”我机器上能跑”的问题
  • 可回滚:回到上个版本就是切回旧镜像
  • 可审计:每次变更都有镜像版本记录

第七部分:Service Mesh

Q21:什么是 Service Mesh?它解决了什么问题?

记忆点:Service Mesh(服务网格)是处理服务间通信的基础设施层——把原本在应用代码中的负载均衡、熔断、重试、认证、可观测等逻辑下沉到 Sidecar 代理。应用只关心业务逻辑,通信治理交给 Mesh。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
没有 Service Mesh:每个服务自己处理通信逻辑
  ┌─────────────────────┐     ┌─────────────────────┐
  │     服务 A           │     │     服务 B           │
  │ ┌─────────────────┐ │     │ ┌─────────────────┐ │
  │ │ 业务逻辑         │ │     │ │ 业务逻辑         │ │
  │ ├─────────────────┤ │     │ ├─────────────────┤ │
  │ │ 重试 │ 熔断 │ TLS│ │ ──→ │ │ 重试 │ 熔断 │ TLS│ │
  │ │ 负载均衡 │ 监控  │ │     │ │ 负载均衡 │ 监控  │ │
  │ └─────────────────┘ │     │ └─────────────────┘ │
  └─────────────────────┘     └─────────────────────┘
  问题:每个服务都要集成 SDK,语言绑定,升级困难

有 Service Mesh:通信逻辑在 Sidecar 中
  ┌───────────────────────────┐     ┌───────────────────────────┐
  │         Pod A              │     │         Pod B              │
  │ ┌──────────┐ ┌──────────┐ │     │ ┌──────────┐ ┌──────────┐ │
  │ │ 服务 A    │ │ Envoy    │ │ ──→ │ │ Envoy    │ │ 服务 B    │ │
  │ │ 纯业务    │ │ Sidecar  │ │     │ │ Sidecar  │ │ 纯业务    │ │
  │ │ 逻辑     │ │ 重试/熔断 │ │     │ │ TLS/监控 │ │ 逻辑     │ │
  │ └──────────┘ │ TLS/监控 │ │     │ │ 重试/熔断 │ └──────────┘ │
  │              └──────────┘ │     │ └──────────┘              │
  └───────────────────────────┘     └───────────────────────────┘
  应用代码零侵入,治理能力由平台统一管理

Service Mesh 的核心能力:

  1. 流量管理:负载均衡、灰度发布、流量镜像、故障注入
  2. 安全:mTLS 双向认证、细粒度访问控制
  3. 可观测:自动生成请求指标、分布式追踪、访问日志

Q22:Istio 的架构是怎样的?

记忆点:Istio 分为数据面(Data Plane)和控制面(Control Plane)。数据面是每个 Pod 中注入的 Envoy Sidecar,拦截所有出入流量。控制面是 istiod,统一管理配置下发、证书颁发、服务发现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Istio 架构:
┌──────────────────── 控制面 ────────────────────┐
│                                                │
│  ┌───────────────── istiod ─────────────────┐  │
│  │  Pilot     │  Citadel    │  Galley       │  │
│  │  流量规则   │  证书管理    │  配置验证      │  │
│  │  服务发现   │  mTLS       │  配置分发      │  │
│  └──────────────────────────────────────────┘  │
│                      │ xDS 协议下发配置          │
└──────────────────────┼─────────────────────────┘
                       │
┌──────────────────── 数据面 ────────────────────┐
│                      │                         │
│  ┌─── Pod A ────┐   │   ┌─── Pod B ────┐      │
│  │ App  │ Envoy │←──┘──→│ Envoy │ App  │      │
│  └──────┴───────┘       └───────┴──────┘      │
│         ↕ 所有流量经 Envoy ↕                    │
└────────────────────────────────────────────────┘

Istio 核心资源:

  • VirtualService:定义路由规则(如 90% 流量到 v1,10% 到 v2)
  • DestinationRule:定义目标策略(负载均衡算法、连接池、熔断)
  • Gateway:配置入口网关(类似 Ingress 但更强大)
  • PeerAuthentication:配置 mTLS 策略

Q23:Service Mesh 的 Sidecar 模式有什么问题?有替代方案吗?

记忆点:Sidecar 的主要问题是性能开销(每次请求多两跳代理)和资源消耗(每个 Pod 多一个 Envoy 容器占 ~50MB 内存)。替代方案是 Sidecar-less 模式——Cilium 用 eBPF 在内核层实现,Istio Ambient Mesh 用共享的 ztunnel 节点代理替代 per-Pod Sidecar。

1
2
3
4
5
6
7
8
9
10
11
12
Sidecar 模式 vs Sidecar-less 模式:

Sidecar(传统):
  Pod 1: [App] ↔ [Envoy]     每个 Pod 一个 Sidecar
  Pod 2: [App] ↔ [Envoy]     延迟 +2ms,内存 +50MB/Pod
  Pod 3: [App] ↔ [Envoy]

Ambient Mesh(Sidecar-less):
  Node: [ztunnel]  ← 每个 Node 一个共享代理
  Pod 1: [App] ──→ ztunnel ──→ Pod 2: [App]
  Pod 3: [App] ──↗
  内存开销大幅减少,延迟更低
方案延迟开销资源开销功能完整性成熟度
Istio + Envoy Sidecar中(~2ms)最完整生产就绪
Istio Ambient Mesh逐步完善正在成熟
Cilium(eBPF)极低极低L4 完整,L7 部分生产就绪
Linkerd够用生产就绪,轻量

面试加分: eBPF(Extended Berkeley Packet Filter)是近年来最热的底层技术之一——它允许在 Linux 内核中安全运行沙盒程序,无需修改内核代码。Cilium 利用 eBPF 在内核态实现网络策略、负载均衡和可观测性,完全绕过用户态代理。


第八部分:可观测性

Q24:可观测性的三大支柱是什么?

记忆点:可观测性(Observability)= 日志(Logs)+ 指标(Metrics)+ 链路追踪(Traces)。日志告诉你”发生了什么”,指标告诉你”系统状态如何”,链路追踪告诉你”请求走了哪条路”。三者结合才能快速定位问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
可观测性三大支柱:
┌─────────────────────────────────────────────┐
│                可观测性平台                    │
│                                             │
│  ┌───────────┐ ┌───────────┐ ┌───────────┐  │
│  │  Logs     │ │ Metrics   │ │  Traces   │  │
│  │  日志      │ │ 指标      │ │  链路追踪  │  │
│  │           │ │           │ │           │  │
│  │ 离散事件   │ │ 聚合数值   │ │ 请求链路   │  │
│  │ 排查细节   │ │ 趋势告警   │ │ 跨服务追踪 │  │
│  │           │ │           │ │           │  │
│  │ ELK Stack │ │Prometheus │ │  Jaeger   │  │
│  │ Loki      │ │ Grafana   │ │  Zipkin   │  │
│  └───────────┘ └───────────┘ └───────────┘  │
│                                             │
│         OpenTelemetry(统一采集标准)          │
└─────────────────────────────────────────────┘
支柱数据类型典型工具用途
日志文本事件流ELK、Loki、Fluentd错误排查、审计
指标时序数值Prometheus、Grafana监控告警、趋势分析
链路追踪请求调用链Jaeger、Zipkin、Tempo延迟分析、依赖排查

面试加分: OpenTelemetry(OTel)正在成为可观测性的事实标准——它统一了 Logs、Metrics、Traces 的 SDK 和协议,一次埋点即可导出到任意后端(Prometheus、Jaeger、Datadog 等),避免厂商锁定。

Q25:Prometheus + Grafana 的监控架构是怎样的?

记忆点:Prometheus 是拉模式(Pull)的时序数据库——定期从目标端点抓取指标。Grafana 是可视化面板。完整链路:应用暴露 /metrics → Prometheus 拉取存储 → Grafana 展示 → AlertManager 告警。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
Prometheus 监控架构:
                               ┌──────────────┐
                               │  Grafana     │
                               │  可视化面板    │
                               └──────┬───────┘
                                      │ PromQL 查询
                               ┌──────┴───────┐
                               │ Prometheus   │
                               │ 时序数据库    │
                               │ 定期拉取指标  │
                               └──┬───┬───┬───┘
                       Pull       │   │   │
              ┌───────────────────┘   │   └──────────────┐
              ↓                       ↓                  ↓
      ┌───────────┐          ┌───────────┐      ┌───────────┐
      │ 服务 A     │          │ 服务 B     │      │ Node      │
      │ /metrics  │          │ /metrics  │      │ Exporter  │
      │ http_req  │          │ http_req  │      │ cpu/mem   │
      │ _total    │          │ _duration │      │ disk/net  │
      └───────────┘          └───────────┘      └───────────┘

                               ┌──────────────┐
                               │ AlertManager │
                               │ 告警路由      │
                               │ → Slack      │
                               │ → PagerDuty  │
                               │ → 邮件       │
                               └──────────────┘

四种指标类型:

  1. Counter(计数器):只增不减,如请求总数 http_requests_total
  2. Gauge(仪表盘):可增可减,如当前内存使用 memory_usage_bytes
  3. Histogram(直方图):分布统计,如请求延迟 P50/P95/P99
  4. Summary(摘要):类似 Histogram,客户端计算分位数

关键监控指标(RED 方法):

  • Rate:请求速率(QPS)
  • Errors:错误率(5xx 比例)
  • Duration:延迟分布(P99 < 200ms)

Q26:分布式链路追踪的原理是什么?

记忆点:请求进入系统时生成全局唯一的 Trace ID,每经过一个服务生成一个 Span(包含服务名、耗时、状态)。所有 Span 通过 Trace ID 串联成一棵调用树。传递方式:HTTP Header 或 gRPC Metadata。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
一次请求的链路追踪:

Trace ID: abc-123
┌───────────────────────────────────────────────────┐
│ Span A: API Gateway (总耗时 350ms)                 │
│ ┌───────────────────────────────────┐              │
│ │ Span B: 用户服务 (50ms)            │              │
│ └───────────────────────────────────┘              │
│ ┌─────────────────────────────────────────┐        │
│ │ Span C: 订单服务 (200ms)                 │        │
│ │ ┌──────────────────────┐                │        │
│ │ │ Span D: 数据库查询 (80ms)│               │        │
│ │ └──────────────────────┘                │        │
│ │ ┌────────────────────────────┐          │        │
│ │ │ Span E: 缓存查询 (5ms)      │          │        │
│ │ └────────────────────────────┘          │        │
│ └─────────────────────────────────────────┘        │
│ ┌───────────────────┐                              │
│ │ Span F: 通知服务 (30ms)│                           │
│ └───────────────────┘                              │
└───────────────────────────────────────────────────┘

上下文传递:
  服务 A → HTTP Header: traceparent: 00-abc123-span_a-01
  服务 B 收到 Header → 创建子 Span,parent = span_a

核心概念:

  • Trace:一次完整请求的调用链
  • Span:调用链中的一个操作单元(一个 RPC 调用、一次 DB 查询)
  • Context Propagation:跨服务传递 Trace ID 和 Span ID

面试加分: 采样策略很重要——全量采集链路数据开销太大。常用策略:头部采样(请求入口决定是否采集,如 1% 采样率)、尾部采样(请求完成后根据是否出错/慢来决定是否保留)。


第九部分:CI/CD 与 DevOps

Q27:CI/CD 的核心概念是什么?

记忆点:CI(持续集成)= 频繁合并代码 + 自动构建测试。CD 有两层含义——持续交付(Continuous Delivery)= 自动部署到预发环境,人工审批上线;持续部署(Continuous Deployment)= 全自动部署到生产,无需人工干预。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
CI/CD 流水线:
  开发者 Push 代码
       │
  ┌────┴──── CI(持续集成)────────────────────┐
  │  1. 代码拉取                               │
  │  2. 依赖安装                               │
  │  3. 代码检查(Lint)                        │
  │  4. 单元测试                               │
  │  5. 构建镜像                               │
  │  6. 集成测试                               │
  └────┬──────────────────────────────────────┘
       │ 通过
  ┌────┴──── CD(持续交付/部署)────────────────┐
  │  7. 推送镜像到 Registry                    │
  │  8. 部署到 Staging 环境                    │
  │  9. 自动化 E2E 测试                        │
  │ 10. [人工审批] 或 自动                      │
  │ 11. 部署到 Production                     │
  │ 12. 健康检查 + 监控                        │
  └────────────────────────────────────────────┘
CI/CD 工具特点
GitHub Actions与 GitHub 深度集成,YAML 配置
GitLab CIGitLab 内置,功能全面
Jenkins老牌,插件丰富,自托管
ArgoCDK8s 原生,GitOps 模式
TektonK8s 原生,Pipeline as Code

Q28:什么是 GitOps?和传统 CI/CD 有什么区别?

记忆点:GitOps = 用 Git 仓库作为基础设施和应用配置的唯一真实来源(Single Source of Truth)。所有变更通过 Git PR 触发,ArgoCD 等工具自动同步 Git 中的声明式配置到 K8s 集群。核心原则:声明式 + 版本化 + 自动同步。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
传统 CI/CD(Push 模式):
  开发者 → Push 代码 → CI 构建 → CD 脚本 Push 到集群
  问题:CD 脚本有集群权限,安全风险高

GitOps(Pull 模式):
  ┌────────┐  PR   ┌──────────┐  Watch  ┌──────────┐
  │开发者   │ ────→ │ Git Repo │ ←────── │ ArgoCD   │
  │修改 YAML│       │ 声明式配置 │        │ 集群内运行 │
  └────────┘       └──────────┘        └────┬─────┘
                                            │ Sync
                                     ┌──────┴──────┐
                                     │  K8s 集群    │
                                     │ 自动同步状态  │
                                     └─────────────┘
  Git 中的状态 = 集群中的实际状态(drift detection)

GitOps 的好处:

  1. 可审计:所有变更都有 Git 提交记录
  2. 可回滚git revert 即可回滚基础设施
  3. 安全:CI 不需要集群权限,ArgoCD 在集群内部拉取
  4. 一致性:自动检测并修复配置漂移

Q29:蓝绿部署、金丝雀发布、灰度发布有什么区别?

记忆点:蓝绿部署 = 两套完整环境一键切换。金丝雀发布 = 先给小比例用户用新版本,逐步扩大。灰度发布 = 金丝雀的增强版,按用户特征(地域、设备、用户 ID)精确控制流量。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
蓝绿部署:
  ┌──────────┐     ┌──────────┐
  │ 蓝(v1)  │ ←── │ 负载均衡  │   100% 流量走蓝
  │ 当前版本  │     └──────────┘
  └──────────┘
  ┌──────────┐
  │ 绿(v2)  │                     新版本待命
  │ 新版本    │
  └──────────┘

  切换后:
  ┌──────────┐
  │ 蓝(v1)  │                     旧版本待命(可快速回滚)
  └──────────┘
  ┌──────────┐     ┌──────────┐
  │ 绿(v2)  │ ←── │ 负载均衡  │   100% 流量走绿
  └──────────┘     └──────────┘

金丝雀发布:
  ┌──────────┐     ┌──────────┐
  │ v1(95%) │ ←── │ 流量分发  │ ──→ 95% 用户
  └──────────┘     └──────────┘
  ┌──────────┐         │
  │ v2(5%)  │ ←───────┘          5% 用户试用新版本
  └──────────┘
  监控正常 → 逐步增加到 10% → 50% → 100%
  发现问题 → 立即回退到 0%
策略资源成本回滚速度风险控制适用场景
蓝绿部署高(双倍资源)秒级全量切换核心服务、需要快速回滚
金丝雀发布秒级精细大规模服务、渐进式发布
滚动更新分钟级中等K8s 默认,日常发布

第十部分:综合实战

Q30:如果让你从零设计一个云原生微服务架构,你会怎么做?

记忆点:不要一开始就全套上——从单体开始,识别瓶颈再拆分。架构设计遵循”演进式架构”,每引入一个组件都要有明确的问题要解决。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
演进路径:
Phase 1: 单体 + Docker
  ┌─────────────┐
  │  单体应用     │ ← Docker 容器化,CI/CD 自动部署
  │  PostgreSQL  │
  └─────────────┘

Phase 2: 拆分核心服务
  ┌──────┐  ┌──────┐  ┌──────┐
  │用户   │  │订单   │  │支付   │  ← 按 DDD 拆分
  └──┬───┘  └──┬───┘  └──┬───┘
     │  REST/gRPC  │    MQ │
  ┌──┴─────────────┴──────┴──┐
  │       API Gateway         │  ← 统一入口
  └───────────────────────────┘

Phase 3: 上 Kubernetes
  ┌────────────────────────────────┐
  │  K8s Cluster                   │
  │  Deployment + Service + Ingress│
  │  HPA 自动扩缩容                │
  │  ConfigMap/Secret 配置管理      │
  └────────────────────────────────┘

Phase 4: 可观测性 + 治理
  ┌────────────────────────────────┐
  │  Prometheus + Grafana(监控)    │
  │  ELK/Loki(日志)              │
  │  Jaeger(链路追踪)             │
  │  Istio/Cilium(Service Mesh)  │
  └────────────────────────────────┘

Phase 5: 成熟期
  GitOps(ArgoCD)
  混沌工程(Chaos Monkey)
  多集群/多云部署

面试回答框架:

  1. 业务理解:先搞清楚业务域和流量规模
  2. 技术选型:根据团队技术栈和规模选择合适的工具
  3. 渐进式演进:不要过度设计,每一步都解决当前最痛的问题
  4. 可观测性优先:没有监控的微服务是灾难
  5. 自动化一切:CI/CD、基础设施即代码、自动扩缩容

面试加分: 能说出”微服务不是目标,而是手段”的候选人通常更受青睐。真正的目标是组织效率——让多个团队能独立、快速、安全地交付价值。如果一个 5 人团队维护 3 个服务就够了,就不要拆成 30 个。


补充一:高频遗漏题——弹性设计与容错模式

Q31:熔断器(Circuit Breaker)模式是怎么工作的?

记忆点:熔断器有三个状态——Closed(正常放行)→ 当错误率超过阈值 → Open(直接拒绝,快速失败)→ 等待超时 → Half-Open(放少量请求试探)→ 成功则恢复 Closed,失败则回到 Open。类比家里的电路跳闸。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
熔断器状态机:
          成功率恢复
  ┌─────────────────────────┐
  │                         ↓
┌──────┐  错误率>阈值  ┌──────┐  超时后试探  ┌───────────┐
│Closed│ ───────────→ │ Open │ ──────────→ │ Half-Open │
│ 正常  │              │ 熔断 │              │  半开试探   │
└──────┘              └──────┘              └───────────┘
  ↑                                             │
  └─────────── 试探请求成功 ──────────────────────┘
                试探请求失败 → 回到 Open

实际例子(用户服务调用积分服务):
  正常:用户服务 → 积分服务(200 OK)     → Closed
  异常:积分服务连续 5 次 5xx              → Open(直接返回降级响应)
  30s 后:放 1 个请求试试                  → Half-Open
  成功:恢复正常调用                       → Closed
  失败:继续熔断                           → Open

常用框架:

框架语言特点
Resilience4jJava轻量级,函数式 API,Spring Boot 集成
SentinelJava阿里开源,限流+熔断+降级一体
HystrixJavaNetflix 开源,已停止维护,用 Resilience4j 替代
Polly.NET.NET 生态的弹性库
Istio任意语言Service Mesh 层面实现,无需改代码

Q32:限流的常用算法有哪些?

记忆点:四种主流限流算法——固定窗口(简单但有临界突刺)、滑动窗口(平滑但内存大)、漏桶(恒定速率,削峰)、令牌桶(允许突发,最常用)。面试记住令牌桶 = “攒令牌,花令牌”。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
令牌桶算法(Token Bucket):
  ┌─────────────────┐
  │    令牌生成器     │  ← 每秒往桶里放 N 个令牌
  │  (恒定速率)     │
  └────────┬────────┘
           ↓
  ┌─────────────────┐
  │   令牌桶(容量M)  │  ← 桶满了就不放了
  │  [●][●][●][●][ ] │
  └────────┬────────┘
           ↓ 每个请求消耗 1 个令牌
  请求来了 → 桶里有令牌?
           ├── 有:通过,取走一个令牌
           └── 没有:拒绝(返回 429 Too Many Requests)

  优点:允许一定程度的突发流量(桶里攒了令牌就能突发用掉)

漏桶 vs 令牌桶:
  漏桶:请求进桶,恒定速率流出  → 严格匀速,不允许突发
  令牌桶:令牌恒定速率生成,请求需要令牌 → 允许突发(桶满了有 M 个令牌可以一次用完)

面试口诀: “漏桶匀速不突发,令牌突发能攒下”

Q33:K8s 的健康检查探针有哪些?

记忆点:三种探针——Liveness(活不活?死了就重启)、Readiness(准备好没?没好就不给流量)、Startup(启动完没?没完就等着别杀)。记忆口诀:”活不活,好没好,启动了没有”。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 三种探针配置示例
containers:
- name: app
  livenessProbe:          # 活不活?失败 → 重启容器
    httpGet:
      path: /healthz
      port: 8080
    initialDelaySeconds: 15
    periodSeconds: 10
    failureThreshold: 3    # 连续 3 次失败才判定为死

  readinessProbe:          # 好没好?失败 → 从 Service 摘除,不接流量
    httpGet:
      path: /ready
      port: 8080
    periodSeconds: 5

  startupProbe:            # 启动完没?没完就不检查 liveness
    httpGet:               # 适合启动慢的应用(如 Java)
      path: /healthz
      port: 8080
    failureThreshold: 30   # 最多等 30 × 10 = 300s
    periodSeconds: 10
1
2
3
4
5
6
7
8
9
10
11
12
13
探针决策流程:
  Pod 启动
    │
    ├── startupProbe 检查中... (不检查 liveness/readiness)
    │   └── 成功 → 开始检查 liveness 和 readiness
    │   └── 失败超过阈值 → 杀掉重启
    │
    ├── livenessProbe: 容器死了吗?
    │   └── 失败 → kubelet 重启容器
    │
    └── readinessProbe: 能接流量吗?
        └── 失败 → 从 Service Endpoints 摘除(不接新流量)
        └── 恢复 → 重新加入 Endpoints

面试常考陷阱: “如果只配了 livenessProbe 没配 readinessProbe 会怎样?” → 容器还没完全启动就被加入 Service 接收流量,导致请求 503。所以两个都要配

Q34:K8s HPA 自动扩缩容是怎么工作的?

记忆点:HPA(Horizontal Pod Autoscaler)根据指标(CPU/内存/自定义指标)自动调整 Pod 副本数。每 15 秒检查一次指标,当 CPU 利用率超过目标值就扩容,低于就缩容。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: user-service-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: user-service
  minReplicas: 2            # 最少 2 个
  maxReplicas: 20           # 最多 20 个
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 70   # CPU 平均利用率超 70% 就扩容
  behavior:
    scaleDown:
      stabilizationWindowSeconds: 300  # 缩容等 5 分钟(防抖)
1
2
3
4
5
6
7
8
9
10
11
12
HPA 工作流程:
  Metrics Server 采集 Pod 指标
       │
  HPA Controller(每 15s 检查一次)
       │
  当前 CPU 平均利用率 = 85%,目标 = 70%
       │
  期望副本数 = ceil(当前副本 × 85/70) = ceil(3 × 1.21) = 4
       │
  调整 Deployment replicas: 3 → 4
       │
  Scheduler 调度新 Pod → Node

补充二:K8s 故障排查实战速查

面试最爱问:”你遇到过什么生产问题?怎么排查的?” 以下是最常见的 K8s 故障场景和排查路径:

场景 1:Pod 状态 CrashLoopBackOff

1
2
3
4
5
6
7
8
9
10
# 排查路径:
kubectl describe pod <pod-name>           # 看 Events 和 Last State
kubectl logs <pod-name>                   # 看应用日志
kubectl logs <pod-name> --previous        # 看上次崩溃的日志(重点!)

# 常见原因:
# 1. 应用启动失败(配置错误、缺少环境变量)
# 2. OOM Killed(内存超过 limits)→ describe 里看 Reason: OOMKilled
# 3. livenessProbe 误杀(探针路径写错、超时太短)
# 4. 启动命令错误(CMD/ENTRYPOINT 写错)

场景 2:Pod 状态 Pending

1
2
3
4
5
6
7
8
kubectl describe pod <pod-name>           # 看 Events 里的调度失败原因

# 常见原因:
# 1. 资源不足 → "Insufficient cpu/memory"
#    → 扩容 Node 或调整 requests
# 2. 节点亲和性不匹配 → "didn't match node selector"
# 3. PVC 绑定失败 → "unbound PersistentVolumeClaims"
# 4. 所有节点有 Taint 且 Pod 没有 Toleration

场景 3:Service 访问不通

1
2
3
4
5
6
7
8
9
10
# 排查路径(从外到内):
kubectl get svc <svc-name>                # 检查 Service 是否存在
kubectl get endpoints <svc-name>          # 检查后端 Pod 列表是否为空!
kubectl get pods -l app=<label>           # Pod 的 label 是否和 Service selector 匹配
kubectl exec -it <pod> -- curl localhost:8080  # Pod 内部能不能访问自己

# 最常见原因:
# 1. endpoints 为空 → Pod label 和 Service selector 不匹配(拼写错误!)
# 2. Pod 的 readinessProbe 失败 → 被摘除出 endpoints
# 3. 网络策略(NetworkPolicy)阻断了流量

场景 4:应用延迟突然升高

1
2
3
4
5
6
7
8
9
# 排查路径:
# 1. 看监控 → Grafana 看 QPS、延迟 P99、错误率(RED 三板斧)
# 2. 看链路追踪 → Jaeger 找慢在哪个 Span
# 3. 看资源 → kubectl top pods(CPU/内存是否打满)
# 4. 看日志 → 是不是数据库慢查询、GC 停顿、连接池耗尽
# 5. 看网络 → 是不是 DNS 解析慢、跨 AZ 延迟

# 常见原因排名:
# 数据库慢查询 > 下游服务超时 > GC 停顿 > 连接池/线程池满 > 网络问题

补充三:5 分钟动手实验速记

纸上得来终觉浅,这些命令建议在本地 Docker/Minikube 上实际跑一遍,比看十遍文档都管用。

实验 1:Docker 镜像分层体验(5 分钟)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 1. 创建一个简单的 Dockerfile
cat > Dockerfile <<'EOF'
FROM alpine:3.19
RUN echo "layer 1" > /file1.txt
RUN echo "layer 2" > /file2.txt
RUN echo "layer 3" > /file3.txt
CMD ["cat", "/file1.txt", "/file2.txt", "/file3.txt"]
EOF

# 2. 构建并查看层
docker build -t layer-demo .
docker history layer-demo          # ← 看每一层的大小和命令

# 3. 修改最后一行 RUN,重新 build,观察缓存命中
# 你会发现前两层秒过(Using cache),只有最后一层重新构建
# → 这就是"把不常变的放前面"的原理

实验 2:K8s 滚动更新+回滚(10 分钟,需要 Minikube/Kind)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 1. 创建 Deployment
kubectl create deployment nginx-demo --image=nginx:1.24 --replicas=3

# 2. 观察滚动更新(开两个终端)
# 终端 1:实时观察 Pod 变化
kubectl get pods -w

# 终端 2:触发更新
kubectl set image deployment/nginx-demo nginx=nginx:1.25

# 3. 查看更新历史
kubectl rollout history deployment/nginx-demo

# 4. 回滚
kubectl rollout undo deployment/nginx-demo

# 5. 感受 → 你会亲眼看到旧 Pod 逐个 Terminating,新 Pod 逐个 Running

实验 3:熔断器效果体验(5 分钟,用 curl 模拟)

1
2
3
4
5
6
7
8
9
10
11
12
13
# 概念模拟(不需要装框架):
# 假设你调用一个服务,连续 5 次超时

# 没有熔断器:
for i in {1..20}; do
  curl --max-time 3 http://slow-service/api  # 每次都等 3 秒才超时
done
# → 20 次请求,总共等了 60 秒,线程全部阻塞

# 有熔断器(伪代码逻辑):
# 前 5 次:正常调用,3 秒超时 → 触发熔断
# 第 6-20 次:直接返回降级响应(<1ms),不再调用下游
# → 保护了调用方,避免级联故障(雪崩效应)

实验 4:Prometheus 指标体验(3 分钟)

1
2
3
4
5
6
7
8
9
10
11
12
# 不需要装 Prometheus,先理解 /metrics 端点长什么样
# 任意一个暴露 metrics 的应用(如 Node Exporter):

curl http://localhost:9100/metrics | head -20
# 你会看到类似:
# # HELP node_cpu_seconds_total Seconds the CPUs spent in each mode.
# # TYPE node_cpu_seconds_total counter
# node_cpu_seconds_total{cpu="0",mode="idle"} 123456.78
# node_cpu_seconds_total{cpu="0",mode="system"} 1234.56
#
# 这就是 Prometheus 的数据格式:metric_name{labels} value
# Counter 只增不减,Gauge 可增可减

补充四:面试速记口诀与记忆锚点

面试前 30 分钟快速过一遍这些口诀,覆盖 80% 的高频考点。

微服务篇

口诀对应知识点
“先单体,后拆分”Monolith First,别上来就微服务
“按业务切,不按技术切”服务拆分原则:Business Capability + DDD Bounded Context
“自己的数据自己管”Database per Service,服务间不共享数据库
“Saga 补偿,幂等是关键”分布式事务用 Saga,每个参与者必须幂等
“同步用 gRPC,异步用 MQ”内部高频调用 gRPC,解耦削峰用消息队列

Kubernetes 篇

口诀对应知识点
“API Server 是唯一入口”所有组件通过 API Server 通信,etcd 只有 API Server 能访问
“Deployment 管跑,Service 管找,Ingress 管进”三大核心资源的职责
“活不活,好没好,启动了没有”livenessProbe / readinessProbe / startupProbe
“过滤打分选节点”Scheduler 调度流程:Filter → Score → Bind
“声明式,非命令式”K8s 的核心理念:你声明期望状态,Controller 负责达成

云原生篇

口诀对应知识点
“配置放环境变量,日志打 stdout”12-Factor 中最实用的两条
“不修旧的,换新的”不可变基础设施
“Git 是唯一真相”GitOps 核心原则
“数据面干活,控制面指挥”Service Mesh / K8s / Istio 的通用架构模式

可观测性篇

口诀对应知识点
“日志看细节,指标看趋势,链路看瓶颈”可观测性三大支柱的分工
“RED = 速率+错误+延迟”服务监控的黄金指标
“Trace ID 串全链,Span 管单段”分布式链路追踪的核心概念
“拉模式 Prometheus,推模式 Push Gateway”Prometheus 的数据采集方式

部署发布篇

口诀对应知识点
“蓝绿一键切,金丝雀慢慢放”两种发布策略的核心区别
“漏桶匀速不突发,令牌突发能攒下”限流算法:漏桶 vs 令牌桶
“电路跳闸三状态:闭合-断开-半开”熔断器模式:Closed → Open → Half-Open

补充五:面试真题模拟与回答框架

面试官不只问”是什么”,更爱问”你怎么选”、”遇到过什么问题”。以下是开放题的回答框架

模拟题 1:”你们的微服务是怎么做服务治理的?”

回答框架(STAR 法):

1
2
3
4
5
6
7
8
9
10
11
Situation: 我们有 30+ 个微服务,Java 为主,部署在 K8s 上。
Task:      需要解决服务间调用的超时、重试、熔断、限流问题。
Action:
  1. 初期用 Spring Cloud(Feign + Ribbon + Hystrix)
  2. Hystrix 停止维护后迁移到 Resilience4j
  3. 后来上了 Istio Service Mesh,把治理逻辑从代码下沉到基础设施
     → 好处:新增的 Go/Python 服务不用集成 Java SDK
  4. 限流在网关层用 Sentinel 做,熔断在 Mesh 层做
Result:
  → 服务间 P99 延迟从 500ms 降到 200ms(熔断避免了级联超时)
  → 故障恢复时间从 30 分钟降到 5 分钟(自动熔断+降级)

模拟题 2:”生产环境出现大量 5xx,你怎么排查?”

回答框架(由外到内,逐层定位):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Step 1: 看监控大盘
  → Grafana 看是全局还是单个服务?从什么时间开始?
  → 是否和某次发布时间吻合?

Step 2: 定位到具体服务
  → 链路追踪(Jaeger)找到出错的 Span
  → 看是服务自身报错还是下游依赖报错

Step 3: 看日志
  → Kibana/Loki 搜索该服务的 ERROR 日志
  → 关键词:OOM、Connection refused、Timeout、NullPointer

Step 4: 看资源
  → kubectl top pods / kubectl describe pod
  → CPU 打满?内存 OOM?Pod 重启了?

Step 5: 常见根因(按概率排序)
  1. 刚发布了有 bug 的版本 → 回滚
  2. 数据库连接池耗尽 → 检查慢查询
  3. 下游服务挂了导致级联 → 检查熔断是否生效
  4. 配置变更出错 → 检查配置中心最近的变更
  5. 流量突增超过限流阈值 → 检查 HPA 是否生效

模拟题 3:”如果让你选 Kafka 还是 RabbitMQ?”

回答框架(场景驱动选型):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
不能一概而论,取决于场景:

选 Kafka 的场景:
  ✓ 日志收集、事件流(高吞吐,百万/s)
  ✓ 大数据管道(对接 Flink/Spark)
  ✓ 需要消息回溯(重新消费历史消息)
  ✓ 顺序保证(同一 Partition 内有序)

选 RabbitMQ 的场景:
  ✓ 复杂路由需求(Topic、Fanout、Header Exchange)
  ✓ 低延迟(μs 级 vs Kafka 的 ms 级)
  ✓ 中小规模,团队更熟悉 AMQP 协议
  ✓ 需要消息优先级、延时消息等高级功能

一句话总结:
  Kafka = 高速公路(吞吐大,但路线固定)
  RabbitMQ = 城市路网(灵活路由,但承载量有限)
本文由作者按照 CC BY 4.0 进行授权