Netty中wirteAndFlush回调状态一定表示数据发送成功吗?

723 阅读1分钟

我们看一下下面的代码

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框架不适合复杂网络环境部署