赞
踩
TCP是面向连接的。创建一个TCP连接,客户端和服务端需要经历三次握手,一旦建立它的期限就是永久,除非其中一方发起关闭。
理想状态下,客户端与服务端建立连接就可以一直用下去,但是在真实的互联网世界没有这么理想: NAT网关、防火墙、代理服务器等网络设备可能会清理空闲的连接; 也有可能其中一方突然崩溃、网络断开来不急通知对方关闭连接;或者其他意外,导致其中一方或双方的连接就一直永久保留在那里。
客户端,随着应用的关闭,系统会自动回收应用创建的连接。这个不处理似乎影响也不太大。
服务端,软件都是长期运行的,没办法通过软件的关闭来实现连接的回收。在Linux里一个空闲的TCP连接占用将近4k内存,大量的空闲连接积攒下来消耗不少内存。而且服务端一直不释放可能会导致TCP创建连接失败。所以在应用层基本都会有一个超过一定时间不使用主动关闭TCP连接的机制。
这个时候我们就会发现TCP keepalive似乎是可有可无的,确实在TPC连接中keepalive是默认不开启的。不过我们可以通过 TCP keepalive做这些事情:
keepalive在一定的间隔里通过连接发送一个信号,如果在指定的时间内收到回应就可以确认连接还是通的;如果指定的时候还没收到回应就启动重试;如果重试了最大重试次数内还是没收到回应,那么就判定连接不通了,就主动关闭连接。
NAT网关、代理服务器、防火墙等等会清理他认为不活动的连接,keepalive的周期性发送信号可以保持连接处于持续活动状态。Linux NAT网关的连接保持时间默认是1天,阿里云NAT网关连接的老化时间是900秒也就是15分钟,这也产生过一个生产事故。
Linux 原生支持TCP keepalive,并提供了三个用户参数:
tcp_keepalive_time
默认值7200s(2小时),就是连接空闲多久,开始发keepalive 探测包。 tcp_keepalive_intvl
默认值75s,后续 keepalive探测包的时间间隔。
tcp_keepalive_probes
默认值9,发多少keepalive探测包没有回应,就认为连接已经死了需要通知应用层。
tcp_keepalive_time
时间内一直静默,那么发一个空的ACK包,也就是keepalive探测包。tcp_keepalive_intvl
秒,然后发另一个ACK包tcp_keepalive_probes
次ACK包。RST
包,然后关闭连接。procfs是一个伪文件系统,通过它可以查看或修改内核参数。
查看
1 2 3 4 5 6 7 | # cat /proc/sys/net/ipv4/tcp_keepalive_time 7200 # cat /proc/sys/net/ipv4/tcp_keepalive_intvl 75 # cat /proc/sys/net/ipv4/tcp_keepalive_probes 9 |
修改
1 2 3 4 | # echo 600 > /proc/sys/net/ipv4/tcp_keepalive_time # echo 60 > /proc/sys/net/ipv4/tcp_keepalive_intvl # echo 20 > /proc/sys/net/ipv4/tcp_keepalive_probes |
简单明了,但是不太适合大量的参数的管理,所有Linux还提供了一个辅助的工具sysctl
。
把procfs路径里的/proc/sys/
删掉剩下的 / 替换成 . 就可以了。sysctl variable
查看变量的值。sysctl -a
打印所有变量的值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | # sysctl net.ipv4.tcp_keepalive_time net.ipv4.tcp_keepalive_time = 7200 # 也可能一次查多个变量名 # sysctl net.ipv4.tcp_keepalive_intvl net.ipv4.tcp_keepalive_probes net.ipv4.tcp_keepalive_intvl = 75 net.ipv4.tcp_keepalive_probes = 9 # 也可以打印出所有的变量,然后通过grep等工具过滤 # sysctl -a | grep net.ipv4.tcp_keepalive net.ipv4.tcp_keepalive_intvl = 75 net.ipv4.tcp_keepalive_probes = 9 net.ipv4.tcp_keepalive_time = 7200 |
需要修改的时候就用sysctl -w variable=value
的方式
1 2 3 4 5 6 7 | # sysctl -w net.ipv4.tcp_keepalive_time=600 \ net.ipv4.tcp_keepalive_intvl=60 \ net.ipv4.tcp_keepalive_probes=20 net.ipv4.tcp_keepalive_time = 600 net.ipv4.tcp_keepalive_intvl = 60 net.ipv4.tcp_keepalive_probes = 20 |
要注意的是这些修改系统重启之后都会失效的,如果希望重启之后依然生效。就需要把配置写入/etc/sysctl.conf
或者在/etc/sysctl.d/
目录内创建一个.conf
文件并写入配置。这样Linux系统再启动时就会加载并应用这个配置。
keepalive默认是不开启的,需要主动指定.
1 2 3 4 5 6 7 8 | // BIO Socket client = new Socket(hostName, port); client.setKeepAlive(true); // NIO socketChannel.setOption(StandardSocketOptions.SO_KEEPALIVE, true); |
Does a TCP socket connection have a "keep alive"?
https://newbedev.com/does-a-tcp-socket-connection-have-a-keep-alive
TCP Keepalive HOWTO
https://tldp.org/HOWTO/html_single/TCP-Keepalive-HOWTO/
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。