一、问题背景
我在 Prometheus / Grafana 监控中发现 Kubernetes 集群中有一个节点网络流量明显偏高。
异常节点是:
10.82.1.39
监控中看到该节点下载和上传带宽都比较高,大概在:
下载带宽:400 Mb/s 左右
上传带宽:390 Mb/s 左右
由于这个节点上运行的业务 Pod 比较多,如果一个个进入业务容器排查,效率会很低。因此我没有直接逐个查看容器,而是按照节点网络链路进行排查:
先确认节点真实网卡流量
再定位高流量虚拟网卡 veth
再通过 tcpdump 抓包确认 Pod IP
最后通过 Pod IP 反查具体业务 Pod
二、确认节点真实网络流量
我先登录到异常节点:
ssh root@10.82.1.39
然后查看节点默认出口网卡:
ip route | awk '/default/ {print $5; exit}'
确认默认网卡是:
eth0
接着我使用 sar 查看节点上各个网卡的实时流量:
sar -n DEV 1 5
如果系统没有安装 sar,可以先安装:
yum install -y sysstat
我重点关注这些字段:
IFACE 网卡名称
rxkB/s 接收流量
txkB/s 发送流量
当时看到的关键结果是:
eth0 rxkB/s 53345.71 txkB/s 1774.42
cbr0 rxkB/s 1575.83 txkB/s 51586.91
veth190a57d3 rxkB/s 151.10 txkB/s 45395.60
换算以后大概是:
eth0 下行约 52 MB/s,约等于 416 Mb/s
cbr0 出方向约 50 MB/s,约等于 403 Mb/s
veth190a57d3 出方向约 44 MB/s,约等于 354 Mb/s
这说明 Prometheus 上看到的高流量不是单纯误报,节点物理网卡 eth0 确实存在比较高的下行流量。
三、分析流量链路
通过 sar 的结果,我判断流量链路大概是:
外部流量进入 eth0
↓
经过 cbr0 网桥
↓
转发到 veth190a57d3
↓
进入某个业务 Pod
也就是说,这次不是所有容器都有问题,而是主要流量集中到了:
veth190a57d3
所以我接下来的重点就是确认:
veth190a57d3 对应的是哪个 Pod
四、通过 tcpdump 抓 veth 流量
因为在 TKE / containerd / cbr0 网络环境下,直接通过脚本反查 veth 和 Pod 的关系有时不稳定,所以我采用了最直接的方法:对高流量 veth 抓包。
执行命令:
tcpdump -i veth190a57d3 -nn -q -c 30
如果系统没有安装 tcpdump,可以先安装:
yum install -y tcpdump
抓包结果中,我看到了类似下面的通信:
10.169.20.169.57602 > 172.18.8.49.1521
172.18.8.49.1521 > 10.169.20.169.57602
10.169.20.169.55648 > 10.82.8.6.6379
10.82.8.6.6379 > 10.169.20.169.55648
根据这个结果,我初步判断:
10.169.20.169 是 Pod IP
172.18.8.49:1521 是 Oracle 数据库
10.82.8.6:6379 是 Redis
其中 1521 是 Oracle 常见端口,6379 是 Redis 常见端口。
从抓包结果看,172.18.8.49:1521 向 10.169.20.169 返回了大量数据,所以这次高流量很可能是某个业务 Pod 正在频繁访问 Oracle,Oracle 返回了大量查询结果。
五、通过 Pod IP 反查业务 Pod
拿到 Pod IP 以后,我直接通过 kubectl 反查 Pod:
kubectl get pod -A -o wide | grep '10.169.20.169'
通过这个命令可以查到:
namespace
pod name
pod ip
node
这样就能定位到具体是哪个业务 Pod 在节点 10.82.1.39 上产生了大量网络流量。
六、确认这个 Pod 的数据库连接情况
定位到 Pod IP 后,我继续在节点上查看它和 Oracle、Redis 的连接情况。
查看和 Oracle 的连接数:
ss -ant | grep '10.169.20.169' | grep '172.18.8.49:1521' | wc -l
查看和 Oracle 的详细连接:
ss -antp | grep '10.169.20.169' | grep '172.18.8.49:1521'
查看和 Redis 的连接:
ss -antp | grep '10.169.20.169' | grep '10.82.8.6:6379'
如果这里连接数比较多,说明这个 Pod 可能存在以下情况:
大量并发查询 Oracle
批量同步数据
查询结果集过大
循环查询
没有分页查询
查询 Oracle 后写入 Redis
定时任务或批处理任务正在执行
七、抓更长时间的包进一步确认
为了避免只看 30 个包导致判断不准确,我可以继续抓 10 秒的数据:
timeout 10 tcpdump -i veth190a57d3 -nn -q > /tmp/veth190a57d3.log
查看 Oracle 相关流量:
grep '172.18.8.49.1521' /tmp/veth190a57d3.log | head -50
查看 Redis 相关流量:
grep '10.82.8.6.6379' /tmp/veth190a57d3.log | head -50
粗略统计通信最多的连接对:
awk '{print $3,$5}' /tmp/veth190a57d3.log \
| sort \
| uniq -c \
| sort -nr \
| head -30
如果持续看到大量:
172.18.8.49.1521 > 10.169.20.169.xxxxx
就说明主要流量方向是:
Oracle 数据库返回大量数据给业务 Pod
八、查看业务 Pod 日志
查到具体 Pod 后,我再看应用日志。
假设命名空间是 <namespace>,Pod 名称是 <pod-name>:
kubectl logs -n <namespace> <pod-name> --tail=300
如果 Pod 有多个容器,我先查看容器名称:
kubectl get pod -n <namespace> <pod-name> -o jsonpath='{.spec.containers[*].name}'
然后指定容器查看日志:
kubectl logs -n <namespace> <pod-name> -c <container-name> --tail=300
我会重点搜索这些关键词:
kubectl logs -n <namespace> <pod-name> --tail=1000 \
| egrep -i 'oracle|sql|select|redis|sync|job|task|error|exception|timeout'
主要确认有没有:
定时任务执行
批量同步任务
SQL 查询刷屏
异常重试
查询超时
连接池异常
Redis 写入频繁
外部接口调用频繁
九、如果是 Java 应用,继续查看线程
如果这个 Pod 是 Java 应用,并且容器里有 JDK 工具,我可以进一步查看线程栈。
进入容器:
kubectl exec -it -n <namespace> <pod-name> -- bash
查看 Java 进程:
jps -l
导出线程栈:
jstack <PID> > /tmp/jstack.txt
然后搜索和数据库、Redis 相关的调用:
grep -iE 'oracle|jdbc|redis|lettuce|jedis|mybatis|druid|hikari|select|execute' /tmp/jstack.txt
如果容器里没有 jstack,我可以先用下面命令确认 Java 进程:
ps -ef | grep java
线程栈里如果看到大量线程在执行 JDBC 查询、Redis 写入、MyBatis 查询或者某个业务方法,就可以进一步定位到具体代码逻辑。
十、判断是否属于正常业务流量
定位到业务 Pod 以后,我不会马上处理,而是先判断这是不是正常业务行为。
我会和开发或业务确认:
这个时间点是否有定时任务?
是否有数据同步任务?
是否有报表导出?
是否有全量缓存刷新?
是否有 Oracle 到 Redis 的同步?
是否有外部系统集中调用?
是否有新版本刚发布后触发缓存预热?
如果是正常业务任务,需要评估是否做优化。
如果不是正常业务任务,就要重点排查是否存在异常循环、异常重试或者 SQL 问题。
十一、可能的优化方向
如果最终确认是业务 Pod 查询 Oracle 导致节点网络流量高,我会从这些方向优化:
1. 检查 SQL 是否缺少分页
2. 检查 SQL 是否返回字段过多
3. 检查是否存在循环查询、重复查询
4. 检查是否有异常重试
5. 检查是否把 Oracle 数据批量写入 Redis
6. 检查连接池并发是否过大
7. 检查是否有外部接口触发大量查询
8. 对大查询做分页、限流、错峰执行
9. 对缓存预热和数据同步任务加并发控制
10. 对非实时任务放到低峰期执行
十二、临时应急处理方式
如果这个 Pod 已经明显影响节点或者集群稳定性,我可以根据业务影响选择应急处理方式。
1. 继续观察流量是否下降
sar -n DEV 1 5 | grep -E 'IFACE|eth0|cbr0|veth190a57d3'
如果流量已经下降,可以先记录问题,继续观察。
2. 重启异常 Pod
如果判断是应用异常循环,可以删除 Pod 让它重新拉起:
kubectl delete pod <pod-name> -n <namespace>
如果这个 Pod 是 Deployment 管理的,会自动创建新 Pod。
3. 临时缩容
如果是 Deployment,可以先查看:
kubectl get deploy -n <namespace>
临时缩容:
kubectl scale deploy <deploy-name> -n <namespace> --replicas=0
或者缩到 1 个副本:
kubectl scale deploy <deploy-name> -n <namespace> --replicas=1
这个操作要谨慎,需要确认业务影响。
4. 从入口侧限流
如果是外部请求触发大量数据库查询,可以从入口侧处理:
Nginx 限流
CLB 限流
网关限流
WAF 限制
安全组限制
应用接口开关
如果是数据库同步或定时任务问题,建议优先从应用侧暂停任务,而不是直接断数据库连接。
十三、这次排查结论
这次问题我可以这样总结:
我在 Prometheus / Grafana 中发现 10.82.1.39 节点网络流量异常升高。
我登录节点后,通过 sar -n DEV 1 5 查看网卡流量,发现 eth0 下行约 53MB/s,cbr0 出方向约 51MB/s,veth190a57d3 出方向约 45MB/s。
由此判断,外部流量从 eth0 进入节点,经 cbr0 转发到 veth190a57d3 对应的 Pod。
随后我使用 tcpdump -i veth190a57d3 抓包,发现高流量 Pod IP 为 10.169.20.169。
抓包中主要通信对象为 172.18.8.49:1521 和 10.82.8.6:6379,其中 172.18.8.49:1521 是 Oracle 数据库端口,10.82.8.6:6379 是 Redis 端口。
从抓包方向看,Oracle 数据库向 10.169.20.169 返回了大量数据,因此初步判断这次节点网络流量升高,主要是 10.169.20.169 对应的业务 Pod 频繁查询 Oracle,导致 Oracle 返回大量数据到 Pod。
十四、完整排查命令清单
1. 查看节点网卡流量
sar -n DEV 1 5
2. 找出高流量 veth
从 sar 输出中找到类似:
veth190a57d3 txkB/s 很高
3. 抓高流量 veth
tcpdump -i veth190a57d3 -nn -q -c 30
4. 反查 Pod IP
从 tcpdump 中找到 Pod IP,例如:
10.169.20.169
然后执行:
kubectl get pod -A -o wide | grep '10.169.20.169'
5. 查看 Pod 到 Oracle 的连接
ss -antp | grep '10.169.20.169' | grep '172.18.8.49:1521'
6. 查看 Pod 到 Redis 的连接
ss -antp | grep '10.169.20.169' | grep '10.82.8.6:6379'
7. 统计 Oracle 连接数
ss -ant | grep '10.169.20.169' | grep '172.18.8.49:1521' | wc -l
8. 抓 10 秒包保存
timeout 10 tcpdump -i veth190a57d3 -nn -q > /tmp/veth190a57d3.log
9. 统计通信对
awk '{print $3,$5}' /tmp/veth190a57d3.log \
| sort \
| uniq -c \
| sort -nr \
| head -30
10. 查看应用日志
kubectl logs -n <namespace> <pod-name> --tail=300
十五、我的排查经验总结
这次排查里,我总结出来的经验是:
节点流量高时,不要一开始就逐个查看业务容器。
应该先从节点网卡流量入手,确认到底是物理网卡高,还是监控统计口径问题。
如果物理网卡确实高,再看 cbr0、veth 等虚拟网卡,找到流量最大的 veth。
找到高流量 veth 后,直接用 tcpdump 抓包,通常可以很快看到 Pod IP 和通信目标。
拿到 Pod IP 后,再用 kubectl get pod -A -o wide 反查具体业务 Pod。
最后再结合目标 IP、端口、应用日志、线程栈和业务时间点,判断是正常业务流量、批处理任务,还是异常查询或重试。
简单来说,这次排查路径是:
Prometheus 发现 10.82.1.39 节点流量高
↓
sar 确认 eth0 / cbr0 / veth190a57d3 高
↓
tcpdump 抓 veth190a57d3
↓
发现 Pod IP:10.169.20.169
↓
发现主要访问目标:172.18.8.49:1521 Oracle
↓
判断为业务 Pod 查询 Oracle 返回大量数据导致节点下行流量升高