正文如下👇

从“能跑”到“稳定运行三年不出大事故”
在 Kubernetes 上跑 Java,很多团队一开始都很自信:
不就是打个镜像、写个 YAML、起个 Pod 吗?
但真正上了生产你会发现,Java + K8s 是一场长期博弈:
在 Kubernetes 上跑 Java,几乎所有团队都会经历同一个阶段:
一开始很自信,上线很顺利,半年后开始疲于救火。
最初的认知通常是这样的:
于是大家会下意识地认为: “Java + K8s 也就这么回事。”
但真正进入长期运行阶段后,问题开始慢慢出现。
这是一个典型的业务中台服务:
部署方式非常“标准”:
resources: requests: cpu: "1" memory: "2Gi" limits: cpu: "2" memory: "2Gi"JVM 参数也“很传统”:
-Xms2g -Xmx2g上线初期,一切正常。
没有任何 Java OOM 日志,只看到:
Reason: OOMKilled重启之后又能跑。
第一次,大家认为是偶发; 第二次,认为是流量波动; 第三次,开始有人说“是不是 K8s 不稳定”。
监控上看到一个反直觉的现象:
这时候,很多团队会犯一个错误: 👉 盲目加 Pod、副本翻倍
结果:
滚动发布时,偶发:
这类问题最要命的地方在于:你很难在测试环境复现。
这个阶段,我给团队下了一个结论:
这不是 Kubernetes 的问题,也不是 Java 的问题,而是 JVM 没有被当成“运行在容器里的 JVM”来治理。
换句话说: 我们一直在用“物理机时代的 JVM 思维”,跑在“强边界的容器环境里”。
在容器里,JVM 实际消耗的内存是:
Heap+ Metaspace+ Direct Memory+ Thread Stack+ JVM 自身开销+ OS Buffer而 Kubernetes 只认一件事:
总和 > memory limit → 直接 OOMKilled
这和物理机时代完全不同。
这是最关键的一步。
# 删除-Xms2g-Xmx2g改为:
-XX:+UseContainerSupport-XX:MaxRAMPercentage=70设计逻辑:
👉 这是“容器优先”的 JVM 设计思路
重新定义资源策略:
requests: cpu: "800m" memory: "2Gi"limits: cpu: "2" memory: "2.5Gi"不是一拍脑袋就给值了,而是基于监控数据:
-XX:+HeapDumpOnOutOfMemoryError-XX:HeapDumpPath=/heapdumps架构原则:
线上 OOM,必须留下“现场证据”。
没有 Dump 的 OOM 排查,本质是猜谜。
-XX:+ExitOnOutOfMemoryError这一步是为 Kubernetes 设计的,而不是 JVM。
这是平台化自愈的基础。
避免一个接口干两件事。
java程序启动慢是事实。
没有 Startup Probe 的结果只有一个: 👉 启动期被误杀
这是避免滚动升级 502 的根本手段。
通过 Micrometer 暴露:
架构层面的价值是:
在 Java 场景下:
往往不会直接反映到 CPU。
最终策略是:
这套服务上线后:
真正起作用的不是某个 JVM 参数,而是这几个认知转变:
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。