Linux 从4.12内核版本开始移除了 tcp_tw_recycle 配置。 tcp_max_tw_buckets TIME-WAIT 稳定值
被抛弃的tcp_recycle_小米云技术-CSDN博客_sysctl: cannot stat /proc/sys/net/ipv4/tcp_tw_recy https://blog.csdn.net/pengzhouzhou/article/details/85229437
1、背景
最近准备搭建一个新的kubernetes集群,将内核从3.18更新到了4.14版本,并执行一些常规的优化操作。在执行sysctl -p操作时突然报错如下:
sysctl: cannot stat /proc/sys/net/ipv4/tcp_tw_recycle: No such file or directory
2、问题原因
Linux 从4.12内核版本开始移除了 tcp_tw_recycle 配置。
参考:[1]tcp:remove tcp_tw_recycle 4396e460
移除sysctl.conf中关于net.ipv4.tcp_tw_recycle的配置内容,再次尝试sysctl -p就不再提示报错了。
3、深入解析
tcp_tw_recycle通常会和tcp_tw_reuse参数一起使用,用于解决服务器TIME_WAIT状态连接过多的问题。
3.1、TIME_WAIT状态出现原因与查看
让我们回顾一下四次挥手的流程:
TIME_WAIT永远是出现在主动发送断开连接请求的一方(下文中我们称之为客户),划重点:这一点面试的时候经常会被问到。
客户在收到服务器端发送的FIN(表示"我们也要断开连接了")后发送ACK报文,并且进入TIME_WAIT状态,等待2MSL(MaximumSegmentLifetime 最大报文生存时间)。对于Linux,字段为TCP_TIMEWAIT_LEN硬编码为30秒,对于windows为2分钟(可自行调整)。
为什么客户端不直接进入CLOSED状态,而是要在TIME_WAIT等待那么久呢,基于如下考虑:
1.确保远程端处于关闭状态。也就是说需要确保客户端发出的最后一个ACK报文能够到达服务器。由于网络不可靠,有可能最后一个ACK报文丢失,如果服务器没有收到客户端的ACK,则会重新发送FIN报文,客户端就可以在2MSL时间段内收到这个这个重发的报文,并且重发ACK报文。但如果客户端跳过TIME_WAIT阶段进入了CLOSED,服务端始终无法得到响应,就会处于LAST-ACK状态,此时假如客户端发起了一个新连接,则会以失败告终。
异常流程如下:
2.防止上一次连接中的包,迷路后重新出现,影响新连接(经过2MSL,上一次连接中所有的重复包都会消失),这一点和为啥要执行三次握手而不是两次的原因是一样的。
异常流程如下:
查看方式有两种:
(1)ss -tan state time-wait|wc -l
(2)netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'
3.2、TIME_WAIT的危害
对于一个处理大量连接的处理器TIME_WAIT是有危害的,表现如下:
1.占用连接资源
TIME_WAIT占用的1分钟时间内,相同四元组(源地址,源端口,目标地址,目标端口)的连接无法创建,通常一个ip可以开启的端口为net.ipv4.ip_local_port_range指定的32768-61000,如果TIME_WAIT状态过多,会导致无法创建新连接。
2.占用内存资源
这个占用资源并不是很多,可以不用担心。
3.3、TIME_WAIT的解决
可以考虑如下方式:
1.修改为长连接,代价较大,长连接对服务器性能有影响。
2.增加可用端口范围(修改net.ipv4.ip_local_port_range); 增加服务端口,比如采用80,81等多个端口提供服务; 增加客户端ip(适用于负载均衡,比如nginx,采用多个ip连接后端服务器); 增加服务端ip; 这些方式治标不治本,只能缓解问题。
3.将net.ipv4.tcp_max_tw_buckets设置为很小的值(默认是18000). 当TIME_WAIT连接数量达到给定的值时,所有的TIME_WAIT连接会被立刻清除,并打印警告信息。但这种粗暴的清理掉所有的连接,意味着有些连接并没有成功等待2MSL,就会造成通讯异常。
4.修改TCP_TIMEWAIT_LEN值,减少等待时间,但这个需要修改内核并重新编译。
5.打开tcp_tw_recycle和tcp_timestamps选项。
6.打开tcp_tw_reuse和tcp_timestamps选项。
3.4、net.ipv4.tcp_tw_{reuse,recycle}
需要明确两个点:
解决方式已经给出,那我们需要了解一下net.ipv4.tcp_tw_reuse和net.ipv4.tcp_tw_recycle有啥区别
1.两个选项都需要打开对TCP时间戳的支持,即net.ipv4.tcp_timestamps=1(默认即为1)。
RFC 1323中实现了TCP拓展规范,以便保证网络繁忙的情况下的高可用。并定义了一个新的TCP选项-两个四字节的timestamp字段,第一个是TCP发送方的当前时钟时间戳,第二个是从远程主机接收到的最新时间戳。
2.两个选项默认都是关闭状态,即等于0。
3.4.1 - net.ipv4.tcp_tw_reuse:更安全的设置
将处于TIME_WAIT状态的socket用于新的TCP连接,影响连出的连接。
[2]kernel sysctl 官方指南中是这么写的:
Allow to reuse TIME-WAIT sockets for new connections when it is safe from protocol viewpoint. Default value is 0.
It should not be changed without advice/request of technical experts.
协议安全主要指的是两点:
1.只适用于客户端(连接发起方)
net/ipv4/inet_hashtables.c
- static int __inet_check_established(struct inet_timewait_death_row *death_row,
- struct sock *sk, __u16 lport,
- struct inet_timewait_sock **twp)
- {
- /* ……省略…… */
- sk_nulls_for_each(sk2, node, &head->chain) {
- if (sk2->sk_hash != hash)
- continue;
- if (likely(INET_MATCH(sk2, net, acookie,
- saddr, daddr, ports, dif))) {
- if (sk2->sk_state == TCP_TIME_WAIT) {
- tw = inet_twsk(sk2);
- if (twsk_unique(sk, sk2, twp))
- break;
- }
- goto not_unique;
- }
- }
- /* ……省略…… */
- }
2.TIME_WAIT创建时间超过1秒才可以被复用
net/ipv4/tcp_ipv4.c
- int tcp_twsk_unique(struct sock *sk, struct sock *sktw, void *twp)
- {
- /* ……省略…… */
- if (tcptw->tw_ts_recent_stamp &&
- (!twp || (sock_net(sk)->ipv4.sysctl_tcp_tw_reuse &&
- get_seconds() - tcptw->tw_ts_recent_stamp > 1))) {
- /* ……省略…… */
- return 1;
- }
- return 0;
- }
满足以上两个条件才会被认为是"safe from protocol viewpoint"的状况。启用net.ipv4.tcp_tw_reuse后,如果新的时间戳比之前存储的时间戳更大,那么Linux将会从TIME-WAIT状态的存活连接中选取一个,重新分配给新的连接出去的的TCP连接,这种情况下,TIME-WAIT的连接相当于只需要1秒就可以被复用了。
重新回顾为什么要引入TIME-WAIT:
第一个作用就是避免新连接接收到重复的数据包,由于使用了时间戳,重复的数据包会因为时间戳过期被丢弃。
第二个作用是确保远端不是处于LAST-ACK状态,如果ACK包丢失,远端没有成功获取到最后一个ACK包,则会重发FIN包。直到:
1.放弃(连接断开)
2.收到ACK包
3.收到RST包
如果FIN包被及时接收到,并且本地端仍然是TIME-WAIT状态,那ACK包会被发送,此时就是正常的四次挥手流程。
如果TIME-WAIT的条目已经被新连接所复用,则新连接的SYN包会被忽略掉,并且会收到FIN包的重传,本地会回复一个RST包(因为此时本地连接为SYN-SENT状态),这会让远程端跳出LAST-ACK状态,最初的SYN包也会在1秒后重新发送,然后完成连接的建立,整个过程不会中断,只是有轻微的延迟。流程如下:
需要注意,连接被复用后,TWrecycled计数器会增加(/proc/net/netstat中TWrecycled值)
3.4.2 - net.ipv4.tcp_tw_recycle:更激进的设置
启用TIME_WAIT 状态的sockets的快速回收,影响所有连入和连出的连接
[3]kernel sysctl 官方指南 是这么写的
Enable fast recycling TIME-WAIT sockets. Default value is 0. It should not be changed without advice/request of technical experts.
这次表述的更加模糊,继续翻看源码:
net/ipv4/tcp_input.c
- int tcp_conn_request(struct request_sock_ops *rsk_ops,
- const struct tcp_request_sock_ops *af_ops,
- struct sock *sk, struct sk_buff *skb)
- {
- /* ……省略…… */
- if (!want_cookie && !isn) {
- /* ……省略…… */
- if (net->ipv4.tcp_death_row.sysctl_tw_recycle) {
- bool strict;
- dst = af_ops->route_req(sk, &fl, req, &strict);
- if (dst && strict &&
- !tcp_peer_is_proven(req, dst, true,
- tmp_opt.saw_tstamp)) {
- NET_INC_STATS(sock_net(sk), LINUX_MIB_PAWSPASSIVEREJECTED);
- goto drop_and_release;
- }
- }
- /* ……省略…… */
- isn = af_ops->init_seq(skb, &tcp_rsk(req)->ts_off);
- }
- /* ……省略…… */
- drop_and_release:
- dst_release(dst);
- drop_and_free:
- reqsk_free(req);
- drop:
- tcp_listendrop(sk);
- return 0;
- }
简单来说就是,Linux会丢弃所有来自远端的timestramp时间戳小于上次记录的时间戳(由同一个远端发送的)的任何数据包。也就是说要使用该选项,则必须保证数据包的时间戳是单调递增的。
问题在于,此处的时间戳并不是我们通常意义上面的绝对时间,而是一个相对时间。很多情况下,我们是没法保证时间戳单调递增的,比如使用了nat,lvs等情况。
而这也是很多优化文章中并没有提及的一点,大部分文章都是简单的推荐将net.ipv4.tcp_tw_recycle设置为1,却忽略了该选项的局限性,最终造成严重的后果(比如我们之前就遇到过部署在nat后端的业务网站有的用户访问没有问题,但有的用户就是打不开网页)。
3.5、被抛弃的tcp_tw_recycle
如果说之前内核中tcp_tw_recycle仅仅不适用于nat和lvs环境,那么从4.10内核开始,官方修改了时间戳的生成机制。
参考:[4] tcp: randomize tcp timestamp offsets for each connection 95a22ca
在这种情况下,无论任何时候,tcp_tw_recycle都不应该开启。故被抛弃也是理所应当的了。
4、总结
tcp_tw_recycle 选项在4.10内核之前还只是不适用于NAT/LB的情况(其他情况下,我们也非常不推荐开启该选项),但4.10内核后彻底没有了用武之地,并且在4.12内核中被移除.
tcp_tw_reuse 选项仍然可用。在服务器上面,启用该选项对于连入的TCP连接来说不起作用,但是对于客户端(比如服务器上面某个服务以客户端形式运行,比如nginx反向代理)等是一个可以考虑的方案。
修改TCP_TIMEWAIT_LEN是非常不建议的行为。
5、参考链接
[1]https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=4396e46187ca5070219b81773c4e65088dac50cc
[2]https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/networking/ip-sysctl.txt?h=v4.11#n648
[3]https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/networking/ip-sysctl.txt?h=v4.11#n643
[4]https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=95a22caee396cef0bb2ca8fafdd82966a49367bb
[5]Coping with the TCP TIME-WAIT state on busy Linux servers:https://vincent.bernat.ch/en/blog/2014-tcp-time-wait-state-linux
[6]net.ipv4.tcp_tw_recycle は廃止されました ― その危険性を理解する:https://qiita.com/tmshn/items/b49f1b51bfc472968b30
[7]tcp_tw_reuse、tcp_tw_recycle 使用场景及注意事项:https://www.cnblogs.com/lulu/p/4149312.html
本文首发于公众号“小米运维”,点击查看原文。
net.ipv4.tcp_max_tw_buckets
TIME-WAIT 稳定至指定值
(base) root@sit:~# ss -atp
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 511 0.0.0.0:https 0.0.0.0:* users:(("nginx",pid=5808,fd=9),("nginx",pid=5807,fd=9),("nginx",pid=1485,fd=9))
LISTEN 0 1024 0.0.0.0:ldap 0.0.0.0:* users:(("slapd",pid=1265,fd=8))
LISTEN 0 128 0.0.0.0:6000 0.0.0.0:* users:(("python3",pid=3926,fd=5))
LISTEN 0 511 0.0.0.0:http 0.0.0.0:* users:(("nginx",pid=5808,fd=10),("nginx",pid=5807,fd=10),("nginx",pid=1485,fd=10))
LISTEN 0 50 0.0.0.0:8080 0.0.0.0:* users:(("java",pid=1331,fd=147))
LISTEN 0 128 127.0.0.53%lo:domain 0.0.0.0:* users:(("systemd-resolve",pid=423,fd=13))
LISTEN 0 128 0.0.0.0:ssh 0.0.0.0:* users:(("sshd",pid=1018,fd=3))
ESTAB 0 0 192.168.0.133:https 121.35.102.243:33515 users:(("nginx",pid=5807,fd=19))
TIME-WAIT 0 0 127.0.0.1:31126 127.0.0.1:25001
ESTAB 0 0 192.168.0.133:36390 100.100.27.15:3128 users:(("exe",pid=771,fd=5))
ESTAB 0 0 127.0.0.1:44230 127.0.0.1:25000 users:(("nginx",pid=5807,fd=21))
ESTAB 0 0 192.168.0.133:https 121.35.102.243:33348 users:(("nginx",pid=5807,fd=4))
TIME-WAIT 0 0 172.17.0.1:34092 172.17.0.3:5000
ESTAB 0 0 172.17.0.1:55194 172.17.0.2:5000 users:(("docker-proxy",pid=30859,fd=25))
ESTAB 0 0 192.168.0.133:https 121.35.102.243:33503 users:(("nginx",pid=5807,fd=8))
TIME-WAIT 0 0 172.17.0.1:56484 172.17.0.2:5000
TIME-WAIT 0 0 172.17.0.1:54188 172.17.0.4:5000
ESTAB 0 36 192.168.0.133:ssh 121.35.102.243:33769 users:(("sshd",pid=30622,fd=3))
ESTAB 0 0 192.168.0.133:https 121.35.102.243:30059 users:(("nginx",pid=5807,fd=22))
ESTAB 0 0 127.0.0.1:43168 127.0.0.1:25000 users:(("nginx",pid=5807,fd=5))
TIME-WAIT 0 0 172.17.0.1:34110 172.17.0.3:5000
ESTAB 0 0 172.17.0.1:54132 172.17.0.2:5000 users:(("docker-proxy",pid=30859,fd=13))
ESTAB 0 0 127.0.0.1:43162 127.0.0.1:25000 users:(("nginx",pid=5807,fd=18))
ESTAB 0 0 172.17.0.1:54144 172.17.0.2:5000 users:(("docker-proxy",pid=30859,fd=19))
ESTAB 0 0 192.168.0.133:https 121.35.102.243:31215 users:(("nginx",pid=5807,fd=17))
ESTAB 0 0 192.168.0.133:https 121.35.102.243:30061 users:(("nginx",pid=5807,fd=24))
TIME-WAIT 0 0 172.17.0.1:33966 172.17.0.3:5000
ESTAB 0 0 192.168.0.133:46810 100.100.30.26:http users:(("AliYunDun",pid=860,fd=17))
TIME-WAIT 0 0 172.17.0.1:55992 172.17.0.2:5000
ESTAB 0 0 172.17.0.1:54126 172.17.0.2:5000 users:(("docker-proxy",pid=30859,fd=5))
TIME-WAIT 0 0 172.17.0.1:34056 172.17.0.3:5000
ESTAB 0 0 192.168.0.133:15770 104.16.22.35:https users:(("node",pid=25216,fd=18))
ESTAB 0 0 127.0.0.1:43180 127.0.0.1:25000 users:(("nginx",pid=5807,fd=20))
LISTEN 0 1024 [::]:ldap [::]:* users:(("slapd",pid=1265,fd=9))
LISTEN 0 65535 *:4999 *:* users:(("docker-proxy",pid=2243,fd=4))
LISTEN 0 65535 *:25000 *:* users:(("docker-proxy",pid=30859,fd=4))
LISTEN 0 65535 *:25001 *:* users:(("docker-proxy",pid=31336,fd=4))
LISTEN 0 65535 *:25002 *:* users:(("docker-proxy",pid=31557,fd=4))
LISTEN 0 80 *:3306 *:* users:(("mysqld",pid=856,fd=29))
LISTEN 0 128 [::]:6000 [::]:* users:(("python3",pid=3926,fd=6))
ESTAB 0 0 [::ffff:127.0.0.1]:25000 [::ffff:127.0.0.1]:43168 users:(("docker-proxy",pid=30859,fd=12))
ESTAB 0 0 [::ffff:127.0.0.1]:25000 [::ffff:127.0.0.1]:44230 users:(("docker-proxy",pid=30859,fd=24))
ESTAB 0 0 [::ffff:127.0.0.1]:25000 [::ffff:127.0.0.1]:43162 users:(("docker-proxy",pid=30859,fd=3))
ESTAB 0 0 [::ffff:127.0.0.1]:25000 [::ffff:127.0.0.1]:43180 users:(("docker-proxy",pid=30859,fd=18))
(base) root@sit:~#
(base) root@sit:~#
(base) root@sit:~# sysctl -p
vm.swappiness = 0
net.ipv4.neigh.default.gc_stale_time = 120
net.ipv4.conf.all.rp_filter = 0
net.ipv4.conf.default.rp_filter = 0
net.ipv4.conf.default.arp_announce = 2
net.ipv4.conf.lo.arp_announce = 2
net.ipv4.conf.all.arp_announce = 2
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_synack_retries = 2
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
net.ipv6.conf.lo.disable_ipv6 = 1
net.ipv6.conf.eth0.disable_ipv6 = 1
kernel.sysrq = 1
net.core.somaxconn = 65535
net.ipv4.tcp_fin_timeout = 2
net.ipv4.ip_local_port_range = 1024 65535
net.ipv4.tcp_max_tw_buckets = 8
Linux 从4.12内核版本开始移除了 tcp_tw_recycle 配置。 tcp_max_tw_buckets TIME-WAIT 稳定值的更多相关文章
- 【原创】Linux基础之查看linux发行版以及内核版本
redhat查看发行版 # cat /etc/redhat-release CentOS Linux release 7.2.1511 (Core) 查看内核版本 # uname -aLinux $h ...
- linux系统如何查看内核版本、操作系统版本等信息
有时候需要查看linux系统的内核版本,可以有多种方法,方法如下:(下面以优麒麟系统为例) 方法1: 打开mate终端,在命令行输入以下命令: uname -a 运行效果如下: 如果只查看内核 ...
- Linux发行版和内核版本
1./etc/issue 和 /etc/redhat-release都是系统安装时默认的发行版本信息,通常安装好系统后文件内容不会发生变化. 2.lsb_release -a :FSG(Free St ...
- 查看Linux内核版本
您可能因多种原因需要确切知道GNU / Linux操作系统上运行的内核版本. 也许您正在调试与硬件相关的问题,或者了解影响旧内核版本的新安全漏洞,并且您想知道您的内核是否易受攻击. 无论是什么原因,从 ...
- Linux 内核版本命名
Linux 内核版本命名在不同的时期有其不同的规范,我们熟悉的也许是 2.x 版本奇数表示开发版.偶数表示稳定版,但到 2.6.x 以及 3.x 甚至将来的 4.x ,内核版本命名都不遵守这样的约定. ...
- linux查看内核版本、系统版本、系统位数(32or64)
linux查看内核版本.系统版本.系统位数(32or64) 2011-05-01 22:05:12 标签:linux 内核版本 休闲 系统版本 系统位数 1. 查看内核版本命令: 1) [root@ ...
- Linux系统中查询发行版本号以及内核版本的命令总结
了解Linux发行版本的版本号是一项非常重要的事情,大多数软件对系统的版本都有要求,发行版本号与软件不匹配,软件将无法安装或者无法使用.这边集合市面上流行的Linux发行版本版本号查询方法.有了这边文 ...
- 升级Centos 7/6内核版本到4.12.4的方法
一.查看那系统内核版本 二.升级内核 三.修改grub中默认的内核版本 四.重启系统并查看系统内核 公司打算上Docker服务,目前需要安装运行环境,Docker新的功能除了需要Centos 7系统之 ...
- 转: linux内核版本本地版本号的检查——setlocalversion
转载:http://blog.csdn.net/adaptiver/article/details/7225980 1. 引子 编译2.6.35.7 kernel版本的时候发现,"2.6 ...
随机推荐
- Failed to process, please exclude the tableName or statementId.--Mybatis-Plus
多租户多个用户间使用同一套程序,但每个用户之间实现数据隔离 方法一:在 Mapper 的自定义方法上添加注解 @SqlParser(filter = true),在查询的时候不需要添加租户信息 @Sq ...
- junit 测试用例多并发
最近再用测试用例写个多并发,但是测试用例一运行完程序就结束啦.还没有等到多线程运行完.这个时候可以用断点在多线程后面停住或者让主线程睡眠多一些
- 入门oj 6451: The XOR Largest Pair之二
Description 今天小W用了1s不到的时候完成了这样一个题:在给定的N个整数 A_1,A_2,-,A_N中选出两个进行异或运算,得到的结果最大是多少?正当他志得意满时,L老师亮出了另一个题:给 ...
- Vue利用v-for渲染时表单信息出不来
今天在写项目时,Controller的值已经传入到html,但是利用vue进行渲染的时候就是出不来, 原因如下: 注意,in 之前的空格.
- C#扫盲篇(二)依赖倒置•控制反转•依赖注入•面向接口编程--满腹经纶的说
扫盲系列的文章收到了广大粉丝朋友的支持,十分感谢,你们的支持就是我最大动力. 我的扫盲系列还会继续输出,本人也是一线码农,有什么问题大家可以一起讨论.也可以私信或者留言您想要了解的知识点,我们一起进步 ...
- 2021升级版微服务教程—为什么会有微服务?什么是SpringCloud?
2021升级版SpringCloud教程从入门到实战精通「H版&alibaba&链路追踪&日志&事务&锁」 教程全目录「含视频」:https://gitee.c ...
- Lagom 官方文档之随手记
引言 Lagom是出品Akka的Lightbend公司推出的一个微服务框架,目前最新版本为1.6.2.Lagom一词出自瑞典语,意为"适量". https://www.lagomf ...
- Face_to_object_design
二.实例 掷骰子游戏:三粒骰子,掷两次,比较两次的结果. 1.提炼 提炼对象:三粒骰子.游戏 提炼对象的属性和功能:掷骰子.比较点数 骰子: 属性:点数 功能:随机获取一个1~6之间的整数值. 游戏: ...
- Linux下安装svn教程
前言 最近买了新服务器,准备开始弄一些个人的开源项目.有了服务器当然是搞一波svn啦.方便自己的资料上传和下载.于是在此记录搭建svn的方式,方便以后直接使用. 安装 使用yum源进行安装,十分的方便 ...
- 关于软件架构中的b/s
**B/S架构 b/s只需要一个浏览器,用户就可以通过不同的网址访问不同的服务器程序. 优点:开发,安装,部署,维护简单 缺点:对硬件要求过高,用户的体验会受到影响 首先是资源分类:**可以分为静态资 ...