架构师

一次HTTP connect-timeout的排查(上)

2019-07-17  本文已影响0人  小菜Yang

问题描述

公司的支付系统,支付核心调用网关系统时候,Tomcat接口服务偶尔会出现连接超时,以下为问题现象:

  1. 出现连接超时的时间点,该机器仍有正常的请求到网关系统,只是部分请求异常
  2. 偶发性质,一天或2天一次,且出现连接超时的时间段比较短暂
image.png

初步排查分析

  1. JVM GC情况:正常,分析GC日志,在发生连接超时时间段,系统只发生过几次YGC,每次STW时间在0.02 sec 左右
  2. 系统资源:CPU、I/O、磁盘使用率和平常一样,无异常
  3. Tomcat 线程数:在出现连接超时的时间段,活动线程数增长了100多个,当仍远低于1500最大工作线程数。
  4. 检查网络,发下在出现连接超时的时间段,TCP全连接队列发生了溢出


    image.png

    PS:只是临时找了个类似的图,当时时间的溢出图没找着

基于以上分析,初步怀疑是TCP全连接队列溢出导致出现了客户端连接超时的情况
接着查看溢出后,OS怎么处理:

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

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

接着检查服务端的全连接队列长度,发现仅为100。 而出现连接超时情况时,全连接队列已经堆积了超过100个请求

采用ss -lnt | grep {server_port} 查看
[root@localhost ~]# ss -lnt | grep 10007
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 100 :::10007 :::*

解释一下上诉Recv-Q Send-Q的含义:

检查tomcat的配置的backlog,确实默认的是100,关键代码如下:

   NioEndpoint.java
   serverSock.socket().bind(addr,getAcceptCount());
   /**
     * Allows the server developer to specify the acceptCount (backlog) that
     * should be used for server sockets. By default, this value
     * is 100.
     */
    private int acceptCount = 100;
    public void setAcceptCount(int acceptCount) { if (acceptCount > 0) this.acceptCount = acceptCount; }
    public int getAcceptCount() { return acceptCount; }

测试模拟

经过上诉分析,已经初步怀疑是由于tomcat backlog配置过小导致的客户端出现连接超时,在测试环境进行模拟(系统TCP相关参数与生产环境一致)

-Dserver.tomcat.accept-count=1
    @ResponseBody
    @RequestMapping("/tomcatTest/{sleepSeconds}")
    public String testSMS(@PathVariable("sleepSeconds") long sleepMS) {
        try {
            TimeUnit.SECONDS.sleep(sleepMS);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "OK";
    }

并发10个http请求(连接超时时间配置为3s,服务端处理时长为10s),出现3个连接超时的情况

第3次异常:I/O error on GET request for "http://xxxx:19966/tomcatTest/10": connect timed out; nested exception is java.net.SocketTimeoutException: connect timed out exec: 3001
第5次异常:I/O error on GET request for "http://xxxx:19966/tomcatTest/10": connect timed out; nested exception is java.net.SocketTimeoutException: connect timed out exec: 3001
第4次异常:I/O error on GET request for "http://xxxx:19966/tomcatTest/10": connect timed out; nested exception is java.net.SocketTimeoutException: connect timed out exec: 3003
第0次正常 exec: 10020
第1次正常 exec: 10019
第7次正常 exec: 10018
第2次正常 exec: 10023
第9次正常 exec: 10020
第8次正常 exec: 10022
第6次正常 exec: 10327

在执行期间观察全连接队列情况,确实有出现溢出

netstat -s | grep -i "listen"
366 times the listen queue of a socket overflowed
366 SYNs to LISTEN sockets ignored

netstat -s | grep -i "listen"
368 times the listen queue of a socket overflowed
368 SYNs to LISTEN sockets ignored

将tomcat backlog调大后,在继续压测,没有在出现连接超时的情况。
依此测试结果,将线上的tomcat backlog增大至500后,观察一周均无在出现connect timeout的情况。

未完待续

上一篇 下一篇

猜你喜欢

热点阅读