找出重传较高的TCP连接

简介: 考虑一个场景:如果监控到一台主机的tcp重传率较高,如达到20%以上,且在这台主机系统上开了成百上千的tcp listen监听端口,同时间tcp连接并发高达数十万,此时如何得知哪些监听端口上重传较高? 哪些tcp连接在不断重传报文导致?可能的原因是什么?下边将解析这些问题。

原创文章:来自找出重传较高的TCP连接

这里先给出某一台主机上评估tcp重传的指标,TCP重传率定义:
TCP重传率 = TCP重传的报文数量/TCP输出的报文数量;
即tcp retransfer radio = Retrans/outSegs

在linux系统中可以通过/proc/net/snmp得到各层网络协议收发包的情况,另外一些扩展的tcp指标可以通过tcpext在/proc/net/netstat文件中读到。监控某台主机重传率的通常方法:可以每隔1秒从这两个文件中分别读到TcpRetransSegs和TcpOutSegs和上一次记录取差值后,再使用重传率计算公式。

简单的观察方法在centos 7等3.10内核中可以使用以下命令实时观察系统中每秒tcp重传报文数量:


watch -n 1 'nstat -z -t 1 | grep -e TcpExtTCPSynRetrans -e TcpRetransSegs -e TcpOutSegs -e TcpInSegs'

其中TcpExtTCPSynRetrans代表syn报文和synack报文的重传数量,TcpRetransSegs代表总的重传数量,TcpOutSegs代表总的tcp报文发出数量,TcpInSeg代表总的入报文数量通常用于计算tcp吞吐量。
备注:TcpExtTCPSynRetrans是centos 7系统(与linux内核有关)中新加入的,在2.6.32等系统内核中没有这个参数。

下边考虑一个场景:如果监控到一台主机的tcp重传率较高,如达到20%以上,且在这台主机系统上开了成百上千的tcp listen监听端口,同时间tcp连接并发高达数十万,此时如何得知哪些监听端口上重传较高? 哪些tcp连接在不断重传报文导致?可能的原因是什么?下边将解析这些问题。

方法1,如果观察到重传率较高时可以通过tcpdump或wireshark抓包,将主机中这段时间的所有tcp报文都抓下来保存为文件,再通过wireshark专家系统进行分析得到重传率较高的连接。wireshark通常过滤重传的命令是tcp.analysis.retransmission。

方法2,从内核统计重传根源处入手,使用systemtap下探点的方式拿到重传报文连接四元组信息。

如果对wireshark的统计与分析比较熟练使用方法1可以快速得到结果,但有兴趣探究内核tcp如何实现的话我选择使用方法2。下边的主要说明方法2。

找到TcpRetransSegs,TcpExtTCPSynRetrans两个参数在linux 3.10内核代码中的位置如下:
netipv4tcp_output.c

_

int __tcp_retransmit_skb(struct sock sk, struct sk_buff skb) 函数中也有一处:

2

编写打印出重传报文四元组信息简要的stap脚本如下:

#! /usr/bin/env stap
#
# fenghui8611@sina.com


#sudo stap -DSTP_NO_OVERLOAD -v -g retran_tcpseg.stp

probe begin {
      print ("\n")
}

#TCPHDR_SYN=0x02
function is_retran_syn:long (skb:long)
%{
    struct sk_buff *skb = (struct sk_buff *)STAP_ARG_skb;
    int ret = 0;

    if (((struct tcp_skb_cb *)&(skb->cb[0]))->tcp_flags & 0x02 )
        ret = 1;
     
     STAP_RETVALUE = ret;
%}     

probe kernel.statement("__tcp_retransmit_skb@net/ipv4/tcp_output.c:2554")
{
    printf("tcp_transmit_skb() err=%d, syn flag=%d ",  $err, is_retran_syn($skb))
    saddr   = format_ipaddr(__ip_sock_saddr($sk), __ip_sock_family($sk))
    daddr   = format_ipaddr(__ip_sock_daddr($sk), __ip_sock_family($sk))
    sport   = __tcp_sock_sport($sk)
    dport   = __tcp_sock_dport($sk) 
    
    printf("%s:%d => %s:%d\n", saddr, sport, daddr, dport)
}

probe kernel.function("tcp_v4_send_synack").return
{
   err = $return 
   if (err == 0) {
        saddr   = format_ipaddr(__ip_sock_saddr($sk), __ip_sock_family($sk))
        daddr   = format_ipaddr(__ip_sock_daddr($sk), __ip_sock_family($sk))
        sport   = __tcp_sock_sport($sk)
        dport   = __tcp_sock_dport($sk)

        printf("synack retran %s:%d => %s:%d\n", saddr, sport, daddr, dport) 
   }           
}

probe end {
      print ("\n")
 }

运行命令与输出信息示例:

 

sudo stap -DSTP_NO_OVERLOAD -v -g retran_tcpseg.stp

tcp_transmit_skb() err=0 syn flag=0 0.0.0.0:59738 => 100.116.2xx.16x:41239
tcp_transmit_skb() err=0 syn flag=0 0.0.0.0:59738 => 100.116.2xx.13x:44026
tcp_transmit_skb() err=0 syn flag=0 0.0.0.0:59738 => 100.116.2xx.13x:34901
tcp_transmit_skb() err=0 syn flag=0 0.0.0.0:59738 => 100.116.2xx.15x:11685

根据四元组信息可以深入的分析为什么这条连接有问题,是链路问题还是软件问题?比如拿到上述结果分析结论:因交换机出口处设置了带宽限制,当达到限制值时很多tcp 59738端口发出的tcp报文段被丢弃,导致此台主机重传较高;另外syn报文重传较高时可以重点分析服务器端tcp连接队列是否有问题等。

目录
相关文章
|
缓存 网络协议 网络架构
四十、TCP协议的特点、TCP报文段格式和TCP的连接管理
四十、TCP协议的特点、TCP报文段格式和TCP的连接管理
四十、TCP协议的特点、TCP报文段格式和TCP的连接管理
|
网络协议
计算机网络学习27:TCP连接与连接释放
客户端和服务端都是先建立传输控制模块
计算机网络学习27:TCP连接与连接释放
|
缓存 网络协议 Java
在项目中使用Curator的Java 客户端搭建后进行长TCP连接和TCP权限配置【Zookeeper】
在项目中使用Curator的Java 客户端搭建后进行长TCP连接和TCP权限配置【Zookeeper】
298 0
在项目中使用Curator的Java 客户端搭建后进行长TCP连接和TCP权限配置【Zookeeper】
|
网络协议
Netty之第一次 TCP 连接时发生了什么
Netty之第一次 TCP 连接时发生了什么
180 0
|
网络协议
|
Web App开发 网络协议 网络安全
89. 5 连问一个 TCP 连接可以发多少个 HTTP 请求
89. 5 连问一个 TCP 连接可以发多少个 HTTP 请求
135 0
89. 5 连问一个 TCP 连接可以发多少个 HTTP 请求
|
网络协议
TCP建立连接的三次握手
看了点网络的书,回顾下TCP的连接细节,记一下
208 0
TCP建立连接的三次握手
|
网络协议
Flutter TCP连接
Flutter TCP连接
|
网络协议 Java 数据库连接
mybatis学习(12)com.microsoft.sqlserver.jdbc.SQLServerException: 通过端口 1433 连接到主机 127.0.0.1 的 TCP/IP
mybatis学习(12)com.microsoft.sqlserver.jdbc.SQLServerException: 通过端口 1433 连接到主机 127.0.0.1 的 TCP/IP
268 0
mybatis学习(12)com.microsoft.sqlserver.jdbc.SQLServerException: 通过端口 1433 连接到主机 127.0.0.1 的 TCP/IP
|
缓存 网络协议 安全
《网络是怎么样连接的》读书笔记 - Tcp/IP连接(二)(下)
《网络是怎么样连接的》读书笔记 - Tcp/IP连接(二)(下)
157 0