netty tcp 參數設置_TCP的KeepAlive机制

前言

了解TCP的KeepAlive机制有利于服务器调参。

TCP的KeepAlive

没错,和想象的一样,通过“心跳包”来检查链路是否连通,但在标准的TCP规范中,并没有保活的强制性要求。

传输层KeepAilve缺点

在传输层做保活有很多缺点:

(1)如果中间链路出现短暂的差错(比如某个路由器重启),可能会使得一个非常好的链路被释放掉

(2)心跳包耗费了不必要的带宽,增加了流量费用

(3)在一些复杂的网络环境下(比如某些网络不响应不带数据的报文),TCP保活机制可能会失效。

TCP的KeepAlive机制描述

但事实上,许多实现都提供了KeepAlive的功能(默认关闭)。

如果一个给定的连接在7200秒(2小时)内没有任何动作,那么服务器就向客户端发送一个探查报文段,此时客户机可能处于如下状态:

(1)客户端正常运行,并可达。客户端响应一个报文,服务端收到报文后知道客户端是正常工作的,则将保活定时器复位,2小时后再次触发。此时间段内如果有任何应用报文通信,都会不断重置定时器的下次探测时间。

(2)客户端崩溃,已经关闭或者正在重启中。此时服务器收不到任何响应,75秒后,服务端将再次发送探查报文,一共会尝试10次探测报文的发送(包括第一次),每次间隔75秒,直到客户端回复响应或者达到10次。如果客户端都没有恢复,则服务端认为客户端已经关闭并终止连接。

(3)客户端崩溃并重启完成。此时服务器会受到客户端的响应,但这个响应是一个复位,使得服务端终止这个连接。

(4)客户端正常运行,但不可达。对服务器来说,处理方式和(2)一致。

传输层KeepAlive优点

(1)在应用层做KeepAlive是最好的事情,但会增加应用开发的设计心跳包复杂度。如果配置传输层就能够检测是否断开连接,应用层似乎就不用写心跳代码了。

(2)传输层的报文更小

Connection reset by peer

当出现情况(3)的时候,任意一端宕机恢复,由于不知道之前的连接信息,所以当之前的连接发过来一条保活探测,就会回送一个复位响应。这个响应将使得对端产生报错,例如:read error: Connection reset by peer

在使用jmeter进行服务器压力测试中,也会经常看到connection reset by peer,但这个复位报文通常不是保活探测造成的,而是在TCP三次握手后,服务器Accept达到了最大值,直接拒绝连接产生的RST报文。

keepalive参数的修改带来变化tcp_keepalive_time 保活探测时间:默认2小时。越长,则探测到链路断开的敏感度越低;越短,可能在保活上耗费大量带宽。

tcp_keepalive_intvl 重发探测报文间隔时间:默认75秒。越长,非法关闭的链路占用资源时间越长;越短,等不到客户端恢复,重试失去意义。

tcp_keepalive_probes 重发探测报文次数:默认9次。越多,非法关闭的链路占用资源时间越长;越少,可能只是网络波动就毁掉了一条很好的链路。

为什么协议制定者把探测时间设定为默认2小时,就是为了弱化TCP保活的作用,强迫开发者尽可能在应用层做保活。

Linux的TCPkeepalive参数配置

查看Linux的TCP配置默认值:

7200秒探测一次、未响应重试9次(一共10次)、重试时间间隔75秒。

修改配置:# 查询保活探测时间

cat /proc/sys/net/ipv4/tcp_keepalive_time

# 修改

sysctl net.ipv4.tcp_keepalive_time=3600

# 查询重试间隔时间

cat /proc/sys/net/ipv4/tcp_keepalive_intvl

# 修改

sysctl net.ipv4.tcp_keepalive_intvl=5

# 查询重试次数

cat /proc/sys/net/ipv4/tcp_keepalive_probes

# 修改

sysctl net.ipv4.tcp_keepalive_probes=3

或者修改/etc/sysctl.conf:net.ipv4.tcp_keepalive_time=7200

net.ipv4.tcp_keepalive_intvl=75

net.ipv4.tcp_keepalive_probes=9

然后立即生效:# 立即生效

sysctl -p

# 查看当前配置

sysctl -a | grep keepalive

Netty设置TCPkeepalive

网络通信必学的Netty,提供了.option的方式配置tcp参数:ServerBootstrap sb = new ServerBootstrap();

sb.group(bossGroup, workerGroup)

.channel(socketChannelClazz)

.childHandler(new ChannelInitializer() {

………………

})

.childOption(ChannelOption.SO_KEEPALIVE, true);

ChannelFuture f = sb.bind(host, port);

f.sync().addListener(FIRE_EXCEPTION_ON_FAILURE);

同时,可以利用Netty的Handler来做应用层的心跳包:// 60秒没有read、write就触发idle事件

channel.pipeline().addFirst("idleStateHandler", new IdleStateHandler(60, 0, 0));

// 再用一个Handler去检查idle事件,清理资源,断开连接

@Override

public void userEventTriggered(ChannelHandlerContext ctx, Object evt){

if(evt instanceof IdleStateEvent){

.................

}

}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值