机器 A 向机器 B 建立 TCP 连接,当建立了 20 万的连接后,想建立新的连接就很慢。
此时在机器 A 上用 tcpdump 抓包可以看到:有的连接可以正常三次握手,有的连接需要发多个 syn 包,有的连续发 6 次 syn 包无响应后应用层就报错了。
在机器 B 上用 ebpf 来捕获 kfree_skb 的调用,可以发现内核的确是丢包了,但是如何知道为什么会丢包呢?不知道谁能解答。此时内核日志无异常,cpu 和内存也很充足。我是用的 bpftrace 定位的,bpftrace 的执行脚本如下:
kprobe:kfree_skb
{
$skb = (struct sk_buff*) arg0;
$ip_header = ((struct iphdr *) ($skb->head + $skb->network_header));
// 这里只捕获 daddr 是 192.168.2.120 的包
if ($ip_header->daddr == 0x7802a8c0)
{
$tcp_header= ((struct tcphdr *) ($skb->head + $skb->network_header + ($ip_header->ihl << 2)));
$sport = $tcp_header->source;
$dport = $tcp_header->dest;
$dport = ($dport >> 8) | (($dport << 8) & 0xff00);
$sport = ($sport >> 8) | (($sport << 8) & 0xff00);
// 这里只捕获 dport 是 8100 的包
if ($dport == 8100) {
time("%H:%M:%S ");
printf("%s:%d > %s:%d\n", ntop($ip_header->saddr), $sport, ntop($ip_header->daddr), $dport);
}
}
}
1
sky96111 2023-05-14 17:50:54 +08:00
|
2
USAToday 2023-05-14 17:51:36 +08:00
syn 包丢的话,可以考虑半连接、全连接丢包。我记得有个丢包情况是内核直接丢弃,不会有任何日志
|
3
tomychen 2023-05-14 18:10:10 +08:00
这时候不是应该贴一下最大连接数的配置吗?
|
4
xing393939 OP @sky96111 打印 kfree_skb 的上游和下游调用链,bpftrace 也能实现的,问题是接下来怎么继续排查呢
|
5
xing393939 OP @tomychen
``` net.core.somaxconn = 40960 net.ipv4.tcp_max_syn_backlog = 40960 net.ipv4.tcp_syncookies = 1 ``` 是说这三个吗? |
6
leonshaw 2023-05-14 19:19:41 +08:00
看一下 nstat 统计
|
7
LGA1150 2023-05-14 22:08:14 +08:00
nf_conntrack_max 配置了多少?
|
8
jackgoudan 2023-05-14 23:28:01 +08:00
猜测是一些队列满了? 最近我们的业务高并发压测遇到过丢包,同事排查过这些问题,好像总体原因就是链接队列放不下了。这会不在公司,看不到排查文档。
|
9
liuxu 2023-05-15 01:23:59 +08:00
/proc/sys/net/ipv4/tcp_abort_on_overflow ,默认 0 是 drop 包,置 1 为 rst ,你置 1 看看会不会 rst ,那就是队列满了
当然这是个直接却冒进的做法,正确的方法还是 ss -n state syn-recv 看看收了多少 syn https://www.alibabacloud.com/blog/tcp-syn-queue-and-accept-queue-overflow-explained_599203 |
10
xing393939 OP |
11
xing393939 OP @jackgoudan
很想参考一下你们的排查文档 |
12
xing393939 OP @liuxu
跑了 ss -n state syn-recv ,没有处于这个状态的连接。 机器 B 配置了 net.ipv4.tcp_abort_on_overflow=1 后,机器 A 上并没有抓包到 rst 包 |
13
salmon5 2023-05-15 10:09:34 +08:00
换硬件试试
|
14
Panic 2023-05-15 10:39:43 +08:00
防火墙 selinux 都关了吧,不是队列的话 不贴点内核调用链不好分析了
|
15
tomychen 2023-05-15 15:17:40 +08:00
从你的描述上,感觉像两个东西,一个是#8 说的内核队列打满了,另一个就是 fd 满了,我没法确定你的场景。
但“机器 A 向机器 B 建立 TCP 连接,当建立了 20 万的连接后,想建立新的连接就很慢。” 这个描述就很像 fd 满了或者说队列满了,需要等待释放。 具体排查的情况,我一下子说不上来,可能也得模拟场景。 |
16
lysS 2023-05-15 17:21:29 +08:00
20 万的连接,有丢包不是很正常吗?可以试试提升硬件能不能缓解?
|
17
liuxu 2023-05-16 00:52:47 +08:00
@xing393939 #12 不是队列满那这个事情就很麻烦了,我之前抓 k8s 的 dns 数据包丢包,查内核 conntrack ,查了大半天才查出原因, 你可以再检查检查 conntrack ,不一定是这个问题,要收集整个内核调用链的数据包了
https://www.liuquanhao.com/posts/%E8%AE%B0%E4%B8%80%E6%AC%A1k3s%E7%9A%84dns%E9%97%AE%E9%A2%98%E8%B0%83%E6%9F%A5%E8%A7%A3%E5%86%B3%E8%BF%87%E7%A8%8B/ |
18
jackgoudan 2023-05-16 19:03:55 +08:00
@xing393939 内网资料,也不好外传。可以用 skbtracer ,打印出 kfree_skb 的调用栈,看看丢包的函数调用链。我们的情况是丢包位于容器内的 eth0 ,调整 net.core.netdev_max_backlog 参数。具体可能不适用,先从函数调用链入手。
|