接口忽快忽慢的元凶是CPU限流——一次K8s CFS排查复盘
概述
线上一套微服务里的移动端查询接口突然”忽快忽慢”:快的时候几十毫秒返回,慢的时候要等上秒级,而且同一个接口、同样的参数,前后两次请求表现完全不同。服务是双副本部署,监控大盘上宿主机 CPU 长期 90% 以上空闲——看起来谁都不缺资源。
- 故障现象:同一查询接口延迟呈双峰分布(几十 ms / 秒级),双副本中一个 pod load 6+、三十个线程处于运行态,另一个 pod load 0.5、全部休眠;
- 根因:Pod 的 CPU limit 只有 0.4 核(
cpu.cfs_quota_us=40000/100000),繁忙副本在 38.8% 的调度周期里打穿 CFS 配额被整体冻结,所有业务线程以 100ms 为台阶周期性停摆; - 关键反直觉点:该 pod 平均 CPU 用量只占配额的 25%,”平均很闲”与”高频被限流”并不矛盾——限流看的是峰值,不是均值。
调大 limit 后 nr_throttled 归零、接口延迟恢复平稳。这篇复盘记录完整排查路径,以及两个值得单独记录的坑:top 的 TIME+ 单位误读(差 60 倍),和容器里没有 jcmd/jstat 时的取证替代。文末后记补充同日把排查铺向全集群后的发现:这不是一个服务的病,是整个集群的系统性配额问题。
从一次单号重复事故,聊透Redis原子发号与面试高频考点
生产系统里最不起眼、又最容易在并发下翻车的代码,大概就是「查最大单号然后加一」这种两行取号。上周就撞上了一次:两位仓管员前后差 2 秒各做了一笔外部调拨,落库后两张调拨单单号相同,第二笔回写 ERP 时被对方系统以「编码唯一性要求:该编码已被使用」拒收。
排查根因、评估方案、换成 Redis 原子发号、真机并发压测验证,一路走下来,恰好把 Redis 的一大串面试高频考点串成了线。这篇文章先复盘事故与修复,再把考点一次讲透。
Nginx句柄耗尽引发K8s探针误杀:一次跨层故障的排查复盘
概述
一套跑在 K8s 上的 MES 系统里,辅助服务 Pod mes-app-assist 频繁重启:kubectl describe pod 显示容器因 Liveness 存活探针连续失败,被 kubelet 强行终止(退出码 137 / SIGKILL)。
- 故障现象:Pod 反复重启,退出码 137 初看像 OOMKilled,但事件日志明确写着
Liveness probe failed; - 根因:外部接入层 Nginx 所在宿主机的文件描述符上限(
nofile)过低——worker 进程软限制仅 1024。并发连接持续累积后,Nginx 报24: Too many open files,既无法建立到后端 NodePort 的 socket 连接,连返回错误页50x.html的文件句柄都拿不到,经它转发的请求只能以 HTTP 500 或超时收场; - 误杀机制:该 Pod 的 Liveness 探针被配置成跨节点探测外部 Nginx 反代地址——外部网关句柄耗尽,被 kubelet 误判为容器死亡,实际健康的后端容器被误杀重启。外部故障沿着探针链路反向传导进了 K8s 内部。
简历实战·下——真实简历模板:后端工程师版,可直接改用
简历实战·上——撰写与美化:把二十七篇素材写成一份能拿到面试的简历
MES+WMS 面试备战(二十七):运维篇·下——物理备份一键化:增量链的自愈与恢复演练
MES+WMS 面试备战(二十六):运维篇·上——把 MES 搬上 K8s:部署清单、稳定域名与自建监控栈
系列二十五篇本已完结,但运维线一直是个缺口——前面讲过的”K8s 部署痕迹”(云主线的 pod 配置、物联篇的 0 号节点)都只是切片。这两篇增补把切片拼成整图:本篇讲一套生产 K8s 部署清单——CentOS 7 自建集群上跑全套 MES 微服务,外加完全自建的 Prometheus 告警监控栈;下一篇讲 MySQL 的物理备份一键化与恢复演练。
先修正一个容易望文生义的误解:这个项目叫 install-k8s,但里面没有一行安装脚本——它是部署清单(manifests)仓库,K8s 集群本身装好后,”把 MES 搬上去”的全部知识都沉淀在这三十八个 YAML 里。这个定位本身就值得说:集群是易耗品,清单才是资产——装集群一天的活,调清单调了一年。