我们看一下下面的代码
ChannelFuture ch=inboundChannel.writeAndFlush(request);
writeFuture.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture channelFuture) {
if (channelFuture.isSuccess()) {
log.error("发送数据成功");
} else {
log.error("发送数据失败",channelFuture.cause());
}
}
});
我们从channelFuture.isSuccess()来判断数据写入成功但不表示数据网络发送成功,由于网卡队列的存在当channelFuture.isSuccess()为true时我们只表示写入网卡队列成功。
在一次客户现场实施部署时出现了一个奇怪的现象,由于两个服务之间的调用通过防火墙,出现了应用时好时坏的问题,问题也是出自于自研RPC框架的问题导致的。
问题产生的原因
RPC框架问题
1、默认不开启心跳包
2、只要使用writeAndFlush(request)就将心跳超时续期
客户防火墙特殊性
客户防火墙在TTL超时后不会断开TCP连接而是采用发送win=0来限制数据发送
问题排查与处理
针对上面的问题当时我使用了netstat查看了连接的SendQ发现snedQ持续增长到很大只但是内网是不会出现网络的问题,对于代码的修改就是应该使用服务端的心跳包来续期不应该用writeAndFlush(request) 来做续期。
在解决完问题后带来的思考
1、自研RPC框架不能做成全异步模式否则数据是否发送成功都无法判断
2、RPC框架的心跳一定要打开不能认为内网不会出现问题就关闭心跳
3、心跳超时计算一定不能认为writeAndFlush(request)写入成功就续期心跳
4、RPC请求最好有超时处理机制否则全异步的RPC框架不适合复杂网络环境部署