我们知道,tcp套接字keepalive选项是一个建议实现,但恰好linux系统是支持的,那么,使用它就可以避免一些异常网络情况么?
结论现行
- keepalive选项仅解决一部分异常,例如,空闲态遭遇了网络异常,通过主动探测可获知异常
- 部分异常还需依赖tcp套接字的内核参数的调节,例如,net.ipv4.tcp_retries1、net.ipv4.tcp_retries2
- 非常个性化场景,可每个套接字设置timeout参数,避免全局性调节,例如,对涉及的套接字设定SO_SNDTIMEO、SO_RCVTIMEO套接字参数
场景
如果发包时出现网络异常,例如,对端异常下电,对端不可回复RST复位控制报文,那么,tcp协议栈要尝试tcp_retries2次重发,但其尝试重发时间,通常持续的时间相当的长。
虽然,这个重发机制保证tcp流的可靠性,但,通常也使得使用阻塞IO的场景,遭遇较长时间的卡顿,例如,使用redis客户端库hiredis阻塞访问redis时,容易被误判为出现不可恢复故障,被重启掉!
见参考资料,拔掉网线后,原本TCP连接还存在吗?
需要注意的是,这个场景期间keepalive的探测包是没有被发送的!