Linux中tcp队列查询

在做系统优化的过程中,最常见的一种情况就是tcp并发连接数的调整。

首先了解一下Linux系统中tcp连接队列的情况,在内核2.2版本以后,listen队列分成两组SYN和ACCEPT,如下图

注意:两队列都是处于listen状态的队列

all-1

那么在实际情况下,我们如何判断这两个队列是排队情况。

在内核3.10版本之后,可以通过ss -tnlp的命令查询

当处于listen状态下,Recv-Q表示Accept Queue,Send-Q表示backlog参数。

那么backlog参数又是什么,我们参考Linux中的man手册关于listen函数listen(2) - Linux manual page

可以看到backlog就是限制最大的SYN和ACCEPT数量,所以,但发现排队的队列数量过大,就可能导致连接的并发数过低,当然前提的应用的性能足够高。

但有时候ss命令给出的数据并不完全准确,因为给出的统计是以秒为单位,出现队列满问题的窗口可能是非常短的,所以这时我们还得进行其他的信息辅助确认,通过以下命令可以查询出listen状态下被丢弃的包的数量

nstat -az TcpExtListenDrops

 如果以上的输出不对增长,说明存在越来越多的listen的包被丢弃,也说明存在队列满的情况

这时候我们就可以提高内核参数进行优化

net.core.somaxconn

这时我们又提出一个问题,我们能不能知道是哪个应用出现了队列满的问题呢?

当然是可以的,我们参考文章

https://blog.cloudflare.com/syn-packet-handling-in-the-wild/

/*
 * Prints details on specifically what connections
 * suffered due to Accept Queue overflow. It can be greatly
 * useful for identifying periodically hung applications that
 * fails to accept() connections fast enough.
 *
 * Usage: stap acceptq.stp
 */
probe begin {
    printf("time (us)       \tacceptq\tqmax\tlocal addr\tremote_addr\n")
}

function skb_get_remote_v4addr:string(skb:long)
{
    return format_ipaddr(__ip_skb_daddr(__get_skb_iphdr(skb)), 2 /* AF_INET */)
}

function skb_get_remote_v6addr:string(skb:long)
{
    ipv6_hdr = &@cast(__get_skb_iphdr(skb), "ipv6hdr")
    return format_ipaddr(&ipv6_hdr->daddr, 10 /* AF_INET6 */)
}

function skb_get_remote_port:long(skb:long)
{
    return __tcp_skb_sport(__get_skb_tcphdr(skb))
}

probe kernel.function("tcp_v4_conn_request") {
    if ($sk->sk_ack_backlog > $sk->sk_max_ack_backlog) {
        printf("%d\t%d\t%d\t%s:%d\t%s:%d\n",
            gettimeofday_us(),
            $sk->sk_ack_backlog,
            $sk->sk_max_ack_backlog,
            inet_get_ip_source($sk),
            inet_get_local_port($sk),
            skb_get_remote_v4addr($skb),
            skb_get_remote_port($skb));
    }
}

probe kernel.function("tcp_v6_conn_request") {
    if ($sk->sk_ack_backlog > $sk->sk_max_ack_backlog) {
        printf("%d\t%d\t%d\t[%s]:%d\t[%s]:%d\n",
            gettimeofday_us(),
            $sk->sk_ack_backlog,
            $sk->sk_max_ack_backlog,
            inet_get_ip_source($sk),
            inet_get_local_port($sk),
            skb_get_remote_v6addr($skb),
            skb_get_remote_port($skb));
    }
}

将以上的内容存成脚本acceptq.stp,运行stap -v acceptq.stp,则可以输出端口对应的队列情况

参考链接

https://blog.cloudflare.com/syn-packet-handling-in-the-wild/

proc(5) - Linux manual page

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值