Java 应用在 Kubernetes 中的滚动更新(RollingUpdate)策略详解
滚动更新(RollingUpdate)是 Kubernetes Deployment 最常用的更新策略,几乎是 Java Spring Boot、Spring Cloud、Quarkus、Micronaut 等后端服务在生产环境的标准做法。
核心概念对比
| 策略类型 | 是否同时存在新旧版本 | 服务中断时间 | 资源峰值占用 | 回滚难度 | Java 服务最常用场景 |
|---|---|---|---|---|---|
| RollingUpdate | 是 | 通常 0 | 中等~较高 | 容易 | 绝大多数生产环境首选 |
| Recreate | 否 | 有(秒~分钟) | 较低 | 中等 | 数据库迁移、状态强绑定服务 |
| Blue-Green | 是(但手动控制) | 接近 0 | 最高(双份) | 容易 | 金融、对版本切换极度敏感场景 |
| Canary | 是(部分流量) | 0 | 中等 | 中等 | 灰度发布、A/B 测试 |
Java 服务 90%+ 的场景最终都会选择 RollingUpdate。
RollingUpdate 的两个核心控制参数
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: # 最多可以比期望副本数多多少个 Pod(可以是整数或百分比)
maxUnavailable: # 更新期间最多允许多少个 Pod 不可用(整数或百分比)
最常见的几种组合(按推荐顺序):
| 组合写法 | maxSurge | maxUnavailable | 含义与适用场景 | 资源峰值倍数 | 推荐指数 |
|---|---|---|---|---|---|
| 1:1(最保守、安全) | 25% | 25% | 标准推荐写法,兼顾速度与稳定性 | ≈1.25x | ★★★★★ |
| 激进型(追求最快上线) | 100% | 0% | 几乎瞬间完成,但资源翻倍,适合资源充裕集群 | ≈2x | ★★★☆☆ |
| 极保守型(零中断优先) | 0 | 1(或 10%) | 一次只替换一个,适合对可用性要求极高的服务 | ≈1.0x | ★★★★☆ |
| 内存敏感型(常见于 Java) | 1 | 25% | 控制峰值内存占用,适合 JVM 内存吃紧的场景 | ≈1.1~1.2x | ★★★★☆ |
| 副本数很少(1~3副本) | 1 | 0 | 小规模服务推荐,避免任何时刻副本数 < 期望值 | ≈2x(短暂) | ★★★★☆ |
生产中最推荐的 Java 滚动更新模板(2025-2026 主流写法)
apiVersion: apps/v1
kind: Deployment
metadata:
name: order-service
spec:
replicas: 6
selector:
matchLabels:
app: order-service
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 25% # 最多同时多出 1~2 个 Pod(6副本时最多多1~2个)
maxUnavailable: 25% # 最多允许 1~2 个 Pod 不可用
minReadySeconds: 30 # Pod 就绪后至少等待 30s 才认为稳定
progressDeadlineSeconds: 600
revisionHistoryLimit: 10
template:
metadata:
labels:
app: order-service
spec:
terminationGracePeriodSeconds: 60 # 优雅终止时间(Java 应用建议 ≥ 30s)
containers:
- name: app
image: registry.cn-hangzhou.aliyuncs.com/my-ns/order-service:1.2.3
ports:
- containerPort: 8080
readinessProbe:
httpGet:
path: /actuator/health/readiness # Spring Boot 3.x 推荐
port: 8080
initialDelaySeconds: 20
periodSeconds: 5
timeoutSeconds: 3
successThreshold: 1
failureThreshold: 3
livenessProbe:
httpGet:
path: /actuator/health/liveness
port: 8080
initialDelaySeconds: 60
periodSeconds: 10
resources:
requests:
cpu: 800m
memory: 1.5Gi
limits:
cpu: 1500m
memory: 2.5Gi
env:
- name: JAVA_OPTS
value: "-XX:MaxRAMPercentage=75.0 -XX:+UseZGC -XX:ConcGCThreads=2"
lifecycle:
preStop:
exec:
command: ["/bin/sh", "-c", "sleep 15"] # 给优雅停机留时间
Java 应用在滚动更新中常见的坑与解决办法
| 问题 | 表现 | 解决办法(优先级顺序) |
|---|---|---|
| 优雅停机没做好,请求丢失 | 503 / connection reset | 1. terminationGracePeriodSeconds ≥ 30~60s 2. preStop sleep 或调用 /shutdown 接口 |
| readinessProbe 太快,流量提前进来 | 502 / 慢请求 | initialDelaySeconds ≥ 启动时间 + 20s 使用 /health/readiness |
| JVM 老年代频繁 Full GC | Pod 频繁重启 / OOMKilled | 1. 使用 ZGC / Shenandoah 2. MaxRAMPercentage 70~80% 3. 降低 maxSurge |
| 启动太慢,滚动更新卡住 | progressDeadlineSeconds 超时 | 增加 progressDeadlineSeconds 到 900~1200 优化镜像分层 |
| 副本数少(1~2个)时短暂无服务 | maxUnavailable=25% 时仍断流 | maxUnavailable: 0 maxSurge: 1 或 100% |
推荐的 Java 服务滚动更新参数参考表
| 服务规模 / 场景 | replicas | maxSurge | maxUnavailable | minReadySeconds | terminationGracePeriodSeconds | 推荐 GC |
|---|---|---|---|---|---|---|
| 小型内部服务(测试/开发) | 2~3 | 100% | 0 | 20 | 30 | ZGC / Epsilon |
| 中型业务服务 | 4~10 | 25% | 25% | 30~45 | 45~60 | ZGC / Shenandoah |
| 高可用核心服务 | 6+ | 1~2 | 1 | 45~60 | 60~120 | ZGC |
| 内存极度敏感(单 Pod 8GB+) | 任意 | 1 | 25% | 60 | 90 | ZGC + 限流 |
快速检查命令
# 查看当前 rollout 状态
kubectl rollout status deployment/order-service
# 查看历史版本
kubectl rollout history deployment/order-service
# 回滚到上一个版本
kubectl rollout undo deployment/order-service
# 回滚到指定版本
kubectl rollout undo deployment/order-service --to-revision=3
# 暂停滚动更新(调试用)
kubectl rollout pause deployment/order-service
希望这篇内容能帮你把 Java 应用在 K8s 上的滚动更新策略理清楚。
你目前遇到的具体问题是?
- 启动太慢导致滚动卡住?
- 优雅停机没做好丢请求?
- 内存峰值爆炸?
- 小副本数场景下仍然断流?
- 想做金丝雀 / 蓝绿?
告诉我具体场景,我可以给出更针对性的 yaml + 启动参数组合。