精华内容
下载资源
问答
  • WIN2012 TCP ECN 启用导致速度慢
    2021-08-13 07:09:51

    测试偶尔访问指定网站速度慢的原因

    1 现象 某业务在客户服务器上,开发人员反映周期性速度慢,开发人员反馈,由于需要到xxx.com去取数据,慢的原因是取数据慢

    直接访问该站点下载文件发下下载速度很快

    2 测试脚本如下

    3 测试结果发现 是每次第一次访问xxx.com的时候的 建立连接的时间很慢,需要9秒以上

    4 最终原因 操作系统启用了TCP ECN,而目的地路由器未使用ECN 导致TCP握手时间延长

    netsh interface tcp set global ecncapability=disabled 关闭后正常

    5 没有介绍TCP ECN 只是介绍如何发现问题原因

    #!/bin/env python

    # -*- coding: utf-8-*-

    #author: skybug

    #date: 2017-12-2

    #web_perf_test

    import urllib2,sys,pycurl,json,StringIO

    import os,subprocess

    import platform,_winreg

    #ipvip = socket.gethostbyname ("www.xxx.com")#获取DNS解析值 本次未用

    reload(sys)

    sys.setdefaultencoding('utf-8')

    iplist = ["113.x.x.1","113.x.x.x","x.x.x.x","x.x.x.x","x.x.x.x"]#vipgate,vip,cnki,cnki2,chaoxing

    urllist=["http://x.com","http://a.com"]

    UA = "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Mobile Safari/537.36"

    headers = {}

    def header_function(header_line): #获取响应头,本次未调用

    header_line = header_line.decode('iso-8859-1')

    if ':' not in header_line:

    return

    name, value = header_line.split(':', 1)

    name = name.strip()

    value = value.strip()

    name = name.lower()

    headers[name] = value

    def webperf_keep(url,times=1): #获取访问页面的性能数据

    b = StringIO.StringIO() #定义个IO流

    pc=pycurl.Curl()#创建pycurl对象

    cnt=0

    alldata=[]

    for i in range(int(times)):

    pc.setopt(pycurl.URL,url) #设置访问url

    pc.setopt(pycurl.HTTPHEADER, ['Content-Type: application/json'])

    pc.setopt (pycurl.USERAGENT,UA)#设置UA

    pc.setopt(pycurl.MAXREDIRS,50) #MAX REDIRECT count#设置最大重定向次数

    pc.setopt(pycurl.WRITEFUNCTION, b.write)#把相应内容写到流里

    pc.setopt( pycurl.FOLLOWLOCATION,1)#跟踪重定向

    pc.setopt(pycurl.FORBID_REUSE, 0)#允许复用连接

    pc.setopt(pycurl.FRESH_CONNECT,0)

    pc.setopt (pycurl.HEADERFUNCTION, header_function)#把头信息写到头函数里

    print "testing access {0} {1} times.....".format (url, cnt)

    pc.perform()#执行pycurl

    cnt+=1

    dns_time = pc.getinfo(pycurl.NAMELOOKUP_TIME)#dns解析时间

    conn_time = pc.getinfo(pycurl.CONNECT_TIME)#建立连接的时间(TCP握手)

    ttfb = pc.getinfo(pycurl.STARTTRANSFER_TIME)#TTFB的时间

    total_time = pc.getinfo(pycurl.TOTAL_TIME)#总时间

    http_code = pc.getinfo(pycurl.HTTP_CODE)#返回code

    http_conn_code= pc.getinfo(pycurl.HTTP_CONNECTCODE)#

    redirect_count = pc.getinfo(pycurl.REDIRECT_COUNT)#重定向次数

    size_upload = pc.getinfo(pycurl.SIZE_UPLOAD)

    size_download = pc.getinfo(pycurl.SIZE_DOWNLOAD)

    size_header = pc.getinfo(pycurl.HEADER_SIZE)

    size_request = pc.getinfo(pycurl.REQUEST_SIZE)

    content_type = pc.getinfo(pycurl.CONTENT_TYPE)

    reponse_code = pc.getinfo(pycurl.RESPONSE_CODE)

    transfer_time = pc.getinfo(pycurl.PRETRANSFER_TIME) #传输时间

    startrans_time= pc.getinfo(pycurl.STARTTRANSFER_TIME)#开始传输时间

    speed_download = pc.getinfo(pycurl.SPEED_DOWNLOAD)#下载速度

    speed_upload = pc.getinfo(pycurl.SPEED_UPLOAD)#上传速度

    redirect_time = pc.getinfo(pycurl.REDIRECT_TIME)#重定向时间

    num_conn = pc.getinfo(pycurl.NUM_CONNECTS)#建立连接的次数

    last_socket= pc.getinfo(pycurl.LASTSOCKET)#最后一个socker

    data = []

    perfdata={"dns_time":dns_time,"ttfb":ttfb,"total_time":total_time,"http_code":http_code,"redirect_count":redirect_count

    ,"size_upload":size_upload,"size_download":size_download,"size_header":size_header,"size_request":size_request

    ,"content_type":content_type,"reponse_code":reponse_code,"conn_time":conn_time,"transfer_time":transfer_time,"speed_download":speed_download

    ,"speed_upload":speed_upload,"startrans_time":startrans_time,"redirect_time":redirect_time,"http_conn_code":http_conn_code,"num_conn":num_conn,"last_socket":last_socket}

    data.append(url)

    data.append(perfdata)

    alldata.append(cnt)

    alldata.append(data)

    #pc.close()

    #b.close()

    jsondata=json.dumps({"perfdata":alldata},indent=4)

    pc.close()

    b.close()

    return jsondata

    def getos():#获取操作系统版本

    os = {}

    if sys.platform == "win32":

    try:

    reg_key = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion")

    if reg_key:

    ProductName = _winreg.QueryValueEx(reg_key, "ProductName")[0] or None

    EditionId = _winreg.QueryValueEx(reg_key, "EditionId")[0] or None

    ReleaseId = _winreg.QueryValueEx(reg_key, "ReleaseId")[0] or None

    CurrentBuild = _winreg.QueryValueEx(reg_key, "CurrentBuild")[0] or None

    BuildLabEx = _winreg.QueryValueEx(reg_key, "BuildLabEx")[0][:9] or None

    os = {"ProductName": ProductName, "EditionId": EditionId, "ReleaseId": ReleaseId,

    "CurrentBuild": CurrentBuild, "BuildLabEx": BuildLabEx}

    jsondata = json.dumps({"OS": os}, indent=4)

    return jsondata

    except Exception as e:

    print e.message.decode(DEFAULT_LOCALE_ENCODING)

    def getcmd(shell):#执行cmd

    ps = subprocess.Popen(shell, shell=True, stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.PIPE)

    out, err = ps.communicate()

    return out.decode('cp936').encode('utf-8')

    def writelog(str):

    with open("result.txt",'a+') as fr:

    fr.write(str)

    fr.write("################################")

    if len(sys.argv) ==2 and sys.argv[1] == "full":

    cnt = 0

    print "test setp {0},Collect routing information....".format(cnt)

    cmd="route print "

    writelog(getcmd(cmd))#获取路由表

    print "test setp {0} ,Collect routing information....OK".format(cnt)

    cnt = cnt+1

    print "test setp {0},Collecting network information....".format(cnt)

    cmd="ipconfig /all "#获取网卡配置

    writelog(getcmd(cmd))

    print "test setp {0},Collecting network information....OK".format(cnt)

    cnt = cnt+1

    print "test setp{0},Collecting TCP information....".format(cnt)

    cmd = "netsh int tcp show global"#获取TCP全局配置

    writelog(getcmd(cmd))

    print "test setp{0},Collecting TCP information....OK".format(cnt)

    cnt=+1

    print "test setp{0},Collecting OS information....".format(cnt)

    writelog(getos())#获取操作系统版本

    print "test setp{0},Collecting OS information....OK".format(cnt)

    for index,item in enumerate(iplist):

    cmd="tracert "+item#获取路由跟踪

    print "test setp {0},Collecting route tracking information....".format(cnt)

    writelog(getcmd(cmd))

    print "test setp {0},Collecting route tracking information....OK".format(cnt)

    cnt=cnt+1

    for index,item in enumerate(urllist):

    print "test setp {0},Collecting web to access information data....".format(cnt)

    writelog(webperf_keep(item))

    print "test setp {0},Collecting web to access information data....OK".format(cnt)

    cnt=cnt+1

    print "All test data collection is completed!"

    if len(sys.argv) ==3:

    url = sys.argv[1]

    times = sys.argv[2]

    print "pre test access {0} {1} times.....".format(url,times)

    writelog(webperf_keep(url,times))

    if len(sys.argv)==1:

    print "Please run web.perf.test full to full test \nor run web.perf.test 'http://www.xxx.com/' 10 ro run 10 times access test"

    更多相关内容
  • 2012关闭ECN

    2017-09-07 09:52:00
    Windows Server 2012 关闭TCP ECN (2014-03-20 18:22:42) 转载 ▼ 标签: it 分类: windows 转载于:https://www.cnblogs.com/gaoyuechen/p/7488200.html

    Windows Server 2012 关闭TCP ECN

    (2014-03-20 18:22:42)
    标签:

    it

    分类: windows
    Windows <wbr>Server <wbr>2012 <wbr>关闭TCP <wbr>ECN
    Windows <wbr>Server <wbr>2012 <wbr>关闭TCP <wbr>ECN

    转载于:https://www.cnblogs.com/gaoyuechen/p/7488200.html

    展开全文
  • H85-SVP-06-03AX_ECN_M076.zip

    2020-11-09 10:19:29
    windows平台下可视化服务器管理软件,通过简单配置以后即可对服务器进行监控以及管理。此链接为第四部分。
  • H85-SVP-06-03AX_ECN_M076.z01

    2020-11-07 11:54:16
    windows平台下可视化服务器管理软件,通过简单配置以后即可对服务器进行监控以及管理。此链接为第一部分。
  • H85-SVP-06-03AX_ECN_M076.z03

    2020-11-07 19:09:58
    windows平台下可视化服务器管理软件,通过简单配置以后即可对服务器进行监控以及管理。此链接为第三部分。
  • H85-SVP-06-03AX_ECN_M076.z02

    2020-11-07 12:57:45
    windows平台下可视化服务器管理软件,通过简单配置以后即可对服务器进行监控以及管理。此链接为第二部分。
  • 1 ECN简介 首先看看ECN握手报文的特点,根据RFC3168,ECN握手报文IP头部不能够设置ECT和CE位的 SYN报文TCP标志字段的CWR和ECE位被置1 ...服务器端在接收到有CE标志的报文后,立即构造带有ECE标志的...

    1 ECN简介

    首先看看ECN握手报文的特点,根据RFC3168,ECN握手报文IP头部不能够设置ECT和CE位的

    SYN报文TCP标志字段的CWR和ECE位被置1

     

    SYN-ACK报文的CWR位被置0,ECE位被置1

    报文在网络上传输的过程中,如果路由器判断自身发生拥塞则在报文的IP首部设置CE标志

    服务器端在接收到有CE标志的报文后,立即构造带有ECE标志的ACK报文,服务器端在接收到该ACK报文后进入TCP_CA_CWR状态,在该状态下发送窗口每两个ACK减1。

     发生拥塞之前的报文都被确认后,客户端会走出TCP_CA_CWR状态,转入TCP_CA_Open状态,重新开始拥塞避免,并向服务端发送CWR标志,终止服务端向客户端发送ECE报文。

     

    2 ECN在Linux上的实现

    以下所有分析基于Linux内核3.16.38

    Linux内核通过调整tcp_sock结构体的ecn_flags来标识ECN所处的状态,在文件include/net/tcp.h, line 393内,Linux定义了ECN可能的4种状态,本文将通过这4中状态的转化把ECN从协议栈中肢解出来。

    393 #define TCP_ECN_OK              1  //套接字支持ECN协议
    394 #define TCP_ECN_QUEUE_CWR       2  //发送端在接收到ECE报文后,设置该标志,并将拥塞状态机设置为TCP_CA_CWR状态
    395 #define TCP_ECN_DEMAND_CWR      4  //接收端处于该状态,将在所有ACK报文中添加ECE,直到接收到CWR报文
    396 #define TCP_ECN_SEEN            8  //是否接收到过ECT报文

    2.1 实现握手

    STEP1 :客户端发送SYN,用户态程序调用connect后,内核态通过tcp_connect构造SYN报文,tcp_connect会调用TCP_ECN_send_syn函数,该函数通过系统配置sysctl_tcp_ecn判断是否启用了ECN协议,如果启用了ECN协议,则在SYN报文中添加ECE和CWR标志,并临时设置该套接字为TCP_ECN_OK,这里说临时的原因为在ECN握手失败后,该标志还可能被取消。

    3046 /* Build a SYN and send it off. */
    3047 int tcp_connect(struct sock *sk)
    3048 {
            ...
    3070         TCP_ECN_send_syn(sk, buff);
    3071 
            ...
    3089 }

     

    328 /* Packet ECN state for a SYN.  */
    329 static inline void TCP_ECN_send_syn(struct sock *sk, struct sk_buff *skb)
    330 {
    331         struct tcp_sock *tp = tcp_sk(sk);
    332 
    333         tp->ecn_flags = 0;
    334         if (sock_net(sk)->ipv4.sysctl_tcp_ecn == 1) {              //通过 /proc/sys/net/ipv4/tcp_ecn进行配置
    335                 TCP_SKB_CB(skb)->tcp_flags |= TCPHDR_ECE | TCPHDR_CWR;    //SYN报文需要添加ECE和CWR
    336                 tp->ecn_flags = TCP_ECN_OK;                    //握手阶段ecn_flags设为支持ECN通信,如果握手失败TCP_ECN_OK会被取消
    337         }
    338 }

    STEP2 :服务端处理SYN, tcp_rcv_state_process函数是接收数据时TCP层上的必经之路,它会根据报文类型调用不同函数来处理,所有握手报文都会交给tcp_v4_conn_request,而tcp_v4_conn_request又会调用TCP_ECN_create_request进行ECN-SYN报文,当SYN报文符合ECN-SYN标准时,套接字添加支持ECN标识。

     
     
      
    5611 int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
    5612                       const struct tcphdr *th, unsigned int len) 
    5613 {
            ...
    5623 switch (sk->sk_state) { 5624 case TCP_CLOSE: 5625 goto discard; 5626 5627 case TCP_LISTEN: 5628 if (th->ack) 5629 return 1; 5630 5631 if (th->rst) 5632 goto discard; 5633 5634 if (th->syn) { 5635 if (th->fin) 5636 goto discard; 5637 if (icsk->icsk_af_ops->conn_request(sk, skb) < 0)    //调用tcp_v4_conn_request
    5638 return 1; 5639 5657 kfree_skb(skb); 5658 return 0; 5659 } 5660 goto discard; 5661
                ...
    5662         case TCP_SYN_SENT:
    5663                 queued = tcp_rcv_synsent_state_process(sk, skb, th, len);
    5672         }
    1257 int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
    1258 {
            ...
    1326         if (!want_cookie || tmp_opt.tstamp_ok)
    1327                 TCP_ECN_create_request(req, skb, sock_net(sk));
            ...1398 }
    737 static inline void
    738 TCP_ECN_create_request(struct request_sock *req, const struct sk_buff *skb,
    739                 struct net *net)
    740 {
    741         const struct tcphdr *th = tcp_hdr(skb);
    742 
    743         if (net->ipv4.sysctl_tcp_ecn && th->ece && th->cwr &&        //服务端也配置了ECN,同时SYN报文中函授ECE和CWR
    744             INET_ECN_is_not_ect(TCP_SKB_CB(skb)->ip_dsfield))
    745                 inet_rsk(req)->ecn_ok = 1;                   //套接字设置支持ECN标识 
    746 }

     STEP3 :客户端处理SYN-ACK报文,首先调用tcp_rcv_synsent_state_process,继而调用TCP_ECN_rcv_synack来完成ECN握手。

    5611 int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
    5612                       const struct tcphdr *th, unsigned int len) 
    5613 {
    
            ...
    5662         case TCP_SYN_SENT:
    5663                 queued = tcp_rcv_synsent_state_process(sk, skb, th, len);
    5672         }
            ...
    5672 } 
    5384 static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb,
    5385                                          const struct tcphdr *th, unsigned int len)
    5386 {
                ...
    5446                 TCP_ECN_rcv_synack(tp, th);
                ...5602 }
    246 static inline void TCP_ECN_rcv_synack(struct tcp_sock *tp, const struct tcphdr *th)
    247 {
    248         if ((tp->ecn_flags & TCP_ECN_OK) && (!th->ece || th->cwr))          //SYN-ACK报文含有CWR或不含ECE则握手失败,客户端撤销TCP_ECN_OK
    249                 tp->ecn_flags &= ~TCP_ECN_OK;
    250 }

    2.2 客户端发送带有ECT的报文

    所有支持ECN通信的流,在传输层 tcp_transmit_skb -> TCP_ECN_send -> INET_ECN_xmit的流程中都会打上ECT(0)标记。

    350 static inline void TCP_ECN_send(struct sock *sk, struct sk_buff *skb,
    351                                 int tcp_header_len)
    352 {
    353         struct tcp_sock *tp = tcp_sk(sk);
    354 
    355         if (tp->ecn_flags & TCP_ECN_OK) {      //ECN通信添加ECT
    356                 /* Not-retransmitted data segment: set ECT and inject CWR. */
    357                 if (skb->len != tcp_header_len &&
    358                     !before(TCP_SKB_CB(skb)->seq, tp->snd_nxt)) {
    359                         INET_ECN_xmit(sk);
    360                         if (tp->ecn_flags & TCP_ECN_QUEUE_CWR) {
    361                                 tp->ecn_flags &= ~TCP_ECN_QUEUE_CWR;
    362                                 tcp_hdr(skb)->cwr = 1;
    363                                 skb_shinfo(skb)->gso_type |= SKB_GSO_TCP_ECN;
    364                         }
    365                 } else {
    366                         /* ACK or retransmitted segment: clear ECT|CE */
    367                         INET_ECN_dontxmit(sk);
    368                 }
    369                 if (tp->ecn_flags & TCP_ECN_DEMAND_CWR)
    370                         tcp_hdr(skb)->ece = 1;
    371         }
    372 }
     51 static inline void INET_ECN_xmit(struct sock *sk)
     52 {
     53         inet_sk(sk)->tos |= INET_ECN_ECT_0;
     54         if (inet6_sk(sk) != NULL)
     55                 inet6_sk(sk)->tclass |= INET_ECN_ECT_0;
     56 }

    2.3 路由器处理ECT报文

    根据设计思路,路由器在认为发生拥塞时,给所有支持ECN协议的流打上CE标记,然而路由器如何判断拥塞发生并没有一个统一的标准,一般来说为平滑后的队列长度超过一定阈值,以RED队列为例,它维护一个队列长度的移动平均值,在该值大于设置的阈值,之后以一定概率给过往的报文打上CE标记(没有启用ECN时为以一定概率丢弃报文)。

     59 static int red_enqueue(struct sk_buff *skb, struct Qdisc *sch)
     60 {
            ...
     72         switch (red_action(&q->parms, &q->vars, q->vars.qavg)) {    //根据平均队列长度决定如何处理报文
     73         case RED_DONT_MARK:
     74                 break;
     75 
     76         case RED_PROB_MARK:                          //标记报文
     77                 sch->qstats.overlimits++;
     78                 if (!red_use_ecn(q) || !INET_ECN_set_ce(skb)) {     //没有启用ECN,或者打CE标记失败则丢弃报文
     79                         q->stats.prob_drop++;
     80                         goto congestion_drop;            
     81                 }
     82 
     83                 q->stats.prob_mark++;
     84                 break;
     85 
     86         case RED_HARD_MARK:
     87                 sch->qstats.overlimits++;
     88                 if (red_use_harddrop(q) || !red_use_ecn(q) ||
     89                     !INET_ECN_set_ce(skb)) {
     90                         q->stats.forced_drop++;
     91                         goto congestion_drop;
     92                 }
     93 
     94                 q->stats.forced_mark++;
     95                 break;
     96         }
            ...

    110 }

    2.4 服务器端处理CE报文

    服务器端在收到带有CE标志的IP报文后,将套接字结构体tp->ecn_flags置TCP_ECN_DEMAND_CWR,并进入quick ack模式,之后所有ack报文都置有ECE标志,直到接收端接收到CWR报文后,取消TCP_ECN_DEMAND_CWR。

    STEP1 : 转入TCP_ECN_DEMAND_CWR状态。具体流程为tcp_rcv_established -> tcp_event_data_recv -> TCP_ECN_check_ce,在TCP_ECN_check_ce中检查报文是否包含CE标记,在遇到CE标记时转入TCP_ECN_DEMAND_CWR状态。

    220 static inline void TCP_ECN_check_ce(struct tcp_sock *tp, const struct sk_buff *skb)
    221 {
    222         if (!(tp->ecn_flags & TCP_ECN_OK))
    223                 return;
    224 
    225         switch (TCP_SKB_CB(skb)->ip_dsfield & INET_ECN_MASK) {
    226         case INET_ECN_NOT_ECT:
    227                 /* Funny extension: if ECT is not set on a segment,
    228                  * and we already seen ECT on a previous segment,
    229                  * it is probably a retransmit.
    230                  */
    231                 if (tp->ecn_flags & TCP_ECN_SEEN)
    232                         tcp_enter_quickack_mode((struct sock *)tp);
    233                 break;
    234         case INET_ECN_CE:
    235                 if (!(tp->ecn_flags & TCP_ECN_DEMAND_CWR)) {
    236                         /* Better not delay acks, sender can have a very low cwnd */
    237                         tcp_enter_quickack_mode((struct sock *)tp);    //进入quick ack模式,立即构造ack报文
    238                         tp->ecn_flags |= TCP_ECN_DEMAND_CWR;        //在ecn_flags中添加TCP_ECN_DEMAND_CWR状态
    239                 }
    240                 /* fallinto */
    241         default:
    242                 tp->ecn_flags |= TCP_ECN_SEEN;
    243         }
    244 }

    STEP2 :构造ECE - ACK。在构造ACK报文时,tcp_transmit_skb 调用 TCP_ECN_send判断是否处于TCP_ECN_DEMAND_CWR状态,并决定是否在ACK报文中添加ECE标志。

    350 static inline void TCP_ECN_send(struct sock *sk, struct sk_buff *skb,
    351                                 int tcp_header_len)
    352 {
    353         struct tcp_sock *tp = tcp_sk(sk);
    354 
    355         if (tp->ecn_flags & TCP_ECN_OK) {
    356                 /* Not-retransmitted data segment: set ECT and inject CWR. */
    357                 if (skb->len != tcp_header_len &&
    358                     !before(TCP_SKB_CB(skb)->seq, tp->snd_nxt)) {
    359                         INET_ECN_xmit(sk);
    360                         if (tp->ecn_flags & TCP_ECN_QUEUE_CWR) {
    361                                 tp->ecn_flags &= ~TCP_ECN_QUEUE_CWR;
    362                                 tcp_hdr(skb)->cwr = 1;
    363                                 skb_shinfo(skb)->gso_type |= SKB_GSO_TCP_ECN;
    364                         }
    365                 } else {
    366                         /* ACK or retransmitted segment: clear ECT|CE */
    367                         INET_ECN_dontxmit(sk);
    368                 }
    369                 if (tp->ecn_flags & TCP_ECN_DEMAND_CWR)       //在CWR状态时,给ACK报文添加ece标志 
    370                         tcp_hdr(skb)->ece = 1;
    371         }
    372 }

    STEP3 :退出TCP_ECN_DEMAND_CWR状态。具体流程为tcp_rcv_established -> tcp_data_queue -> TCP_ECN_accept_cwr,在TCP_ECN_accept_cwr中,判断接收到的报文中是否有CWR标志,并决定是否退出TCP_ECN_DEMAND_CWR状态。

    209 static inline void TCP_ECN_accept_cwr(struct tcp_sock *tp, const struct sk_buff *skb)
    210 {
    211         if (tcp_hdr(skb)->cwr)  //退出TCP_ECN_DEMAND_CWR状态
    212                 tp->ecn_flags &= ~TCP_ECN_DEMAND_CWR;
    213 }

    2.5 客户端处理ECE报文

    客户端首先要根据ACK报文中的ECE调整TCP拥塞状态机到TCP_CA_CWR状态,并开始减小发送窗口,在拥塞发生之前的所有报文都被确认后,恢复TCP_CA_Open状态,并向服务器端发送CWR终止服务器端的TCP_ECN_DEMAND_CWR,结束整个流程。

    STEP1 :处理ACK报文,并确定是否包含ECE标志,流程为tcp_rcv_established -> tcp_ack 。

     

    3360 static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
    3361 {
            ...
    3407         if (!(flag & FLAG_SLOWPATH) && after(ack, prior_snd_una)) {
              ...
    3419 } else { 3420 if (ack_seq != TCP_SKB_CB(skb)->end_seq) 3421 flag |= FLAG_DATA; 3422 else 3423 NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPPUREACKS); 3424 3425 flag |= tcp_ack_update_window(sk, skb, ack, ack_seq); 3426 3427 if (TCP_SKB_CB(skb)->sacked) 3428 flag |= tcp_sacktag_write_queue(sk, skb, prior_snd_una, 3429 &sack_rtt_us); 3430 3431 if (TCP_ECN_rcv_ecn_echo(tp, tcp_hdr(skb)))  //确定ACK报文是否含有ECE标志 3432 flag |= FLAG_ECE;         3433 3434 tcp_ca_event(sk, CA_EVENT_SLOW_ACK); 3435 }
            ...
    3508 }

     STEP2 : 调整拥塞控制状态机。具体流程为tcp_rcv_established -> tcp_ack -> tcp_fastretrans_alert -> tcp_try_to_open,其中tcp_fastretrans_alert 函数为整个TCP拥塞控制状态机的核心,而tcp_try_to_open函数则根据flag中是否包含FLAG_ECE标志,确定是否将拥塞状态机调整为TCP_CA_CWR状态。拥塞控制状态机进入TCP_CA_CWR状态后,协议栈需要调用tcp_enter_cwr函数来保存当前snd_nxt等重要的变量,之后发送窗口大致为每两个ack减1。

    2557 static void tcp_try_to_open(struct sock *sk, int flag, const int prior_unsacked)
    2558 {
    2559         struct tcp_sock *tp = tcp_sk(sk);
    2560 
    2561         tcp_verify_left_out(tp);
    2562 
    2563         if (!tcp_any_retrans_done(sk))
    2564                 tp->retrans_stamp = 0;
    2565 
    2566         if (flag & FLAG_ECE)        //将拥塞控制状态机从OPEN或REORDER状态调整为CWR状态
    2567                 tcp_enter_cwr(sk, 1);
    2568 
    2569         if (inet_csk(sk)->icsk_ca_state != TCP_CA_CWR) {
    2570                 tcp_try_keep_open(sk);
    2571         } else {
    2572                 tcp_cwnd_reduction(sk, prior_unsacked, 0);
    2573         }
    2574 }

    STEP3 : 退出CWR状态。上面介绍过Linux的拥塞控制状态机主要由tcp_fastretrans_alert 控制,在STEP2中记录的snd_nxt之前的报文都被确认后,拥塞状态机也将退出TCP_CA_CWR状态,并转入TCP_CA_Open状态。

    2774 static void tcp_fastretrans_alert(struct sock *sk, const int acked,
    2775                                   const int prior_unsacked,
    2776                                   bool is_dupack, int flag)
    2777 {
            ...
    2801         /* D. Check state exit conditions. State can be terminated
    2802          *    when high_seq is ACKed. */
    2803         if (icsk->icsk_ca_state == TCP_CA_Open) {
    2804                 WARN_ON(tp->retrans_out != 0);
    2805                 tp->retrans_stamp = 0;
    2806         } else if (!before(tp->snd_una, tp->high_seq)) {
    2807                 switch (icsk->icsk_ca_state) {
    2808                 case TCP_CA_CWR:
    2809                         /* CWR is to be held something *above* high_seq
    2810                          * is ACKed for CWR bit to reach receiver. */
    2811                         if (tp->snd_una != tp->high_seq) {      //退出TCP_CA_Cwr
    2812                                 tcp_end_cwnd_reduction(sk);
    2813                                 tcp_set_ca_state(sk, TCP_CA_Open);
    2814                         }
    2815                         break;
    2816 
                    ...
    2824 } 2825 }
            ...
    2886 }

    转载于:https://www.cnblogs.com/codingMozart/p/6389165.html

    展开全文
  • PFC 和 ECN PFC是一种基于队列的反压协议,在单机场景下,PFC可以快速、有效的调节服务器速率来保证网络不丢包,但是在多级网络中,就会出现不公平降速、PFC风暴、死锁等问题,而且当有异常服务器向网络中注入PFC...

    原文:https://www.sohu.com/a/190664909_210640   

    配合这个PDF阅读:https://mentor.ieee.org/802.1/dcn/17/1-17-0008-02-ICne-baidu-s-best-practice-with-low-latency-networks.pdf

    报告人:高峰

    低时延网络的实践:

    第一是低时延网络解决方案,会介绍百度在低时延网络解决方案设计过程中如何思考的

    第二是低时延网络技术展望,会介绍低时延网络技术研究方向

    第三是总结。

    以前数据中心:

    追求大带宽,无阻塞 。

    现在数据中心:

    追求低时延、无丢包。

    网络时延组成5部分:光电传输时延、数据串行时延、设备转发时延、重新排队时延、主机处理时延。

    光电传播时延:是固定值,没办法改变

    数据串行时延和设备转发时延:主要是取决于芯片技术的发展

    我们聚焦的重点是重新排队时延和主机处理时延,通过主机端加速技术,可以减小主机处理时延,我们选择的方向是RDMA和RoCE,主要考虑成本和技术成熟度,另外随着100G技术的成熟,RoCE的优势越来越明显,网络侧我们选择的方向是DCB和ECN,通过流控技术,避免网络拥塞造成的业务丢包。

    主机端的加速,我们是RDMA和RoCE,RDMA性能方面有两个方面,RDMA的性能优势主要体现在以下几个方面:

    1.Zerocopy:减少数据拷贝次数,由于没有将数据拷贝到内核态,传输延迟会显著提高,

    2、Kernelbypass&Protocoloffload:不需要内核参与,数据通路中没有繁琐的处理报头逻辑,不仅会使延迟降低,而且也大大节省了CPU的资源。

    RDMA和TCP相比,性能提升比较明显,但是数据包大小,以及业务模型不同情况下,提升的效果也不同。我们在语音识别训练提速2倍,在机器翻译训练提速15倍。

    RoCE是RDMA承载协议,RoCE和Infiniband的性能基本相近,而且比iWARP产业生态更加健全,主流网卡厂商都已支持。除此之外,RoCE网络在数据链路层支持标准以太网协议,在网络层上支持IP协议,因此可以无缝融合到现有的数据中心网络中,部署和运维更加方便,而且设备成本更低。

    以太网为何容易丢包

    以太网采用的是尽力而为的转发方式,每个网络设备都会尽力的把数据转发给下游的设备。当下游设备处理能力不足的时候,网络就会出现拥塞或者丢包,所以网络本身是不可靠的,无论是TCP或者RDMA协议,网络拥塞和丢包重传都会让业务性能受到影响,尤其是RDMA协议对网络丢包的容忍度更低。如何减少或者避免网络拥塞和丢包,现在通用的解决方案是PFC和ECN的流控技术。

    PFC 和 ECN

    PFC是一种基于队列的反压协议,在单机场景下,PFC可以快速、有效的调节服务器速率来保证网络不丢包,但是在多级网络中,就会出现不公平降速PFC风暴死锁等问题,而且当有异常服务器向网络中注入PFC报文时,还可能造成整个网络瘫痪,因此,在数据中心开启PFC,需要通过对Pause帧进行严格的监控、管理,以保证网络的可靠性。

    ECN是一种基于流的端到端流控技术,效果上会优于PFC,但是也不是很理想,主要有几个问题:

    1、ECN缺点是需要网卡侧生成反压报文,反馈路径周期比较长。

    2、随机性标记,会不公平。

    3、水线设计比较复杂,这也是现阶段ECN方案的最大挑战,因为水线不是一个固定值,要结合网络架构和业务特点来设计。

    4、目前各个网卡厂商拥塞算法不一致。虽然方案不理想,但是目前也没有更好的选择。

    从解决方案设计上面来说,ECN和PFC组合配置,针对PFC固有的缺陷问题,可以通过优先触发ECN报文,用来减少网络中PFC的数量,在PFC生效前完成流量的降速

    避免触发流控机制+加速比

    (PFC流控,但是拥塞发生后触发的。那要在拥塞之前就接入,避免发生拥塞:ECN)

    依靠有效流控机制只能是减少网络拥塞和丢包的发生,网络是共享资源,面对多个业务并发流量导致拥塞的问题,是很难避免的。高效的网络一定是避免触发流控机制,那么在组网架构方面也要同步思考这个问题,比较有效的办法是用带宽来换时间,为服务器提供端到端的线速转发能力。下面介绍一下网络架构设计过程中要关注什么,在低时延网络架构设计中最关键的指标是加速比,加速比越大,网络拥塞越少,时延越低。目前我们的网络架构设计是1:1加速比,下一代新架构会提升加速比到4:3以上,主要来避免fabric内部拥塞和丢包问题,加速比提升会让网络性能提升,新架构在性能提升的同时,也要付出更高的组网成本。

    (加速比:http://blog.chinaunix.net/uid-26893610-id-3769239.html ?、http://net.zhiding.cn/network_security_zone/2008/0925/1152705.shtml ?)

    下面分享一下在整个设计过程中的思考。在整个低时延网络解决方案中有两个选择:

    第一个是单独部署PFC,

    第二个就是PFC和ECN的结合。

    结果很明显:

    1、ECN+PFC的方式优于单独部署PFC.

    2、加速比是很关键的指标,决定了我们的效率,加速比越高,网络优势就越明显。

    3、就是水线的设计,PFC的水线越大,ECN的水线要适合网络模型。

    下面分享一下我们在方案设计过程中的一些分析,有两种技术方案选择,

    第一种是单独部署PFC

    第二种是PFC+ECN组合

    我们分别在加速比1:1和加速比4:3环境下,以及在不同的带宽利用率下面测试,分别是50%、75%、100%利用率。

    结果很明显:

    1、ECN+PFC优于单独部署PFC,而且在各种利用率情况下均有优势。

    2、加速比是关键指标,加速比决定网络效率,越高,优势越明显。

    3、水线设计一定要合理,PFC水线的设置只要满足HEADROOM,越大越好,ECN水线的设置需要视不同流量模型而定。

    PFC+ECN VS 新方案

    这个分享是PFC+ECN和新方案的对比,新方案是我们在探索的一个方向,就是在tor下行端口单独部署ECN,这个方案需要两个前提条件,ECN控制环不失效,fabirc内部不能丢包,提高加速比来解决fabric内部丢包问题,从结果上看会优于PFC+ECN的方案,但是如果fabric内部无法保证不丢包,在仅部署ECN时,丢包率非常高,100%利用率时,丢包率高达5%以上,影响会非常严重,稳妥一些还是PFC+ECN的组合方案比较好。提高加速比可以缓解Fabric内部端口的拥塞,仍然存在流量不均导致丢包的可能,也要配合一种理想的负载均衡方案。

    对未来的技术展望

    以上是百度在低时延网络解决方案上面的思考,下面是我们对未来的技术展望。我们

    希望从四个方面进行深度的优化,控制面、数据面、管理面、功能强化。

    控制面-优化反馈机制,目前拥塞反馈信息比较单一,反馈内容很少,由于是网卡做拥塞通知,反馈路径周期太长,控制面数据未高优保障。需要优化通知消息,引入更多级别的拥塞通知机制,包括拥塞程度等信息,通过多种方式提速,比如交换机设备直接反馈拥塞通知,缩短反馈路径,确保控制面消息在网络传递过程中不被丢弃,同时由交换机来触发丢包重传。

    数据面-多路径负载均衡,当前多路径下多采用基于流的哈希算法,实现数据在不同链路上调度,大象流叠加容易造成流量不均,在特定路径的拥塞。如前面解决方案中介绍,fabric内部的负载均衡很重要,需要从负载均衡算法方面进行优化,例如:基于成员接口历史负载情况,选择空闲链路。把出接口队列长度作为流量均衡的hash因子。切割大象流,把一条流切分为多组,调度到不同路径,且保证不乱序。从这三个方面协作处理,实现完美的负载均衡调度

    管理面-自适应网络。低时延网络对运维的管理自动化提出更多的要求,相对于低时延网络在丢包、性能方面提出更高的要求,网络运维管理要屏蔽网络环境变化对性能的影响,确保配置永远是最优的。要达到自适应的网络效果,我们认为应该建立分析。第一点是业务的探索和发现,我们要构建自己业务测量的能力,把业务沿途网络节点转发信息进行记录和提取,第二点是计算和特征分析,根据现网实时数据和业务特征,计算出最优的水线阈值和最优策略。第三点是下发和持续的优化。根据业务流量特点,自动配置并动态调整参数,自动下发给服务器和网络设备,实现自适应网络配置。

    功能强化-队列优化,数据中心内流量特征有两种,大象流和老鼠流,大象流对时延不敏感,丢包对整体性能影响较小,但是占据了80%的流量,网络拥塞期间,很容易把交换机的队列占满,时延敏感的业务流量被饿死,需要从交换机队列层面优化,将大象流隔离到单独的队列中,为老鼠流预留足够的buffer,以及单独的队列设计,实现设备层面的低时延转发。

    以上技术分享就结束了。在低时延网络里面业界也关注很多,也有很多相应的技术,由于时间关系就分享这么多。总结一下今天我的分享。共4个部分,第一部分是业务定位,低时延网络在百度来说主要是面向百度云和人工智能的内生需求,我们分别部署了25G、40G、100G的低时延网络,用来支撑业务需求。从网络定位上面,我们配合整体的网络布局,实现局部的加速的能力。第三点是产品定位,目前低时延网络中仍然有很多问题和挑战,技术的优化空间还很大,在未来也希望跟厂商共同的去探索。第四点是架构演进定位,向大规模网络架构探索,随着技术发展,逐步优化迭代。

    大象流和老鼠流

    主要是通过流的大小和速率区分。

    大象流:大速率,长时的流就是elephant flow,如:虚机的迁移,数据的迁移,MapReduce

    老鼠流:小速率,短时的就是mouse flow,如:发邮件,看网页,聊微信

    多说一点,因为 per flow的哈希肯定是不精确的,所以elephant flow会影响到mouse flow。虽然 per packet能解决问题,但使用同时也有乱序的可能。所以,可以通过使用segment routing的flowlets来彻底解决这个问题。
    链接:https://www.zhihu.com/question/50171430/answer/470878604

              https://www.zhihu.com/question/50171430

    自适应地隔离大象流和老鼠流在不同的路径上传输:https://blog.csdn.net/qq_36028921/article/details/85012707

    @UESTC

    展开全文
  • 在部署服务测试的时候,内网服务器访问dmz服务器telnet很慢。经过多台测试发现有的访问快,有的访问慢,然后尝试在dmz防火墙加白名单后,都很快。对比和分析数据包后得出结论: 访问该目的服务的25邮件服务的端口,...
  • 目录 前言 一、为什么会产生拥塞 二、PFC如何实现流控 三、PFC存在的问题 四、利用ECN实现端到端的拥塞控制 五、ECN交互过程 QC-QCN (网络工程师必会) (待续) PFC和ECN对比* 总结 PFC的水线设置 无损网络测试...
  • 在WIN2012R2和WIN2016服务器中访问网站或网页需要等待加载N秒才显示解决步骤:1、执行netsh int tcp show global查看默认TCP全局参数等相关设置“ECN功能”后面的参数是否为disabled如果不是,请关闭ECN:netsh int ...
  • ECN与ECO工程变更操作

    千次阅读 2018-07-04 19:20:10
    丽姐的方法:首先将脚本copy到建模器运行的workspace的default下面,然后建模器重新加载模型,最后重新部署到服务器。 然后在服务器的conf下面的脚本中也加上对应的脚本。 综上,我觉得只需要在我的代码运行的服务器...
  • 一、syslog服务器配置首先,配置Red Hat上自带的syslog服务,使它能够记录来自其他服务器的log信息。1、编辑/etc/sysconfig/syslog文件,修改SYSLOGD_OPTIONS选项,如下:# Options to syslogd# -m 0 disables 'MARK...
  • ·在交换机连接服务器的接口上使能DCBX,以便交换机和服务器网卡协商ETS和PFC参数。 ·配置 ETS 以保证设备 A 的 25-5GigE 1/0/3 和设备 B 的 25-5GigE 1/0/2 上的 802.1p 优先级为 5 的数据包的带宽。 ·在Device ...
  • 如何查看线上服务器日志

    万次阅读 多人点赞 2019-03-10 15:46:09
    Xshell可以在Windows界面下用来访问远端不同系统下的服务器,从而比较好的达到远程控制终端的目的。打开软件之后,点击左上角文件里的新建。 填上服务所部署的那台服务器的地址和端口号 ...
  • 转自http://blog.2forex.cn/sy_binbin/2569.html常见交易商服务器ip地址汇总:诺德外汇nordfxNordGroupInv-Demo78.140.130.82:443NordGroupInv-Real178.140.165.83:443NordGroupInv-Real278.140.166.246:443...
  • 常见交易商服务器ip地址汇总:诺德外汇nordfxNordGroupInv-Demo78.140.130.82:443NordGroupInv-Real178.140.165.83:443NordGroupInv-Real278.140.166.246:443NordGroupInv-Real378.140.166.244:443NordGroupInv-Real...
  • 慢响应,ECN
  • 假设iperf服务端为主机tian04,使用TCP协议,那么在控制台执行以下两个命令开启服务器进程。 iperf-s -p 12000 -i1 iperf-s -p 12001 -i1 假设iperf客户端为主机tian05,tian06。注意,与1G的实验环境使用的命令不同...
  • 如果您的服务器是Windows Server2012版本(其他 Windows Server版本也可尝试) 请在服务器上执行以下命令:netsh interface tcp show global 检查[ECN 功能]是否为“enable”,如果为“enable”请执行命令: netsh int ...
  • 服务器TCP优化1

    2019-11-09 23:58:27
    ECN 功能:netsh int tcp set global ecncapability=disabled RFC 1323 时间戳:netsh int tcp set global timestamps=enabled 再加一条优化网卡缓存配合使用 网上流传的 在“运行”对话框中输入“MSINFO32....
  • 1、 time_wait的作用:TIME_WAIT状态存在的理由:1)可靠地实现TCP全双工连接的终止在进行关闭连接四次挥手协议时,最后的ACK是由主动关闭端发出的,如果这个最终的ACK丢失,服务器将重发最终的FIN,因此客户端必须...
  • 3 配置windows服务器,使其发送日志到日志服务器。需要安装一个第三方软件,名字叫eventsys,用于转发日志到linux系统的syslog日志服务程序。下载地址为:...
  • net.ipv4.tcp_ecn = 0 #把TCP的直接拥塞通告(tcp_ecn)关掉 net.ipv4.tcp_sack = 1 #关闭tcp_sack #启用有选择的应答(Selective Acknowledgment), #这可以通过有选择地应答乱序接收到的报文来提高性能(这样可以...
  • 外汇经纪商平台的分类:  * MM,做市商模式,全称Market Maker;... * ECN,电子自动撮合成交模式,全称Electronic Communications Network;  * MTF,多边交易设备模式,全称Multilateral Trading F

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 3,142
精华内容 1,256
关键字:

服务器ecn