记一次TCP TIME_WAIT引发的血案

前言

记录线上一次故障,状态延迟,状态使用短连接,长轮训的方式获取,在每天的固定时间点,出现状态延迟,持续几分钟,然后又莫名其妙的恢复了,很是怪异,下面就来复盘下,这次问题的定位和思考。

冰山一角

我们可以掌握的线索有 1.固定的时间点,发生。2.通过监控可以看到,流量并不高,但是TCP TIMEWAIT一瞬间疯涨 3.出问题的时间点,远程客户的电脑(全内网),ping网关和服务器,发现有大量延时 4.有同事通过jstat看,发现gc的次数很多,认为gc导致了接口延时。5.接口超时的时间点,CPU不高,内存不高,I/O不高,系统负载不高,也就是未达到机器的性能瓶颈。机器配置16核64g

软件版本:

操作系统 centos7.9JDK 1.6nginx7.7

由于,这个问题牵涉的大客户,很多技术人员,投入进来一起攻破,每个人的想法不一致,导致问题更难以统一突破。

一部分人,认为是网络问题,和某为扯了半天,没有个所以然 一部分人,认为gc太频繁,full gc次数太多了,所以需要gc调优 一部分人,认为需要在测试环境,压测,测试出系统瓶颈

实施的方案

抛开以上的言论,我们回到线索上 

1、每天固定时间出现,询问客户,这个时间段是否是业务高峰期。回答:是 

2、从监控来看,TCP-TIMEWAIT高,那我们就要先定位到系统部署方案。

系统部署方案如下 1.nginx反向代理java服务。nginx监听443端口 java服务监听8080端口

每一次轮训,发起http请求,通过nginx,nginx请求java服务

查看8080端口的tcp端口timewait个数,发现全是timewait,现在可以确定的是nginx和tcp连接出现了大量的timewait,导致接口延时。

翻了运维的调优记录如下:

根据监控看,丢弃的连接数比较多

修改后| 当前情况| 说明| |--|--|--| | net.core.netdev_max_backlog = 16384 |net.core.netdev_max_backlog = 1000 |系统建立全链接队列长度(TCP三次握手成功后的连接放入队列) | | net.ipv4.tcp_max_syn_backlog = 8192|net.ipv4.tcp_max_syn_backlog = 512 |系统建立半链接队列长度(TCP三次握手过程中的连接放入队列) | | net.core.somaxconn = 4096 |net.core.somaxconn = 128 |系统建立全链接队列(TCP三次握手成功后的连接放入队列 系统级别的 |

TCP 建立连接时要经过 3 次握手,在客户端向服务器发起连接时,对于服务器而言,一个完整的连接建立过程,服务器会经历 2 种 TCP 状态:SYN_REVD, ESTABELLISHED

对应也会维护两个队列:

一个存放 SYN 的队列(半连接队列) 一个存放已经完成连接的队列(全连接队列)

ESTABLISHED列长度如何计算?

如果 backlog 大于内核参数 net.core.somaxconn,则以 net.core.somaxconn 为准,

即全连接队列长度 = min(backlog, 内核参数 net.core.somaxconn),net.core.somaxconn 默认为 128。

这个很好理解,net.core.somaxconn 定义了系统级别的全连接队列最大长度,

backlog 只是应用层传入的参数,不可能超过内核参数,所以 backlog 必须小于等于 net.core.somaxconn。

SYN_RECV队列长度如何计算?

半连接队列长度由内核参数 tcp_max_syn_backlog 决定,

当使用 SYN Cookie 时(就是内核参数 net.ipv4.tcp_syncookies = 1),这个参数无效,

半连接队列的最大长度为 backlog、内核参数 net.core.somaxconn、内核参数 tcp_max_syn_backlog 的最小值。

即半连接队列长度 = min(backlog, 内核参数 net.core.somaxconn,内核参数 tcp_max_syn_backlog)。

这个公式实际上规定半连接队列长度不能超过全连接队列长度,但是tcp_syncooking默认是启用的,如果按上文的理解,那这个参数设置没有多大意义

其实,对于 Nginx/Tomcat 等这种 Web 服务器,都提供了 backlog 参数设置入口,当然它们都会有默认值,通常这个默认值都不会太大(包括内核默认的半连接队列和全连接队列长度)。如果应用并发访问非常高,只增大应用层 backlog 是没有意义的,因为可能内核参数关于连接队列设置的都很小,一定要综合应用层 backlog 和内核参数一起看,通过公式很容易调整出正确的设置

nginx调优 nginx到java建立的连接Timewait比较大,优化nginx配置,降低握手次数。

    upstream node {
server 127.0.0.1:8080;
keepalive 10000; //新增
keepalive_timeout 65s; //新增
keepalive_requests 20000; //新增
}

从以上记录看,似乎都和TCP连接数有关。解决思路如下:

1.长轮训 短连接改为websocket方案 评估:不确定因素太多,客户要限时解决问题,不敢上线 2.降低tcp 连接数,根据业务拆分,降低请求量。3.控制timewait数量,保证业务高峰期不会发生太大的抖动 4.询问业务人员,请求会分配到一个线程的处理,并且没有限制线程数量,所以如果请求量很大,应该会有很多线程,并且cpu应该有很高的使用量,而现在cpu的使用量很低,不太正常。使用jstack打印线程情况

实施

找到运维沟通,tcp的连接数设置高点。然而被告知最多只能创建65535个。这个问题我们稍后在细聊下。

控制TCP TIMEWAIT的数量,设置参数

net.ipv4.tcp_max_tw_buckets=1024

jstack打印线程池,发现有很多线程在等待同一个锁。锁是使用synchronized关键字,锁的是HashTable一个数组,锁的代码逻辑,处理比较长。优化:拆分锁的逻辑,不需要一致性的数据踢出去。

后记

一台机器最多能创建多少个TCP连接?

上面的截图中,tcp timewait的个数太多,到了65535限制,导致连接被重置,那为什么有这个结论呢 注意看上面的nginx配置

    upstream node {
server 127.0.0.1:8080;
keepalive 10000; //新增
keepalive_timeout 65s; //新增
keepalive_requests 20000; //新增
}

这里指定了去连接127.0.0.1的8080端口,那么nginx去连接java服务的时候如下:| 源ip| 源端口 |目标ip |目标端口 | |--|--|--|--| | 127.0.0.1|20000 |127.0.0.1 |8080 | | 127.0.0.1|20001 |127.0.0.1 |8080 | | 127.0.0.1|20002 |127.0.0.1 |8080 |

所以为什么会说一个机器上最多65535个端口数。这个端口号16位的,可以有0~65535端口数是针对单个ip来描述的,那我们在机器上可不是只有一个ip,所以理论上端口数是无上限的,配置nginx的时候这里需要注意上。

端口号的上限不一定是65535 如果你有幸见过cannot assign requested address 那么你一定知道 Linux对可使用的范围端口有具体限制,使用以下命令查看

cat /proc/sys/net/ipv4/ip_local_port_range 
1024 65000

文件描述符 Linux 下一切皆文件 我们突破tcp端口限制的时候,很可能会遇到以下错误too many open files

每建立一个TCP连接,会分配一个文件描述符,linux 对可打开的文件描述符的数量分别作了三个方面的限制。

系统级:当前系统可打开的最大数量,通过 cat /proc/sys/fs/file-max 查看

用户级:指定用户可打开的最大数量,通过 cat /etc/security/limits.conf 查看

进程级:单个进程可打开的最大数量,通过 cat /proc/sys/fs/nr_open 查看

C10K 每创建一个TCP连接,操作系统都需要消耗一个线程,当我们TCP连接数过多,会导致线程不停的上下文切换,导致cpu处理时间越来越长。C10K就是早期单机性能的瓶颈代名词。所以后续有了 I/O多路复用模型。

何时进行JVM调优?

还记得上面说过,通过jstat看到gc很频繁,full gc次数很多,所以建议GC调优吗?

我们看关键指标

YGC 59085 Young GC次数 
YGCT 318.142 Young 总时间 单位秒
FGC 407 Full GC 次数
FGCT 75.310 Full GC 总时间,单位为妙
我们看平均时间
年轻代平均gc时间
318.142/59085=0.0005
- 老年代平均gc时间
75.310/407=0.185

我们可以看到GC的次数很多,但是GC的平均时间并不高。

但是这并不是万能的

有一种情况比如Full GC发生了10次,平均值不高,但是某几次的Full GC时间为5~6秒,所以为了更确定这个问题,我们可以使用启动参数,查看每次GC的时间。

-verbose:gc -XX:+PrintGCTimeStamps -XX:+PrintGCDetails -Xloggc:./gc.log

查看当天gc日志,Full gc时间并不高,可以排除,GC引起的问题。

所有的优化,GC调优应该是最后的手段,更多的是优化我们的代码。

本文使用 文章同步助手 同步

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容

  • 参数文件位置:/proc/sys/net/ipv4/ 参数文件位置 /proc/sys/net/ipv4/net...
    杀破魂阅读 1,292评论 0 0
  • nginx优化 突破十万并发 一、一般来说nginx 配置文件中对优化比较有作用的为以下几项: worker_pr...
    SkTj阅读 963评论 0 4
  • nginx的安装与基本配置文档网上已经有很多了,但具体讲优化的文章还比较少,偶尔发现有这么一篇《nginx优化 突...
    yichen_china阅读 8,691评论 0 65
  • client_body_buffer_size 1m; //请求体缓冲区大小(post大的要设置)client_m...
    SkTj阅读 444评论 0 6
  • 本篇内容:集群、负载均衡、安全相关 一、集群与负载均衡 1.1 集群简介 粗暴理解集群就是多个nginx同时协作使...
    莫须有的呓语阅读 249评论 1 0