【Kubernetes 性能排查】线上服务突然变慢?SRE 的 4 层排查法

你是不是也遇到过这种场景:大半夜被告警震醒,打开监控一看------服务响应时间从 50ms 飙到了 5s,用户反馈"转圈圈转不动"。你登录集群,kubectl get pods 一看,全是 Running,一脸懵:进程没挂,但就是慢

这种"假活"状态最折磨人。我干了 10 年运维,踩过无数坑,今天把 Kubernetes 环境下服务变慢的排查思路整理出来,希望能帮你少熬几个大夜。

核心思路:4 层排查法

不要一上来就查代码、猜原因。从外向里、从底层到上层,按这个顺序来:

复制代码
资源层 → 应用层 → 网络层 → 存储/依赖层

📋 前置条件

  • 有 kubectl 权限访问目标集群
  • Metrics Server 已部署------kubectl top 依赖它(kubectl get deployment metrics-server -n kube-system
  • 如果你用 Istio/Linkerd,准备好 istioctllinkerd 命令
  • 生产环境慎用破坏性操作(strace 可能卡住进程),优先用临时 Pod + ephemeral containers

🚨 第一层:资源层

这一层先快速判断 Pod 或节点是不是"吃不消了"。

1. 找出可疑 Pod

复制代码
# 看节点资源
kubectl top nodes

# 按 CPU 排序看 Pod
kubectl top pods --all-namespaces --sort-by=cpu

输出示例:

复制代码
NAMESPACE   NAME                    CPU(cores)   CPU%
default     api-server-7d5b6c8-h8   800m         80%
default     db-postgres-0           2500m        250%    <-- 超标了

我的判断规则:

  • Pod CPU 超过 limit 的 80% → 可能被限流,用 kubectl describe podThrottled 指标
  • Pod 内存持续逼近 limit → OOM 风险。kubectl top 是实时快照,趋势要看 Prometheus
  • 节点资源不足且驱逐事件多 → 查 kubectl get events -n default --sort-by='.lastTimestamp'

2. 进 Pod 内部抓内鬼

复制代码
kubectl exec -it <pod-name> -- /bin/sh
# 进去后
top -b -n 1 | head -20
# 或
ps aux --sort=-%cpu | head -10

⚠️ 警告: Distroless 镜像(比如谷歌的 gcr.io/distroless)没有 bash 和 top,不要慌------用 kubectl debug 创建一个临时容器挂进去。

复制代码
kubectl debug -it <pod-name> --image=busybox --target=<container-name>

3. CPU 100% 怎么办

strace 是定位高 CPU 的神器:

复制代码
# 进 Pod 找到高 CPU 的 PID
kubectl exec -it <pod-name> -- top -b -n 1

# 追踪系统调用
strace -c -p <PID>   # 汇总哪个系统调用占用最高
strace -p <PID> -T   # 实时输出,带耗时

(顺便说一句,strace 会略微拉慢进程,别在生产高峰用。用几分钟立刻停。)

4. 内存问题

看 RSS(常驻内存)和 cache 占用:

复制代码
kubectl exec -it <pod-name> -- cat /proc/<PID>/status | grep -E "VmRSS|VmSwap"

如果 Pod 不断重启(CrashLoopBackOff),kubectl describe pod 里通常能看到 OOMKilled。

💡 彩蛋: 如果节点 CPU 正常但 Pod 很慢,检查是否有 CPU 限流:

复制代码
kubectl get pod <pod-name> -o yaml | grep -A 5 "limits:"

CPU limit 设得过低会导致 CPU Throttling ------CPU 没用满但请求被强行排队。相关指标在 Prometheus:container_cpu_cfs_throttled_seconds_total。监控要是没配,看 kubectl describe pod 的 Events。

🚨 第二层:应用层

资源没问题?进应用内部看看。

1. 看日志------但别瞎看

复制代码
# 查慢请求日志
kubectl logs --tail=500 <pod-name> | grep -E "slow|timeout|error"

# 实时追踪
kubectl logs -f <pod-name> --since=10m

我踩过的坑: 日志写太多本身就会拖慢服务。日志级别设成 DEBUG?生产环境赶紧改回 INFO/WARN。

2. 链路追踪(如果你还没用,真的该上了)

说实话,分布式追踪是排查微服务慢请求的救命稻草。Jaeger 配合 Istio 或 OpenTelemetry,能清清楚楚看到每个请求在哪个环节卡住------是 A 服务处理慢,还是调用 B 服务的网络慢。

访问 Jaeger UI(通常 ingress 或 port-forward),按 Trace ID 搜一个慢请求,看火焰图就一目了然。

还没上 tracing? 有个笨办法但有效:在 Pod 里用 curl -w "@curl-format.txt" -o /dev/null -s "http://downstream-service" 手工测下游依赖。格式文件大概长这样:

复制代码
# curl-format.txt
     time_namelookup:  %{time_namelookup}s\n
        time_connect:  %{time_connect}s\n
     time_starttransfer:  %{time_starttransfer}s\n

3. pprof(如果你用 Go)

复制代码
# 前提:应用开启了 /debug/pprof
kubectl port-forward <pod-name> 8080:8080
go tool pprof -http=:8081 http://localhost:8080/debug/pprof/profile?seconds=30

浏览器打开 localhost:8081,火焰图直接告诉你哪个函数在烧 CPU。

💡 彩蛋: Java 服务?jstack。进 Pod 执行 jstack <PID> 导出线程栈。如果一个 Pod 里装了 JDK,镜像很大,用 kubectl debug --image=openjdk:11-jre-slim 挂进去。

🚨 第三层:网络层

这一层坑最多,我分成三类讲。

类型一:Service Mesh/Ingress 层面的延迟

复制代码
# Istio 环境看代理延迟
istioctl dashboard kiali
# 或
kubectl exec -it <pod-name> -c istio-proxy -- pilot-agent request GET stats

坑爹的是,有时候 Istio 配置没毛病,但 Pod 重启时 sidecar 先加载了旧配置缓存------一个过时的 ServiceEntry 可能把请求发到无效 IP。测试方法:临时停用 sidecar 注入(给命名空间去掉 istio-injection=enabled 标签),看延迟是否消失。

类型二:DNS 解析慢

CoreDNS 是无声的性能杀手。

复制代码
# 检查 CoreDNS Pod 状态
kubectl get pods -n kube-system -l k8s-app=kube-dns

# 看 CoreDNS 日志
kubectl logs -n kube-system -l k8s-app=kube-dns --tail=100

如果 CoreDNS 大量报 i/o timeout,别光盯着 DNS 服务器------检查 CNI 网络插件的性能和 Pod 与 CoreDNS 之间的连通性。

DNS 慢的典型特征:服务第一次调用慢,后面快。说明是 DNS 解析没缓存。生产环境强烈推荐启用 NodeLocal DNSCache

类型三:网络策略冲突

最隐蔽的坑。新节点加入集群,CNI 插件版本不一致,网络策略控制器没同步------服务能通但数据包在某个节点被拦。故障特征:非对称------部分 Pod 正常,部分慢。A 节点上的 Pod 跨节点调用 B 节点时,只有部分包丢了。

测试方法:

复制代码
# 找个临时 Pod 去 ping 目标 Service IP
kubectl run test-pod --image=busybox -it --rm -- nslookup <service-name>

# 或绕开 Service,直接用 ClusterIP
kubectl run test-pod --image=busybox -it --rm -- wget -O- http://<cluster-ip>:<port>

如果 ClusterIP 直接访问正常,但经过 Service 就慢 → DNS 或 kube-proxy 层面的问题。

💡 彩蛋:conntrack 表被撑爆

NodePort 模式下,请求量大时 conntrack 表会满,导致 TCP 重传和延迟飙升。

复制代码
# 在节点上检查 conntrack 统计(需要节点访问权限)
conntrack -S
# 看 "insert_failed" 或 "drop" 计数,涨得快就说明 conntrack 满了

# 检查当前连接表大小
sysctl net.netfilter.nf_conntrack_max
netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'

conntrack 坑的一个真实案例:WHOOP 团队发现 Ubuntu 自动安全更新触发 needrestart,重启网络服务时清空了 conntrack 表,导致 RDS 和 ElastiCache 的返回包被丢弃,响应延迟从 1 秒跳到 20 秒。

🚨 第四层:存储与依赖

1. PVC 存储 I/O 慢

数据库或日志写到持久卷,I/O 慢会拖垮整个 Pod。

复制代码
kubectl describe pvc <pvc-name>
# 看 Events 有没有 I/O 超时、挂载失败

# 进 Pod 用 dd 和 iostat(需要进节点或 debug 容器)
dd if=/dev/zero of=/mnt/data/test bs=1M count=100 conv=fdatasync

生产环境建议用 Inspektor Gadget 的 top_blockio,它能追踪容器级别的磁盘 I/O 延迟。

2. 外部依赖

应用依赖数据库、Redis、第三方 API,这些慢了也会让服务变慢。看看请求日志里的上下游调用耗时,用 tracing 最直观。

3. 数据库连接池

服务连接池配置太小,在流量高峰时大量请求在等连接。看应用日志有没有 waiting for connectiontimeout waiting for pool

快速自查清单(可以贴在工位上)

|---------------|-------------------------------------------------------------|-----------------------|
| 排查维度 | 快速命令 | 看什么 |
| 节点/Pod 资源 | kubectl top node/pod | 超限?被限流? |
| Pod 详细信息 | kubectl describe pod | Events、Restarts、OOM |
| CoreDNS 健康 | kubectl logs -n kube-system -l k8s-app=kube-dns --tail=50 | i/o timeout?SERVFAIL? |
| NetworkPolicy | kubectl get netpol -A | 策略冲突 |
| PVC 状态 | kubectl get pvc | Pending?I/O 超时? |
| 应用日志 | kubectl logs --tail=200 | 慢请求、连接池异常 |
| 链路追踪 | Jaeger UI(Ingress 地址) | 哪一跳最慢 |

常见陷阱(我帮你踩过了)

  1. "Pod 不是 Running 吗?" ------ 运行中不等于真正常。健康检查配置不对可能导致 Pod "假活"------应用没就绪但存活探针一直返回成功。建议用 startupProbe 替代存活探针的 initialDelaySeconds,给应用足够启动时间。
  2. "Log 怎么全在报错但排查没进展?" ------ 先看是不是日志级别太高。DEBUG 日志在大流量下本身就耗资源。改成 INFO/WARN,观察几分钟。
  3. "这个 Deployment 副本数我加到 100 了,怎么还是慢?" ------ 加节点解决不了延迟问题,尤其是 DNS 解析慢、网络策略冲突或服务网格配置不当。先把真正瓶颈定位再扩容。
  4. "为什么半夜 2-3 点才慢?" ------ 检查操作系统自动更新、定时任务、备份任务。WHOOP 团队的 Ubuntu 自动安全更新就是半夜触发的。
  5. "这 Pod 里连 strace 都装不上" ------ Distroless 镜像确实没这些工具。用 kubectl debug 创建临时容器,或直接用 ephemeral containers 功能(K8s 1.16+ GA,1.25+ 稳定)挂调试工具进去。别想着往生产镜像里塞调试工具------那是反模式。

写在最后

排查服务变慢,忌讳"我知道一定是 XXX 的问题"这种先入为主的猜测。我见过太多人一上来就怀疑"节点太少"、"服务代码有 bug",结果折腾半天,最后发现是 conntrack 表满了或者 DNS 超时。

按这 4 层排查法走一遍:资源层→应用层→网络层→存储/依赖层,10 分钟内大概率能定位根因。如果还不行------

你还有什么更好的排查套路?评论区见 👇

相关推荐
小猿姐1 天前
MySQL Top 10 热点问题 AI 运维实战:从内核诊断到云原生运维
mysql·云原生·aiops
阿里云云原生2 天前
深入内核:拆解 OpenTelemetry eBPF 探针如何优雅地“透视”多语言微服务?
云原生
大树882 天前
金刚石散热越强,管路越先见顶
大数据·运维·服务器·人工智能·ai
摇滚侠2 天前
Linux CentOS7 rpm 安装 MySQL 5.7
linux·运维·mysql
霸道流氓气质2 天前
领域驱动设计(DDD)在 Spring Boot 微服务中的实践指南
运维·spring boot·微服务
Inhand陈工2 天前
基于台达PLC与映翰通IG502的智慧水产养殖精准投喂与远程运维解决方案
运维·人工智能·物联网·阿里云·信息与通信
酣大智2 天前
ARP代理--工作原理
运维·网络·arp·arp代理
shushangyun_2 天前
2026年快消品B2B系统推荐:支持终端门店订货、促销政策自动化的工具?
java·运维·网络·数据库·人工智能·spring·自动化
施努卡机器视觉2 天前
SNK施努卡侧滑门锁上滑轮总成自动化装配线,从零件到组件,全流程精密制造方案
运维·自动化·制造
AC赳赳老秦2 天前
用 OpenClaw 搭建服务器故障应急响应系统,自动处理 80% 常见运维故障
android·运维·服务器·python·rxjava·deepseek·openclaw