用 ebpf 可以定位到服务器这边会偶尔丢掉 syn 包,如何进一步定位具体是什么原因丢包的?

350 天前
 xing393939

机器 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);
                }
        }
}
1665 次点击
所在节点    Linux
18 条回复
sky96111
350 天前
USAToday
350 天前
syn 包丢的话,可以考虑半连接、全连接丢包。我记得有个丢包情况是内核直接丢弃,不会有任何日志
tomychen
350 天前
这时候不是应该贴一下最大连接数的配置吗?
xing393939
350 天前
@sky96111 打印 kfree_skb 的上游和下游调用链,bpftrace 也能实现的,问题是接下来怎么继续排查呢
xing393939
350 天前
@tomychen
```
net.core.somaxconn = 40960
net.ipv4.tcp_max_syn_backlog = 40960
net.ipv4.tcp_syncookies = 1
```
是说这三个吗?
leonshaw
350 天前
看一下 nstat 统计
LGA1150
349 天前
nf_conntrack_max 配置了多少?
jackgoudan
349 天前
猜测是一些队列满了? 最近我们的业务高并发压测遇到过丢包,同事排查过这些问题,好像总体原因就是链接队列放不下了。这会不在公司,看不到排查文档。
liuxu
349 天前
/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
xing393939
349 天前
@LGA1150
net.netfilter.nf_conntrack_max = 6553600
net.nf_conntrack_max = 6553600
xing393939
349 天前
@jackgoudan
很想参考一下你们的排查文档
xing393939
349 天前
@liuxu
跑了 ss -n state syn-recv ,没有处于这个状态的连接。
机器 B 配置了 net.ipv4.tcp_abort_on_overflow=1 后,机器 A 上并没有抓包到 rst 包
salmon5
349 天前
换硬件试试
Panic
349 天前
防火墙 selinux 都关了吧,不是队列的话 不贴点内核调用链不好分析了
tomychen
349 天前
从你的描述上,感觉像两个东西,一个是#8 说的内核队列打满了,另一个就是 fd 满了,我没法确定你的场景。
但“机器 A 向机器 B 建立 TCP 连接,当建立了 20 万的连接后,想建立新的连接就很慢。”
这个描述就很像 fd 满了或者说队列满了,需要等待释放。

具体排查的情况,我一下子说不上来,可能也得模拟场景。
lysS
349 天前
20 万的连接,有丢包不是很正常吗?可以试试提升硬件能不能缓解?
liuxu
348 天前
@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/
jackgoudan
348 天前
@xing393939 内网资料,也不好外传。可以用 skbtracer ,打印出 kfree_skb 的调用栈,看看丢包的函数调用链。我们的情况是丢包位于容器内的 eth0 ,调整 net.core.netdev_max_backlog 参数。具体可能不适用,先从函数调用链入手。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/939902

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX