您好,欢迎访问上海聚搜信息技术有限公司官方网站!
24小时咨询热线:4000-747-360

上海阿里云代理商:记一次k8s压测发生SLB 499的串流问题

时间:2022-11-25 23:34:07 点击:

  上海阿里云代理商:记一次k8s压测发生SLB 499的串流问题

  聚搜云(www.4526.cn)是上海聚搜信息技术有限公司旗下品牌,坐落于魔都上海,服务于全球、2019年成为阿里云代理商生态合作伙伴。与阿里云代理商、腾讯云、华为云、西部数码、美橙互联、AWS亚马逊云国际站代理商、聚搜云,长期战略合作的计划!阿里云国际站代理商专业的云服务商!

  问题描述

  对阿里云ACK集群中的pod进行压测,压测方式是直接访问集群前的SLB, 压测表现是 SLB (CLB 7层监听)偶发返回499报错。

  补充抓包后看到的表现:SLB后端抓包表现是,SLB传到后端的SYN包被后端服务节点直接ACK而结束三次握手,建联失败。

  关键词: 偶发 、压测、SYN-ACK、ExternalTrafficPolicy:Cluster、七层SLB

  环境

  数据流向:

  七层SLB -> Node: NodePort ( Svc ExternalTraffic:Cluster) -> Pod

  环境:

  集群版本:阿里云ACK 1.20.11-aliyun.1

  节点操作系统:Aliyun Linux 2

  SLB: CLB 7层监听

  SLB 后端:手动挂的nodeport类型svc, 且ExternalTrafficPolicy:Cluster

  架构:

  SLB后端手动挂多集群的nodeport类型svc, 实现多集群的负载均衡。(此处不对业务架构设计做讨论)

  问题分析

  异常复杂网络问题,且偶发可复现,自然要抓包分析。但是该类问题通常只有tcpdump抓包是不够的,本文略掉中间的摸索过程,直接上有效的所有分析步骤。

  1. 抓包准备:

  为便于抓取后端数据,测试环境中slb svc 后缩容只有一个pod。

  1) Node进行tcpdump抓包(200M一个 抓10个包 问题复现之前涵盖五分钟):

  sudo tcpdump -i any -nnvv -C 200 -W 10 -w /alios_499.pcap

  2)Node抓ipvsadm 以及contrack表项状态 ;Pod抓netstat状态综合分析:

  //直接运行在pod节点上的脚本

  for i in {1..2000}

  do

  echo $(date) >> node.txt

  sudo ipvsadm -Ln -c |egrep "nodeip:nodeport" >>node.txt

  sudo egrep "nodeport" /proc/net/nf_conntrack  >>node.txt

  sleep 1s

  done

  //nsenter切换到pod网络命名空间:nsenter -n -p <pid> ,抓pod里面的netstat

  for i in {1..2000}

  do

  echo $(date) >> pod.txt

  netstat -antpl|grep pod-port >> pod.txt

  sleep 1s

  done

  2. 问题复现:

  通过监控SLB 499的日志,确认问题复现时间2022-xx-xx 17:05:42

  则之前部署的有效抓包时间段 2022.xx.xx 17:00:42-17:06:01

  3. 数据包分析:

  1) 如何从海量数据包中找到问题数据流

  方法一: 使用wireshark- statics->conversation -> limit to display-》packets排序找 “1”

  由于三次握手没完成,SYN后没收到SYN,ACK, 因此使用 tcp.flags.syn == 1以及node/pod ip 过滤,找非成对单数的数据流,可以定位看到SLB源端口33322 , node 源端口30552  对应的数据流符合条件:

  进而使用过滤条件 tcp.port == 33322 or tcp.port == 30552 可以定位到问题数据流 tcp.stream in {24182  24183},问题时间戳是17:05:41。

  SLB-NODE是一个stream 24182, node-pod是新的stream 24183,其实只分析node向后转发给pod的24183即可。

  方法二:当数据包很大时,可使用命令行tshark分析

  过滤条件tcp.flags.syn == 1 and (ip.src == 10.1.72.105 or ip.dst == 10.1.72.105)

  tshark -t ad -r alios_499.pcap6 -Y "tcp.flags.syn == 1 && (ip.src == 10.0.1.107 || ip.dst== 10.0.1.107) && (ip.src == 10.1.72.105 || ip.dst== 10.1.72.105)" -T fields -e "tcp.stream" -e "frame.number" -e "ip.addr" -e "tcp.port"| awk '{print $1}' |sort|uniq -c |awk '{ if ( $1 % 2 != 0) print $2 }'

  基于上述两种方法,找到SLB 499对应的异常数据流为tcp.stream in {24182  24183},问题时间戳是17:05:41,看数据链路的端口为:

  stream 24182:SLB源端口33322 -> Node目的端口:30718

  stream 24183:Node源端口30552-> Pod目的端口7001

  小知识:

   由于SLB是7层,因此数据包流经SLB后,SLB会跟后端新起一个新stream,源IP 会SNAT修改为SLB内部IP后转发给后端。因此抓包看不到源客户端IP,而是SLB的IP。

   ExternalTrafficPolicy:Cluster 模式,数据包经过node转发给pod时,会被SNAT, 源IP被SNAT为node IP,因此节点上抓包会有两个stream (SLB-NODE ; NODE-POD)。

   同一条数据流流经 SLB-Node-Pod 三个环节时的tcp.seq相同,也可以先找到node->pod的异常包后根据tcp.seq找slb-node包。

  2)查node的ipvs连接以及contrack表定位

  针对异常stream 24183:Node源端口30552-> Pod目的端口7001,可以发现,在异常数据包于17:05:41到达之前有一条使用相同端口五元组的“TIME_WAIT”状态的连接还没结束。新的SYN包经node转发给pod时,复用了端口30552,导致node到pod的两次数据流五元组相同 。查pod的netstat,也可以看到异常数据包到达pod时,前一条五元组相同的连接处于 “TIME_WAIT”。

  基于节点内部ipvs/conntrack表的分析,最终找到node -pod 发生串流的两个 stream:

  tcp.stream in {19697 24183}  //NODE-POD的stream

  17:05:36  TIME_WAIT 100.117.95.144:9742  - 10.0.1.107:9742 -> SNAT-> 10.0.1.107:30552 -> TCP->10.1.72.105:7001

  17:05:41  SYN_SENT 100.117.95.189:33322 - 10.0.1.107:33322 -> SNAT-> 10.0.1.107:30552 -> TCP->10.1.72.105:7001

  数据分析详情:

   查node的contrack表:

  可以发现node-pod这一段的五元组(红框中所示)中,17:05:36的表项正处于TIME_WAIT ,对应的SLB source 是100.117.95.144:9742 (slb-node段没重复);5秒后17:05:41的表项是新的stream,状态为SYN_SENT (该表项可以看出问题数据流是node-pod五元组重复的数据流),对应的slb source是100.117.95.189:33322。

   查node的ipvs连接:

  17:05:36的时候,在ipvs的session 中该五元组正在倒计时 01:58,还没结束。五秒后17:05:41新的session来的时候,前一个五元组倒计时还剩01分54秒。因此新syn包命中五元组重复的场景。

   分析 pod中 netstat

  可以看到pod:7001到node:30552端口的连接处于time_wait.

  小知识:

   五元组为 【源IP+源端口+协议+目的IP+目的端口】 组合。

   ExternalTrafficPolicy两种模式解析:

  若SLB后端nodeport类型的svc采用ExternalTraffic:Cluster模式,SLB转发的数据包在经node转发给pod时会被SNAT,传入pod的数据流的源IP会变为node IP。节点的端口有限,因此在压测流量大的场景中,对于相同的pod ip:pod port,很容易发生nodeip:node port 五元组重复。

  若SLB后端nodeport类型的svc采用ExternalTraffic:Local模式,SLB转发的数据包经node只会转发给本机pod,且数据包不会被SNAT,传入pod的数据流的源IP源端口依旧是SLB的IP跟端口。由于SLB是公有云的7层负载均衡,底层实则是整个集群做支撑,因此slb的源端口不容易发生重复。在以上抓包看到node-pod五元组重复的场景中也可以看到,slb-node的stream中,slb port其实每次都不同。

   TIME_WAIT:TCP连接中断过程中,主动关闭的一方在发送最后一个 ack 后就会进入 TIME_WAIT 状态停留2MSL(max segment lifetime),这个是TCP/IP链接关闭过程中必不可少的状态。如果在TIME_WAIT 状态继续收到相同五元组的SYN数据包,协议栈如何处理?本案例中是服务端回复SYN包一个ACK结束建联。

  方案建议

  本文不讨论架构优化,针对本次案例中串流问题的方案建议:

  1. 针对五元组重复的串流问题,通用解法是采用 externalTrafficPolicy =Local,这样node-pod的数据包不会被SNAT为node的ip:port,那么pod接收到数据包都会是slb的IP:PORT,由于slb位于公有云七层负载均衡的集群中,slb ip通常也是整个集群ip列表中的一个,就可以大大减少出现ip跟port都重复的概率。

  2. 若是terway模式的集群,SLB后端可以采用terway eni模式直接挂pod eni在SLB后端,slb 转发的数据包可以不用在node做周转,省去了ipvs/iptables这一层转换,slb后直达pod,除了对性能也可以有所提升,也可以避免被node snat后五元组重复的串流问题。

  3. 该问题只有在流量很密集的场景中偶发,比如上文中的压测场景,正常业务场景中很少命中这个问题,若不做配置改动,可视业务需求而忽略。

标签

收缩
  • 电话咨询

  • 4000-747-360
微信咨询 获取代理价(更低折扣)
更低报价 更低折扣 代金券申请
咨询热线: 15026612550