[转帖]性能分析之TCP全连接队列占满问题分析及优化过程

性能,分析,tcp,连接,队列,占满,问题,优化,过程 · 浏览次数 : 0

小编点评

**内容生成指令** ```bash #定义队列的数据包的最大数目 cat /proc/sys/net/core/netdev_max_backlog #使用命令使之生效 sysctl -p ``` **优化指令** * **php优化 ( -1 )**:设置 `listen.backlog` 为 2048,以确保每个端口的最大监听队列长度为 2048。 * **linux内核参数优化**:设置 `net.ipv4.tcp_syncookies` 为 1,以确保所有连接请求可保存在队列中。设置 `net.core.somaxconn` 为 4096,以确保每个端口的最大监听队列长度为 4096。 **其他** * **nginx配置参数优化**:使用 `server`块设置 `listen` 和 `backlog`,以确保每个端口的监听队列长度为 2048。 * **php优化 ( -1 )**:在 `php-fpm.conf` 中设置 `listen.backlog` 为 2048。 * **linux内核参数优化**:在 `sysctl.conf` 中设置 `net.ipv4.tcp_syncookies` 和 `net.core.somaxconn`。

正文

https://www.cnblogs.com/wx170119/p/12068005.html

 

前言

在对一个挡板系统进行测试时,遇到一个由于TCP全连接队列被占满而影响系统性能的问题,这里记录下如何进行分析及解决的。

 

理解下TCP建立连接过程与队列

 

 

从图中明显可以看出建立 TCP 连接的时候,有两个队列:syns queue(半连接队列)和accept queue(全连接队列),分别在第一次握手和第三次握手。
半连接队列: 保存 SYN_RECV 状态的连接。
控制参数:

  • 半连接队列的大小:min(backlog, 内核参数 net.core.somaxconn,内核参数tcp_max_syn_backlog).

  • net.ipv4.tcp_max_syn_backlog:能接受 SYN 同步包的最大客户端数量,即半连接上限;

  • tcp_syncookies:当出现SYN等待队列溢出时,启用cookies来处理,可防范少量SYN攻击,默认为0,表示关闭;

accept队列-全连接队列:保存 ESTABLISHED 状态的连接。
控制参数:

  • 全连接队列的大小:min(backlog, /proc/sys/net/core/somaxconn),意思是取backlog 与 somaxconn 两值的最小值,net.core.somaxconn 定义了系统级别的全连接队列最大长度,而 backlog 只是应用层传入的参数,所以 backlog 值尽量小于net.core.somaxconn;

  • net.core.somaxconn(内核态参数,系统中每一个端口最大的监听队列的长度);

  • net.core.netdev_max_backlog(每个网络接口接收数据包的速率比内核处理这些包的速率快时,允许送到队列的数据包的最大数目);

  • ServerSocket(int port, int backlog) 代码中的backlog参数;

  • 文件句柄;

  • net.ipv4.tcp_abort_on_overflow = 0,此值为 0 表示握手到第三步时全连接队列满时则扔掉 client 发过来的 ACK,此值为 1 则说明握手到第三步时全连接队列满时则返回 reset 给客户端。

系统概况

系统的整体架构比较简单,只有一个挡板服务,业务功能主要是接受业务数据写入日志文件,并加了 35 ms的延时等待,没有复杂的运算等业务逻辑。

开始第一次压测

以 6000 线程并发,加 1 秒的等待,对挡板服务发起压力,压测结果如下:
PS:应客户要求,为了模拟真实业务场景,用较大并发进行测试。

 

 通过上图可以看出,当系统吞吐量也就是 TPS 达到 3800 左右的时候,系统开始出现部分请求失败,继续压一段时间后,报错没有减少,且有增多的趋势。这是什么原因导致的呢,接着我也观察了下,系统的资源使用情况,发现CPU也不是很高,那可以先排除系统CPU资源的问题。

 

 

这时候,我们一定要记住,当出现请求事务大量失败的时候,一定要先看以下具体的错误信息,在继续往下面分析,而不是进行盲目的猜测,这里要提一下高楼老师经常强调的证据链,一定要根据详细的错误信息指向进行下一步分析,不能根据猜测进而通过修改一些参数,或者增加系统资源来解决问题。
以下是具体的报错信息:

 

看到报错信息后,发现有大量的 “Connection reset” 错误,导致这种错误的原因就是服务端因为某种原因关闭了 Connection,而客户端仍然在读写数据,此时服务器会返回复位标志 “RST”,也就是刚才提到的 `“java.net.SocketException: Connection reset”。参考 Oracle 的相关文档,看到这么一段话,原文如下:

By contrast, an abortive close uses the RST (Reset) message. If either side issues an RST, this means the entire connection is aborted and the TCP stack can throw away any queued data which has not been sent or received by either application.

翻译过来也就是说:

如果任何一方发出RST,这意味着整个连接被中止,TCP栈可以丢弃任何没有被任何应用程序发送或接收的队列数据。

这样的话,问题就很明显了,接下来看下 TCP 连接队列的溢出数据统计情况,命令为:“netstat -s

# 查看TCP半连接队列溢出:
netstat -s | grep LISTEN

# 查看TCPaccept队列溢出:
netstat -s | grep overflow

 

 

通过反复敲命令,可以看出这个 overflow 的值一直在增加,那么这个现象说明 server 的TCP 全连接队列的确是满了。这时候应该想到的是,全连接队列已经溢出了,下一步就应该看一下,全连接队列的占用情况,命令为:

 

 

参数说明:

  • Recv-Q:全连接当前长度

  • Send-Q:如果连接不是在建立状态,则是当前全连接最大队列长度

从上图第三列的 Send-Q 可以看出,5000 端口服务的全连接队列最大为 50,而 Recv-Q 为当前使用了多少。在压测过程中,查看指定端口的 TCP 全连接队列使用情况,如下:

 

 

 上图可以看出,全连接队列几乎已经被占满,那么最终可以确定问题所在了。找到原因后,现在只要增大全连接队列的长度就可以了。
通过上面介绍的全连接队列中,我们知道全连接队列的大小为 backlog 和 somaxconn 的最小值,那么来看下 somaxconn 的取值。

可以看出 somaxconn 的值是很大的,那就只有通知开发,增加应用代码中的 backlog 的值来加大全连接队列的长度。

调大backlog值为5000后,再次进行压测

调整后的全连接队列如下图所示:

 

 继续以 6000 并发对系统发起压力,测试结果如下:

 

 从上面的测试结果数据看出,已经没有错误请求了,再次查看TCP全连接队列的使用情况,Recv-Q的值也变得很大,但是仍小于 5000,这也说明之前的 50 的确太小,导致全连接队列被占满,最终影响系统性能,出现大量请求失败,到此,由 TCP 连接队列满导致的问题解决。

但是仔细看上面的 JMeter 的测试结果数据,发现当系统并发达到 4600 多后,再继续加大线程,系统的响应时间开始大幅度的增加,TPS增加趋势变缓,可以看出来此时系统仍存在瓶颈。
发现仍问题后,接着往下分析。系统没有报错,响应时间变长,导致系统吞吐量增长速度变慢。这时应该清楚的是,接下来该看什么。首先查看系统CPU使用情况,发现并不是很高,说明不是系统资源不够用而引起的问题。因为挡板服务本身没有什么业务逻辑,只是加了 35 ms的延时,那么如果响应时间变慢了,那么多半是由于网络传输出现阻塞导致。
所以使用命令:

netstat -ano | grep 10.231.44.249:5000 | grep ESTABLISHED | more

看下网络队列情况:

参数说明:

  • Send-Q:发送队列中没有被远程主机确认的 bytes 数;

  • Recv-Q:指收到的数据还在缓存中,还没被进程读取,这个值就是还没被进程读取的

  • bytes;一般是CPU处理不过来导致的。

可以看出图中标红列的数据不为 0,通过上面的解释可以判断出是系统 CPU 处理不过来了,但是CPU也没有被充分使用,那为什么会出现这种情况呢。接下我们就该看一下,CPU 在做什么。
这里使用阿里的开源工具 arthas(arthas的安装及使用这里不过多介绍了),看下挡板服务是否存在线程的资源争用或者阻塞等,发现结果如下,存在大量的线程状态为 BLOCKED
命令:thread | grep BLOCKED

 

 命令:thread -b

 

 看到具体的线程栈信息后,问题就比较明显了,是一个写日志的锁导致出现线程阻塞,严重影响系统的处理能力。
为了快速的验证是写日志导致的,调整日志级别为 ERROR,再次发起压力,看问题是否解决,测试结果如下:

 

 调整日志级别后,系统的响应时间保持在 37 ms左右,吞吐量有了大幅度的提升,问题解决。

小结

通过上面的分析案例,需注意以下几点:

  1. 压测时,如果出现请求大量失败时,记住一定要先解决报错,在进行下一步的分析;

  2. 进行性能分析时,一定要找到相应的证据链一步一步的往下分析,而不是盲目的猜测,通过修改参数及加大资源配置来解决问题;

  3. 响应时间长,TPS上不去这种问题,一定要对时间进行拆分拆解,找到时间具体慢在哪里,再进行进一步的分析优化。

 

转自:https://mp.weixin.qq.com/s/Bjjrk85MTTSiHoECNIWEaw

 

 

多学一点:

一、查看当前系统下所有连接状态的数
    netstat -n|awk '/^tcp/{++S[$NF]}END{for (key in S) print key,S[key]}'
    ESTABLISHED 38
    TIME_WAIT 1000
 
二、看下我系统上默认的SYN队列大小
    [root@log]# cat /proc/sys/net/ipv4/tcp_max_syn_backlog 
    262144
    定义SYN队列大小:
    echo 4096 > /proc/sys/net/ipv4/tcp_max_syn_backlog   --定义是php配置的两倍,大于php的就行
 
三、看下我系统上默认的TIME_WAIT队列大小
    cat /proc/sys/net/ipv4/tcp_max_tw_buckets
    1000
    定义TIME_WAIT的大小:
    echo 4096 > /proc/sys/net/ipv4/tcp_max_tw_buckets
 
四、修改backlog参数
    Kernel会为LISTEN状态的socket维护两个队列,一个是SYN RECEIVED状态,另一个是ESTABLISHED状态,而backlog就是这两个队列的大小之和。
    当前Linux版本使用上面说法,有两个队列:具有由系统范围设置指定的大小的SYN队列 和 应用程序(也就是backlog参数)指定的accept队列。
 
五、查看系统默认数量:
    cat /proc/sys/net/core/netdev_max_backlog
    定义队列的数据包的最大数目
    echo "4096"  > /proc/sys/net/core/netdev_max_backlog  #在每个网络接口接收数据包的速率比内核处理这些包的速率快时,允许送到队列的数据包的最大数目。
 
六、nginx 配置参数优化:
    有代理就设置在代理上:没有代理就直接设置在web应用上(或者两个都设置)
    upstream js_sdk {
            #ip_hash;
            server ******* weight=1 max_fails=3 fail_timeout=10s;
            server ******* weight=1 max_fails=3 fail_timeout=10s;
            keepalive 1000;
    }
    
    server {
        listen 80 default backlog=1024;
        listen 443 ssl default backlog=1024;
 
七、php优化:(-1  表示没有使用系统的 backlog )    
    vim /usr/local/php/etc/php-fpm.conf
   
    listen.backlog = 2048   #每一个端口最大的监听队列的长度,需要配置nginx配置文件使用,如下(暂时只更改这里)
 
八、linux内核参进行优化:
    vim /etc/sysctl.conf
    
     net.ipv4.tcp_syncookies = 1
     net.ipv4.tcp_max_syn_backlog = 4096  #对于还未获得对方确认的连接请求,可保存在队列中的最大数目。如果服务器经常出现过载,可以尝试增加这个数字。
     net.core.somaxconn = 4096   #定义了系统中每一个端口最大的监听队列的长度,这是个全局的参数。backlog需要设置这个
 
    使用命令使之生效:sysctl -p
 

转自:https://blog.csdn.net/u010917150/article/details/95621873

与[转帖]性能分析之TCP全连接队列占满问题分析及优化过程相似的内容:

[转帖]性能分析之TCP全连接队列占满问题分析及优化过程(转载)

https://cloud.tencent.com/developer/article/1420726 前言 在对一个挡板系统进行测试时,遇到一个由于TCP全连接队列被占满而影响系统性能的问题,这里记录下如何进行分析及解决的。 理解下TCP建立连接过程与队列 从图中明显可以看出建立 TCP 连接的时

[转帖]性能分析之TCP全连接队列占满问题分析及优化过程

https://www.cnblogs.com/wx170119/p/12068005.html 前言 在对一个挡板系统进行测试时,遇到一个由于TCP全连接队列被占满而影响系统性能的问题,这里记录下如何进行分析及解决的。 理解下TCP建立连接过程与队列 从图中明显可以看出建立 TCP 连接的时候,有

[转帖]性能分析之TCP全连接队列占满问题分析及优化过程(转载)

https://www.cnblogs.com/wx170119/p/12068005.html 前言 在对一个挡板系统进行测试时,遇到一个由于TCP全连接队列被占满而影响系统性能的问题,这里记录下如何进行分析及解决的。 理解下TCP建立连接过程与队列 从图中明显可以看出建立 TCP 连接的时候,有

[转帖]《Linux性能优化实战》笔记(22)—— 网络丢包问题分析

所谓丢包,是指在网络数据的收发过程中,由于种种原因,数据包还没传输到应用程序中,就被丢弃了。这些被丢弃包的数量,除以总的传输包数,也就是我们常说的丢包率。丢包率是网络性能中最核心的指标之一。丢包通常会带来严重的性能下降,特别是对 TCP 来说,丢包通常意味着网络拥塞和重传,进而还会导致网络延迟增大、

[转帖]从性能问题定位,扯到性能模型,再到 TCP - 都微服务云原生了,还学 TCP 干嘛系列 Part 1

https://blog.mygraphql.com/zh/posts/low-tec/network/tcp-flow-control-part1/ 引 本来想直接写理论、和实践分析的,但为了不 “赶客出門” 和不 TL;DR,还是以故事形式展开吧。语言要生动活泼。 故事的开始 话说,一次性能测试

[转帖]java性能分析之火焰图

http://t.zoukankan.com/lemon-le-p-13820204.html 原由 最近因为kafka、zookeeper、ES和相关的Java应用的内存问题搞的头大,做运维将近4年,对Java调优、性能方面的知识了解的少之又少,是时候下定决心来对他多一个学习了。不能一口吃成一个胖

[转帖]MySQL索引优化分析之性能分析(Explain执行计划)

一、MySQL常见瓶颈 二、性能分析工具Explain(执行计划 ) 使用EXPLAIN关键字可以模拟优化器执行SQL查询语句,从而知道MySQL是如何处理你的SQL语句的。分析你的查询语句或是表结构的性能瓶颈。查看官网说明: 使用: Explain + SQL语句 作用: 三、各字段解释 3.1、

[转帖]性能之内存篇

http://www.manongjc.com/detail/62-xzlnozethfhhibi.html 本文章向大家介绍性能之内存篇,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。 最近笔者在看性能分析相关的是知识,就特意针对内存整

[转帖]systemtap - perf - 火焰图

https://www.cnblogs.com/hixiaowei/p/15580662.html 0. 火焰图生成框架 1. Capture stacks 2. Fold stacks 3. flamegraph.pl 1. perf (13条消息) 性能分析之profiling及火焰图_巷中人的

[转帖]linux 系统级性能分析工具 perf 的介绍与使用

目录 1. 背景知识 1.1 tracepoints 1.2 硬件特性之cache 2. 主要关注点 3. perf的使用 3.0 perf引入的overhead 3.1 perf list 3.2 perf top 3.3 perf stat 3.4 perf bench 3.4.1 perf b