一、链路的有效性检测
当网络发生单通、连接被防火墙Hang住、长时间GC或者通信线程发生非预期异常时,会导致链路不可用且不易被及时发现。
特别是异常发生在凌晨业务低谷期间,当早晨业务高峰期到来时,由于链路不可用会导致瞬间的大批量业务失败或者超时,
这将对系统的可靠性产生重大的威胁。
从技术层面看,要解决链路的可靠性问题,必须周期性的对链路进行有效性检测。目前最流行和通用的做法就是心跳检测。
心跳检测机制分为三个层面:
1) TCP层面的心跳检测,即TCP的Keep-Alive机制,它的作用域是整个TCP协议栈;
2) 协议层的心跳检测,主要存在于长连接协议中。例如SMPP协议;
3) 应用层的心跳检测,它主要由各业务产品通过约定方式定时给对方发送心跳消息实现。
心跳检测的目的就是确认当前链路可用,对方活着并且能够正常接收和发送消息。
做为高可靠的NIO框架,Netty也提供了心跳检测机制,下面我们一起熟悉下心跳的检测原理。
不同的协议,心跳检测机制也存在差异,归纳起来主要分为两类:
1) Ping-Pong型心跳:由通信一方定时发送Ping消息,对方接收到Ping消息之后,立即返回Pong应答消息给对方,属于请求-响应型心跳;
2) Ping-Ping型心跳:不区分心跳请求和应答,由通信双方按照约定定时向对方发送心跳Ping消息,它属于双向心跳。
心跳检测策略如下:
1) 连续N次心跳检测都没有收到对方的Pong应答消息或者Ping请求消息,则认为链路已经发生逻辑失效,这被称作心跳超时;
2) 读取和发送心跳消息的时候如果发生了IO异常,说明链路已经失效,这被称为心跳失败。
无论发生心跳超时还是心跳失败,都需要关闭链路,由客户端发起重连操作,保证链路能够恢复正常。
二、基于TCP的通信为什么需要RETRY
TCP协议本身是可靠的,它的重传机制保证了消息的可送达性(如果没有收到对端的ACK确认,它会在等待一定时间后,尝试再次发送,且这是一个循环过程,上限是9分钟。超过9分钟,则认为连接已经断开,关闭socket)。
虽然有了TCP的可靠性保证,但是很多基于TCP的应用间通信依然会采用RETRY机制:发送消息后,如果在一定时间内没有收到对端的确认消息,则重发消息。明明TCP已经可以保证消息的可送达,为什么还要在应用层加这么一层实现呢?
1. 有些服务进程,基于性能或是内存容量方面的考虑,使用了限长的消息队列:如果收到的瞬时消息过多,超过了消息队列的可处理个数,所有超出的消息会被它丢弃。注意,在这种情况下,TCP确实是将消息成功送达了,只是应用层不接受而已。客户进程等待一小段时间,尝试再次发送,有可能此时服务端的处理压力已经降下来了,消息就能被处理了。
2. 进入了弱网环境的移动应用,发送超时往往意味着已经断连。
三、TCP 重试参数
对于每个连接,TCP管理4个定时器来完成数据的传输:
1. 重传定时器
2. 坚持定时器(persist):使窗口大小保持不断流动
3. 保活定时器(keepalive):检测空闲连接的另一端何时崩溃
4. 2MSL定时器:测量一个连接处于TIME_WAIT状态的时间
sysctl -a | grep tcp_syn_retries 对于一个新建连接,内核要发送多少个SYN连接请求才决定放弃
net.ipv4.tcp_syn_retries = 6
sysctl -a | grep tcp_synack_retries 对于远端的连接请求SYN,内核会发送SYN+ACK数据包,以确认收到上一个SYN连接请求包
net.ipv4.tcp_synack_retries = 5
sysctl -a | grep tcp_retries1 放弃回应一个TCP连接请求前﹐需要进行多少次重试
net.ipv4.tcp_retries1 = 3
sysctl -a | grep tcp_retries2 在丢弃激活(已建立通讯状况)的TCP连接之前﹐需要进行多少次重试
net.ipv4.tcp_retries2 = 15
参考: