k8s网络诊断之被丢弃的SYN--linux数据包的接收过程(k8s+flannel+ ipvs)

本文涉及的产品
容器服务 Serverless 版 ACK Serverless,952元额度 多规格
容器服务 Serverless 版 ACK Serverless,317元额度 多规格
公网NAT网关,每月750个小时 15CU
简介: 某客户反馈,ECS上自建nginx server 通过proxy_pass 反向代理 云上k8s集群 nodeport类型的svc,存在大量1s的延迟请求的问题,在nginx所在的ecs上,使用netstat可以看到syn_sent状态的connection,如下图所示,但是在pod所在的worker节点上是看不到syn_RECV状态的connection(nodeport上也无)

背景信息:

         某客户反馈,ECS上自建nginx server 通过proxy_pass 反向代理 云上k8s集群 nodeport类型的svc,存在大量1s的延迟请求的问题,在nginx所在的ecs上,使用netstat可以看到syn_sent状态的connection,如下图所示,但是在pod所在的worker节点上是看不到syn_RECV状态的connection(nodeport上也无)

集群网络模式:        

     客户的k8s集群使用的网络模式是flannel+ipvs,这二者的组合我首先想到的是:

  • pod 具备自己的 cidr ,网络通过eth0转进相关的veth虚拟网卡再到pod里面
  • svc通过ipvs做转发,过ipvs会被fnat转换


flannel图示(本图摘自网络):

三次握手示意图:

- 半连接队列,保存SYN_RECV状态的连接。队列长度由net.ipv4.tcp_max_syn_backlog设置

- accept队列,保存ESTABLISHED状态的连接。队列长度为min(net.core.somaxconn, backlog)。其中backlog是我们创建ServerSocket(int port,int backlog)时指定的参数

如果是队列满导致的syn丢弃,则可以通过netstat -st观察到,如

netstat -st | egrep -i "drop|reject|overflowed|listen|filter"

访问链路:

   访问链路,client --(nginx server)-- ecs nodeport (ipvs转发给某个pod)-- pod,这种链路当nginx server转发请求给后端的ecs nodeport时,ipvs会介入做一次fnat转换,即受访的ecs本地还会起一个随机端口,去跟ipvs给的pod地址建联,相当于有2个会话来完成这个请求

抓包信息图示:

   如下图所示,我们可以通过相同的(seq_number wireshark 用 tcp.seq_raw == 赋值)以及(tcp.ack_raw)找到节点的nodeport转发给pod的真实流,而从图上可以看出确实存在一次syn重传,第一次的syn包,实际pod没有收到,说明问题出现在转发阶段,同时采集了ipvs 以及conntrack的相关session,发现当前端存在异常syn状态的时候,ipvs 以及conntrack 实际并不存在syn状态的session,这种情况我们就要看下还会影响这个报文转发的因素有哪些了,先来了解一下网络报文的内核路径吧

小知识:

1,相同秒级时间的seq num相同可以视为一条流,即在不同的网卡上抓到的这1个请求,seq是一样的

从网卡到内存:

网卡需要有驱动才能工作,驱动是加载到内核中的模块,负责衔接网卡和内核的网络模块,驱动在加载的时候将自己注册进网络模块,当相应的网卡收到数据包时,网络模块会调用相应的驱动程序处理数据。

下图展示了数据包(packet)如何进入内存,并被内核的网络模块开始处理:

image.png

1: 数据包从外面的网络进入物理网卡。如果目的地址不是该网卡,且该网卡没有开启混杂模式,该包会被网卡丢弃。

2: 网卡将数据包通过DMA的方式写入到指定的内存地址,该地址由网卡驱动分配并初始化。注: 老的网卡可能不支持DMA,不过新的网卡一般都支持。

3: 网卡通过硬件中断(IRQ)通知CPU,告诉它有数据来了

4: CPU根据中断表,调用已经注册的中断函数,这个中断函数会调到驱动程序(NIC Driver)中相应的函数

5: 驱动先禁用网卡的中断,表示驱动程序已经知道内存中有数据了,告诉网卡下次再收到数据包直接写内存就可以了,不要再通知CPU了,这样可以提高效率,避免CPU不停的被中断。

6: 启动软中断。这步结束后,硬件中断处理函数就结束返回了。由于硬中断处理程序执行的过程中不能被中断,所以如果它执行时间过长,会导致CPU没法响应其它硬件的中断,于是内核引入软中断,这样可以将硬中断处理函数中耗时的部分移到软中断处理函数里面来慢慢处理。

内核的网络模块

软中断会触发内核网络模块中的软中断处理函数,后续流程如下:


image.png

7: 内核中的ksoftirqd进程专门负责软中断的处理,当它收到软中断后,就会调用相应软中断所对应的处理函数,对于上面第6步中是网卡驱动模块抛出的软中断,ksoftirqd会调用网络模块的net_rx_action函数

8: net_rx_action调用网卡驱动里的poll函数来一个一个的处理数据包

9: 在pool函数中,驱动会一个接一个的读取网卡写到内存中的数据包,内存中数据包的格式只有驱动知道

10: 驱动程序将内存中的数据包转换成内核网络模块能识别的skb格式,然后调用napi_gro_receive函数

11: napi_gro_receive会处理GRO相关的内容,也就是将可以合并的数据包进行合并,这样就只需要调用一次协议栈。然后判断是否开启了RPS,如果开启了,将会调用enqueue_to_backlog

12: 在enqueue_to_backlog函数中,会将数据包放入CPU的softnet_data结构体的input_pkt_queue中,然后返回,如果input_pkt_queue满了的话,该数据包将会被丢弃,queue的大小可以通过net.core.netdev_max_backlog来配置

13: CPU会接着在自己的软中断上下文中处理自己input_pkt_queue里的网络数据(调用__netif_receive_skb_core)

14: 如果没开启RPS,napi_gro_receive会直接调用__netif_receive_skb_core

15: 看是不是有AF_PACKET类型的socket(也就是我们常说的原始套接字),如果有的话,拷贝一份数据给它。tcpdump抓包就是在这里进行的,也就是上面说的为什么能抓到包就可以确认不是前后端丢包或者软中断导致了

16: 调用协议栈相应的函数,将数据包交给协议栈处理。

17: 待内存中的所有数据包被处理完成后(即poll函数执行完成),启用网卡的硬中断,这样下次网卡再收到数据的时候就会通知CPU

enqueue_to_backlog函数也会被netif_rx函数调用,而netif_rx正是lo设备发送数据包时调用的函数

Linux 数据包收发内核路径图

未严格分层,仅做表示

Linux 数据包收发内核路径图--0919.png

协议栈

IP层

  由于是TCP包,所以第一步会进入IP层,然后一级一级的函数往下调,看到这里,相信眼尖的同学就已经发现过了ip协议栈,进入tcp协议栈之前,还要过iptables的相关链,那么在过iptables的时候,到哪个阶段会填充conntrack表呢?


image.png

Conntrack介入的时机-iptables&ipvs表链路径:

iptables的表链路径:

     既然进入tcp协议栈之前需要过一次iptables,那么过iptable在哪个阶段会往conntrack表里面填充的呢?我们继续往下走,看下iptables各个表链工作的路径

先放一张内核协议栈各 hook 点位置和 iptables 规则优先级的经典配图,详细的内核路径图可以往上翻下,当然看图说话还是比较费劲的,我们直接看表格吧

                                               经典大图

    下面的表格展示了 table 和 chain 的关系。横向是 table, 纵向是 chain,Y 表示 这个 table 里面有这个 chain。例如,第二行表示 raw table 有 PRETOUTINGOUTPUT 两 个 chain。具体到每列,从上倒下的顺序就是 netfilter hook 触发的时候,(对应 table 的)chain 被调用的顺序。

有几点需要说明一下。在下面的图中,nat table 被细分成了 DNAT (修改目的地址) 和 SNAT(修改源地址),以更方便地展示他们的优先级。另外,我们添加了路由决策点 和连接跟踪点,以使得整个过程更完整全面:

Tables/Chains

PREROUTING

INPUT

FORWARD

OUTPUT

POSTROUTING

(路由判断)

 

 

 

Y

 

raw

Y

 

 

Y

 

(连接跟踪)

Y

 

 

Y

 

mangle

Y

Y

Y

Y

Y

nat (DNAT)

Y

 

 

Y

 

(路由判断)

Y

 

 

Y

 

filter

 

Y

Y

Y

 

security

 

Y

Y

Y

 

nat (SNAT)

 

Y

 

Y

Y

当一个包触发 netfilter hook 时,处理过程将沿着列从上向下执行。 触发哪个 hook (列)和包的方向(ingress/egress)、路由判断、过滤条件等相关。

特定事件会导致 table 的 chain 被跳过。例如,只有每个连接的第一个包会去匹配 NAT 规则,对这个包的动作会应用于此连接后面的所有包。到这个连接的应答包会被自动应用反 方向的 NAT 规则。

我之前的理解以为过了raw表prerouting链其实就应该往conntrack表里面填充了,但是实际并不是这样的,这里只是相当于打了一个标记而已,后面还要过ipvs的链,下面给大家看个简单的trace的demo

flannel+ipvs的流量在iptables上的进出路径,下面curl的endpoint是pod在本机上的流量展示 源是 172.16.3.85,访问的目标机器 172.16.2.112:32125,pod 10.111.0.25 就在这个机器上,不同的场景,如terway-eni+ipvs ,svc是nodeport,访问的是clusterip,流量策略是local/cluster这些不同的元素都会走不同的路径,这里只做一个简单的demo


Trace在目标机器上添加的

# iptables -t raw -A PREROUTING -p tcp -s 172.16.3.85 --dport 32125 -j TRACE

# iptables -t raw -A OUTPUT -p tcp -s 172.16.3.85 --dport 32125 -j TRACE


第一阶段,刚开始过各种表的 prerouting链,可以结合上面的表格看


Oct 21 14:34:49 iZwz92a65mqaa9jbf5z4irZ kernel: TRACE: raw:PREROUTING:policy:5 IN=eth0 OUT= MAC=00:16:3e:16:ea:fb:ee:ff:ff:ff:ff:ff:08:00 SRC=172.16.3.85 DST=172.16.2.112 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=2229 DF PROTO=TCP SPT=49704 DPT=32125 SEQ=1668671541 ACK=0 WINDOW=29200 RES=0x00 SYN URGP=0 OPT (020405B40402080A251AE0800000000001030307)

Oct 21 14:34:49 iZwz92a65mqaa9jbf5z4irZ kernel: TRACE: mangle:PREROUTING:policy:1 IN=eth0 OUT= MAC=00:16:3e:16:ea:fb:ee:ff:ff:ff:ff:ff:08:00 SRC=172.16.3.85 DST=172.16.2.112 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=2229 DF PROTO=TCP SPT=49704 DPT=32125 SEQ=1668671541 ACK=0 WINDOW=29200 RES=0x00 SYN URGP=0 OPT (020405B40402080A251AE0800000000001030307)

......

Oct 21 14:34:49 iZwz92a65mqaa9jbf5z4irZ kernel: TRACE: nat:PREROUTING:policy:2 IN=eth0 OUT= MAC=00:16:3e:16:ea:fb:ee:ff:ff:ff:ff:ff:08:00 SRC=172.16.3.85 DST=172.16.2.112 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=2229 DF PROTO=TCP SPT=49704 DPT=32125 SEQ=1668671541 ACK=0 WINDOW=29200 RES=0x00 SYN URGP=0 OPT (020405B40402080A251AE0800000000001030307) MARK=0x4000


第二阶段,过input链,可以观察各个表链

Oct 21 14:34:49 iZwz92a65mqaa9jbf5z4irZ kernel: TRACE: mangle:INPUT:policy:1 IN=eth0 OUT= MAC=00:16:3e:16:ea:fb:ee:ff:ff:ff:ff:ff:08:00 SRC=172.16.3.85 DST=172.16.2.112 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=2229 DF PROTO=TCP SPT=49704 DPT=32125 SEQ=1668671541 ACK=0 WINDOW=29200 RES=0x00 SYN URGP=0 OPT (020405B40402080A251AE0800000000001030307) MARK=0x4000

......

Oct 21 14:34:49 iZwz92a65mqaa9jbf5z4irZ kernel: TRACE: filter:INPUT:policy:4 IN=eth0 OUT= MAC=00:16:3e:16:ea:fb:ee:ff:ff:ff:ff:ff:08:00 SRC=172.16.3.85 DST=172.16.2.112 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=2229 DF PROTO=TCP SPT=49704 DPT=32125 SEQ=1668671541 ACK=0 WINDOW=29200 RES=0x00 SYN URGP=0 OPT (020405B40402080A251AE0800000000001030307) MARK=0x4000


第三阶段,input链过完走output,这个时候可以看到流量被转给了cni0的网卡,目的地址换成了10.111.0.25:80,这个ip是真实的pod ip + port


Oct 21 14:34:49 iZwz92a65mqaa9jbf5z4irZ kernel: TRACE: raw:OUTPUT:policy:9 IN= OUT=cni0 SRC=172.16.3.85 DST=10.111.0.25 LEN=60 TOS=0x00 PREC=0x00 TTL=63 ID=2229 DF PROTO=TCP SPT=49704 DPT=80 SEQ=1668671541 ACK=0 WINDOW=29200 RES=0x00 SYN URGP=0 OPT (020405B40402080A251AE0800000000001030307) MARK=0x4000

......

Oct 21 14:34:49 iZwz92a65mqaa9jbf5z4irZ kernel: TRACE: nat:KUBE-POSTROUTING:rule:4 IN= OUT=cni0 SRC=172.16.3.85 DST=10.111.0.25 LEN=60 TOS=0x00 PREC=0x00 TTL=63 ID=2229 DF PROTO=TCP SPT=49704 DPT=80 SEQ=1668671541 ACK=0 WINDOW=29200 RES=0x00 SYN URGP=0 OPT (020405B40402080A251AE0800000000001030307)


在这之前的包都是syn包,可以看关键字 RES=0x00 SYN URGP=0 ,这里的syn就是syn包,同时可以看到 SEQ=1668671541 ACK=0 一般都是代表了独立的syn包,trace是不到万不得已不建议用,实在是比较难读的,可以结合抓包一起看


Oct 21 14:34:49 iZwz92a65mqaa9jbf5z4irZ kernel: TRACE: raw:PREROUTING:policy:5 IN=eth0 OUT= MAC=00:16:3e:16:ea:fb:ee:ff:ff:ff:ff:ff:08:00 SRC=172.16.3.85 DST=172.16.2.112 LEN=52 TOS=0x00 PREC=0x00 TTL=64 ID=2230 DF PROTO=TCP SPT=49704 DPT=32125 SEQ=1668671542 ACK=3151037026 WINDOW=229 RES=0x00 ACK URGP=0 OPT (0101080A251AE0816F0DFBA1)

...省略数十万字

Oct 21 14:34:49 iZwz92a65mqaa9jbf5z4irZ kernel: TRACE: mangle:POSTROUTING:policy:1 IN= OUT=cni0 SRC=172.16.3.85 DST=10.111.0.25 LEN=52 TOS=0x00 PREC=0x00 TTL=63 ID=2234 DF PROTO=TCP SPT=49704 DPT=80 SEQ=1668671625 ACK=3151037305 WINDOW=237 RES=0x00 ACK URGP=0 OPT (0101080A251AE0856F0DFBA4)


IPVS工作的HOOK点:

IPVS的实现利用了Netfilter的三个Hook点,分别是:NF_INET_LOCAL_IN、NF_INET_LOCAL_OUT和NF_INET_FORWARD。在每个Hook点,IPVS注册了两个钩子函数

如下表所示,IPVS中对于Request和Reply的定义,是按照由外部客户端到IPVS内部的报文为Request;而由IPVS内部回复到外部客户端的报文为Reply。所以,Hook函数的命名中带有request的都对应IPVS核心函数ip_vs_in;而Hook函数命名中带有reply的函数都对应IPVS的核心函数ip_vs_out。

Hook点LOCAL_IN

在Hook点NF_INET_LOCAL_IN上,IPVS挂载了两个函数ip_vs_reply4和ip_vs_remote_request4,其中前者优先级高于后者。前者ip_vs_reply4主要用于NAT/Masq转发模式,其核心处理函数为ip_vs_out,负责处理IPVS系统回复给外部客户端的报文,包括修改IP地址等。

由于是回复报文,要求系统中已经存在连接,否则处理IPVS系统中真实服务器可能发送的ICMP报文。

static unsigned int ip_vs_out(struct netns_ipvs *ipvs, unsigned int hooknum, struct sk_buff *skb, int af)

{

   /* Check if the packet belongs to an existing entry

    */

   cp = pp->conn_out_get(ipvs, af, skb, &iph);

   if (likely(cp)) {

       if (IP_VS_FWD_METHOD(cp) != IP_VS_CONN_F_MASQ)

           goto ignore_cp;

       return handle_response(af, skb, pd, cp, &iph, hooknum);

   }


   if (sysctl_nat_icmp_send(ipvs) &&

       (pp->protocol == IPPROTO_TCP ||

        pp->protocol == IPPROTO_UDP ||

        pp->protocol == IPPROTO_SCTP)) {

另外一个Hook函数ip_vs_remote_request4,其核心函数为ip_vs_in,负责处理由外部客户端进入IPVS系统的报文,如果没有可用的连接,将使用调度函数进行调度处理,创建连接结构。

static unsigned int ip_vs_in(struct netns_ipvs *ipvs, unsigned int hooknum, struct sk_buff *skb, int af)

{

   if (unlikely(!cp)) {

       int v;

       if (!ip_vs_try_to_schedule(ipvs, af, skb, pd, &v, &cp, &iph))

           return v;

   }

   ip_vs_in_stats(cp, skb);

   ip_vs_set_state(cp, IP_VS_DIR_INPUT, skb, pd);

   if (cp->packet_xmit)

       ret = cp->packet_xmit(skb, cp, pp, &iph);

}

Hook点LOCAL_OUT

与前一节的NF_INET_LOCAL_IN Hook点不同,此处的NF_INET_LOCAL_OUT的Hook点用于处理IPVS本机发送的报文。而前者用于处理外部客户端进入IPVS系统的报文。

在Hook点NF_INET_LOCAL_OUT上,IPVS挂载了两个函数ip_vs_local_reply4和ip_vs_local_request4,其中前者优先级高于后者。前者ip_vs_local_reply4的核心函数为ip_vs_out,主要用于NAT/Masq转发模式,负责NAT地址的修改。

函数ip_vs_local_request4的核心函数为ip_vs_in,其负责处理由本机应用层进入IPVS系统的报文的调度和发送。

Hook点FORWARD

在Hook点NF_INET_FORWARD上,IPVS挂载了两个函数ip_vs_forward_icmp和ip_vs_reply4,其中前者优先级高于后者。前者ip_vs_forward_icmp的核心处理函数为ip_vs_in_icmp,用于处理外部进入IPVS系统的ICMP报文,将其调度到对应的真实服务器上。

static int ip_vs_in_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb, int *related, unsigned int hooknum)

{

   cp = pp->conn_in_get(ipvs, AF_INET, skb, &ciph);


   if (!cp) {

       int v;


       if (!sysctl_schedule_icmp(ipvs))

           return NF_ACCEPT;


       if (!ip_vs_try_to_schedule(ipvs, AF_INET, skb, pd, &v, &cp, &ciph))

           return v;

       new_cp = true;

   }

verdict = ip_vs_icmp_xmit(skb, cp, pp, offset, hooknum, &ciph);

函数ip_vs_reply4,核心函数为ip_vs_out,主要用于NAT/Masq转发模式,负责NAT地址的修改。对于真实服务器回复的报文,其目的地址为外部客户端的地址,非IPVS系统的虚拟地址,所以其将进入此转发Hook点,此时进行SNAT转换,将源地址转换为IPVS的虚拟地址。


以上路径参考内核版本 4.15

conntrack:

  如下图所示,Netfilter 在四个 Hook 点对包进行跟踪,之前以为的过raw表PREROUTING链时会创建一个conntrack连接,实际不是直接填充到表内的

   

  1. PRE_ROUTINGLOCAL_OUT调用 nf_conntrack_in() 开始连接跟踪, 正常情况下会创建一条新连接记录,然后将 conntrack entry 放到unconfirmed list为什么是这两个 hook 点呢?因为它们都是新连接的第一个包最先达到的地方
  • PRE_ROUTING外部主动和本机建连时包最先到达的地方
  • LOCAL_OUT本机主动和外部建连时包最先到达的地方
  1. POST_ROUTINGLOCAL_IN调用 nf_conntrack_confirm() 将 nf_conntrack_in() 创建的连接移到 confirmed list同样要问,为什么在这两个 hook 点呢?因为如果新连接的第一个包没有被丢弃,那这 是它们离开 netfilter 之前的最后 hook 点
  • 外部主动和本机建连的包,如果在中间处理中没有被丢弃,LOCAL_IN是其被送到应用(例如 nginx 服务)之前的最后 hook 点
  • 本机主动和外部建连的包,如果在中间处理中没有被丢弃,POST_ROUTING 是其离开主机时的最后 hook 点

一点个人理解:

     nf_conntrack_in创建的连接是在一个内存列表内,过了input再由nf_conntrack_confirm来插入conntrack表,而ipvs在input链上做了一些流量劫持的动作,需要做nat转换ecs ip+nodeport到pod ip+port,ipvs没丢这个包才会被正经插入到conntrack表内,因此这个问题需要继续往下看


排查分析过程:

采集conntrack表里面 syn状态的信息,判断一下session有没有被填充到conntrack里面,

for i in {1..600};do echo `date` >>c.log;ipvsadm -Ln -c |grep -i syn >>c.log;grep -i syn /proc/net/nf_conntrack >>c.log;sleep 1s.done


实际conntrack还支持状态的采集,以及源目端口的用法等,如:

conntrack -L -p tcp --dport 8611 --state SYN_RECV


###支持以下状态

--state [NONE | SYN_SENT | SYN_RECV | ESTABLISHED | FIN_WAIT | CLOSE_WAIT | LAST_ACK | TIME_WAIT | CLOSE | LISTEN]

TCP state

参见conntrack man手册

http://conntrack-tools.netfilter.org/conntrack.html

iptables添加trace日志,为什么添加trace日志,需要看被丢弃的syn包到了哪个表链上来判断问题所在,如 过了raw表的prerouting,manage表的prerouting等等,最终input后没有下文了,说明ipvs大概率是有问题的

iptables -t raw -A OUTPUT -p tcp -s 源ip --dport 目标port -j TRACE

iptables -t raw -A PREROUTING  -p tcp -s 源ip --dport 目标port -j TRACE


###排查过程中发现有的时候不添加port的话trace不工作

使用bcctools跟踪重传的包,实际这个问题在排查的时候,bcctools没能抓到被drop的syn包

# ./tcpretrans

Tracing retransmits ... Hit Ctrl-C to end

TIME     PID    IP LADDR:LPORT          T> RADDR:RPORT          STATE

14:14:49 3300458 4  192.168.40.72:45584  R> 192.168.0.2:10255    SYN_SENT

14:14:49 3300480 4  192.168.40.182:50610 R> 192.168.0.242:10250  SYN_SENT

14:14:50 0      4  192.168.40.182:53896 R> 192.168.0.241:10250  SYN_SENT

14:14:50 0      4  192.168.40.182:50500 R> 192.168.0.242:10250  SYN_SENT

14:14:50 0      4  192.168.40.182:36276 R> 192.168.0.2:10250    SYN_SENT

tcpdump指定flags采集syn的包

tcpdump可以组合flags抓包,就不用每次都下载到本地看了

tcpdump -i any "tcp[tcpflags] & (tcp-syn) != 0" and "tcp[tcpflags] & (tcp-ack) != 0" -nv


上面的手段用完,依然不能确认问题在哪,就需要采集全量的conntrack 以及 ipvs 相关连接做对比了,这个问题的原因是因为net.ipv4.vs.conn_reuse_mode=1时,根据ip_vs_in()的处理逻辑,当开启了net.ipv4.vs.conntrack时,且conntrack表中相同的五元组是time_wait状态,则会 DROP 掉第一个 SYN 包,等待 SYN 的重传然后分配新的连接,有 1S 延迟。而 Kube-proxy 在 IPVS 模式下,使用了 iptables 进行MASQUERADE,也正好开启了net.ipv4.vs.conntrack

对应的代码说明:

下面来自 可参考 Julian Anastasov (这位可是写在ipvs源码里面的Authors之一)的回复:


What could be causing the delay? How can we get rid of it?
 It should be this code that leads to delay:
 if (uses_ct)
  return NF_DROP;
 What happens is that we drop SYN packet that hits IPVS
connection in TIME_WAIT state if such connection uses
Netfilter connection tracking (conntrack=1).
 The conn_reuse_mode=1 relies on selecting different
real server but as we can not alter the Netfilter conntrack
tuple after it is confirmed, we drop the conntrack, the IPVS
connection and current packet and expect next SYN (retransmitted
after 1 second, as you observe) to create new IPVS connection
and corresponding conntrack to some available real server.
And that is what happens after 1 second.
 To get rid of this delay you have the following options:
1. do not enable IPVS conntrack mode (can be slower to create
and drop conntrack on every packet), use conntrack=0 for this.
This allows IPVS to ignore the TIME_WAIT connection and to
create a new one.
2. Use NOTRACK for IPVS connections, it should be faster
because conntracks are not created/removed
iptables -t raw -A PREROUTING -p tcp -d VIP --dport VPORT -j CT --notrack
For local clients use -A OUTPUT -o lo
If needed, such traffic can be matched with -m state --state UNTRACKED
3. Reduce the TIME_WAIT timeout in IPVS source, table
tcp_timeouts[]. It does not solve the problem but reduces
its rate.
Regards
--
Julian Anastasov <ja@ssi.bg>

一句话总结:

      tcpdump能抓到包的话,说明过了网卡,以及cpu中断等环节,即非前后端丢包,抓包之后是 ip_rcv再到iptables,根据iptables的链表规则,先进raw表,可以在raw表上开启trace看看是否进了iptables来判断是否存在ip_rcv丢包的情况,进了iptables后,再看trace跟踪的流走的相关表链,以及fnat发生在哪个表链上(看源目的变化),当使用了IPVS的的时候,ipvs会在input链上拿走数据进行处理,做完转换才会往conntrack表里填充,而不是过了raw表后就填充,实际上net.ipv4.vs.conn_reuse_mode=0时在老版的内核中也会引起问题,详情可见我的另一篇文章《k8s网络诊断之我的流量去哪了》,借着这个问题,让我们学习了一个包进到系统内走的各个路径,同时也学到了iptables的trace 以及conntrack 表工具的使用,写这个文档主要是想分享一下网络问题的处理思路,其中很多资料借鉴以及个人理解可能会有偏差,欢迎斧正


参考文献:

One second connection delay in masquerading mode

连接跟踪(conntrack):原理、应用及 Linux 内核实现

Monitoring and Tuning the Linux Networking Stack: Receiving Data

相关实践学习
通过Ingress进行灰度发布
本场景您将运行一个简单的应用,部署一个新的应用用于新的发布,并通过Ingress能力实现灰度发布。
容器应用与集群管理
欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
目录
相关文章
|
2月前
|
监控 网络协议 安全
|
2月前
|
缓存 算法 物联网
基于AODV和leach协议的自组网络平台matlab仿真,对比吞吐量,负荷,丢包率,剩余节点个数,节点消耗能量
本系统基于MATLAB 2017b,对AODV与LEACH自组网进行了升级仿真,新增运动节点路由测试,修正丢包率统计。AODV是一种按需路由协议,结合DSDV和DSR,支持动态路由。程序包含参数设置、消息收发等功能模块,通过GUI界面配置节点数量、仿真时间和路由协议等参数,并计算网络性能指标。 该代码实现了节点能量管理、簇头选举、路由发现等功能,并统计了网络性能指标。
164 73
|
20天前
|
网络协议 安全 算法
网络空间安全之一个WH的超前沿全栈技术深入学习之路(9):WireShark 简介和抓包原理及实战过程一条龙全线分析——就怕你学成黑客啦!
实战:WireShark 抓包及快速定位数据包技巧、使用 WireShark 对常用协议抓包并分析原理 、WireShark 抓包解决服务器被黑上不了网等具体操作详解步骤;精典图示举例说明、注意点及常见报错问题所对应的解决方法IKUN和I原们你这要是学不会我直接退出江湖;好吧!!!
网络空间安全之一个WH的超前沿全栈技术深入学习之路(9):WireShark 简介和抓包原理及实战过程一条龙全线分析——就怕你学成黑客啦!
|
26天前
|
Kubernetes Linux 测试技术
|
2月前
|
存储 弹性计算 测试技术
阿里云服务器实例规格vCPU、内存、网络带宽、网络收发包PPS、连接数等性能指标详解
阿里云服务器ECS实例可以分为多种实例规格族。根据CPU、内存等配置,一种实例规格族又分为多种实例规格。而实例规格又包含vCPU、处理器、内存、vTPM、本地存储、网络带宽、网络收发包PPS、连接数、弹性网卡、云盘带宽、云盘IOPS等指标,本文为大家详细介绍实例规格的这些指标,以供大家了解和选择。
147 14
阿里云服务器实例规格vCPU、内存、网络带宽、网络收发包PPS、连接数等性能指标详解
|
1月前
|
Kubernetes 网络协议 网络安全
k8s中网络连接问题
【10月更文挑战第3天】
142 7
|
20天前
|
网络协议 安全 算法
网络空间安全之一个WH的超前沿全栈技术深入学习之路(9-2):WireShark 简介和抓包原理及实战过程一条龙全线分析——就怕你学成黑客啦!
实战:WireShark 抓包及快速定位数据包技巧、使用 WireShark 对常用协议抓包并分析原理 、WireShark 抓包解决服务器被黑上不了网等具体操作详解步骤;精典图示举例说明、注意点及常见报错问题所对应的解决方法IKUN和I原们你这要是学不会我直接退出江湖;好吧!!!
|
2月前
|
网络协议 网络虚拟化
接收网络包的过程——从硬件网卡解析到IP
【9月更文挑战第18天】这段内容详细描述了网络包接收过程中机制。当网络包触发中断后,内核处理完这批网络包,会进入主动轮询模式,持续处理后续到来的包,直至处理间隙返回其他任务,从而减少中断次数,提高处理效率。此机制涉及网卡驱动初始化时注册轮询函数,通过软中断触发后续处理,并逐步深入内核网络协议栈,最终到达TCP层。整个接收流程分为多个层次,包括DMA技术存入Ring Buffer、中断通知CPU、软中断处理、以及进入内核网络协议栈等多个步骤。
|
1月前
|
网络协议 网络架构
【第三期】计算机网络常识/网络分层模型与数据包封装传输过程
【第三期】计算机网络常识/网络分层模型与数据包封装传输过程
46 0
|
1月前
|
Kubernetes 容器
基于Ubuntu-22.04安装K8s-v1.28.2实验(三)数据卷挂载NFS(网络文件系统)
基于Ubuntu-22.04安装K8s-v1.28.2实验(三)数据卷挂载NFS(网络文件系统)
135 0