最終編集/結論
これはnettyとは関係のない問題でしたが、それでもデバッグは非常に困難でした。messageReceivedのワーカースレッドがブロックされることがあったため、しばらくするとプールで使用可能なスレッドがなくなりました。
元の問題
私の会社では、nettyを使用してGPS追跡デバイスからの接続をリッスンしています。トラッカーはGPRSを介して通信します。
netty3.2.4-finalの非常に奇妙な動作を経験しました。
しばらくすると(正確にはわかりませんが、1日近く)、トラッカーからメッセージが届きません。これは、SimpleCahnnelUpstreamHandlerの実装のmessageReceivedメソッドが呼び出されないことを意味します。ただし、tcpdumpを使用してすべてのパケットをキャプチャすると、すべてのメッセージが着信するのを確認できます。
これは既知の問題ですか、それはnettyの新しいバージョンですでに修正されていますか?
チャネルパイプラインは次のようになります。
...
final TcpListenerChannelHandler tcpChannelHandler;
@Inject
public TcpListenerPipeline(TcpListenerChannelHandler tcpChannelHandler) {
this.tcpChannelHandler = tcpChannelHandler;
}
@Override
public ChannelPipeline getPipeline() throws Exception {
ChannelPipeline p = Channels.pipeline();
p.addLast("frameDecoder", new DelimiterBasedFrameDecoder(2048, Delimiters.lineDelimiter()));
p.addLast("encoder", new ByteArrayWrapperEncoder());
p.addLast("handler", tcpChannelHandler);
return p;
}
...
次の方法でリスニングをインスタンス化します。
public void startListen() {
ChannelFactory channelFactory = new NioServerSocketChannelFactory(Executors.newCachedThreadPool(), Executors.newCachedThreadPool(),20);
bootstrap = new ServerBootstrap(channelFactory);
bootstrap.setPipelineFactory(pipeline);
bootstrap.setOption("child.tcpNoDelay", true);
bootstrap.setOption("child.keepAlive", true);
lazyLogger.getLogger().info("Binding Tcp listener to 0.0.0.0 on port '{}'", listenPort);
serverChannel = bootstrap.bind(new InetSocketAddress("0.0.0.0", listenPort));
}
誰かが何が間違っているのか手がかりを持っていますか?それとも、たとえば1時間程度ごとに、すべてのチャネルを手動で切断する必要がありますか?
編集:
問題についてもう少し情報があります
メッセージが処理されない場合、正常なリモート接続でchannelConnectedが呼び出されないことも発生します。問題をリモートでデバッグしたところ、次のことがわかりました。
- NioServerSocketPipelineSink.java行#246でregisterAcceptedChannel(acceptedSocket、currentThread); 起こる
- ソフトウェアの実行は、さまざまなイベントを伴うDefaultChannelPipeline行#781まで続きますが、私のTcpListenerChannelHandlerがコンテキストに含まれることはありません。
最も奇妙なのは、nettyがチャネルが接続されていることに気付く場合と、接続されていない場合があることです。
EDIT2:
TcpListenerCahnnelHandlerは、SimpleChannelUpstreamHandlerの単純な実装です。
それからのハイライト:
public class TcpListenerChannelHandler extends SimpleChannelUpstreamHandler {
...
@Override
public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
super.channelConnected(ctx, e);
_logger.info("{} device connected from: {}", deviceProtocol.getName(), ctx.getChannel().getRemoteAddress());
deviceConnectionRegistry.channelConnected(ctx.getChannel());
}
@Override
public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
super.channelDisconnected(ctx, e);
_logger.info("{} device from endpoint '{}' disconnected.", deviceProtocol.getName(), ctx.getChannel().getRemoteAddress());
deviceConnectionRegistry.channelDisconnected(ctx.getChannel());
}
@Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent messageEvent) throws Exception {
super.messageReceived(ctx, messageEvent);
...
NOTE: here we process the meassage, I do not think it can cause any problem
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {
if(_logger.isWarnEnabled())
_logger.warn(deviceProtocol.getName()+ " device"
+e.getChannel().getRemoteAddress()+" channel", e.getCause());
if (!(e.getCause() instanceof ConnectException))
e.getChannel().close();
}
その間に、私は3.3.1-finalにアップグレードしました。また、問題が再発する場合は、デバッグを続行する場所がわかります。
編集3:
3.3.1ファイナルにアップグレードしましたが、2日後に同じ問題が再発しました。
それが関連しているかどうかはわかりませんが、同じ物理インターフェイス上にさらに多くのIPアドレスがあります。1つのインターフェースだけで聞いてみるべきですか?より多くのethインターフェースに関する既知の問題はありますか?
ただし、tcpdumpはトラッカーのメッセージを認識しますが、nettyはカスタムハンドラーでmessageReceivedを呼び出しません。
編集4:
コードをさらにデバッグしました。この問題はNioWorker.javaで発生します。131行目(ブール値提供= registerTaskQueue.offer(registerTask);)は正常に実行されますが、タスクは処理されません。つまり、748行目のRegisterTask.run()が呼び出されることはありません。