提问者:小点点

HTTP2服务器发送FIN/确认字符,然后RST没有巨大的流量


我在HTTP2上使用泽西。当流量变得有点高时,就会引发异常。我得到了pcap发现服务器在没有接收到FIN的情况下发送FIN/确认字符。我不确定从服务器端关闭连接是单个FIN。或者单个FIN将确认字符组合到以前的数据包。它看起来是后者,因为客户端没有发送FIN。所以问题是为什么服务器在只有小流量的情况下发送FIN。我发现rece_q和send_q非常低。CPU使用率不是那么高。我已经调整了一些TCP参数,结果是一样的。这种行为是不稳定的,有时它是确定的,有时不确定。当我添加更多的请求(使用相同的TPS)然后不确定。它看起来服务器完成了连接,但不知道确切的原因。它是否与HTTP2有关。我们有什么地方可以看到确切的原因吗?

下面是pcap快照。

pcap快照

更新2017-07-30调试日志:

Sun Jul 30, 2017 8:31:35.591 PM org.glassfish.grizzly.http2.Http2FrameCodec parse
FINE: Rx [2]: connection=TCPNIOConnection{localSocketAddress={localhost/127.0.0.1:80}, peerSocketAddress={/127.0.0.1:57802}}, frame=DataFrame {streamId=277, type=0, flags=[none], length=42, data=BuffersBuffer (154351355) [pos=0 lim=42 cap=42 bufferSize=1 buffers=[HeapBuffer (165674143) [pos=0 lim=42 cap=8391], null, null, null]]}
Sun Jul 30, 2017 8:31:35.673 PM org.glassfish.grizzly.http2.Http2BaseFilter processFrames
FINE: Http2ConnectionException occurred on connection=TCPNIOConnection{localSocketAddress={localhost/127.0.0.1:80}, peerSocketAddress={/127.0.0.1:57802}} during Http2Frame processing
Sun Jul 30, 2017 8:31:35.684 PM org.glassfish.grizzly.http2.Http2FrameCodec serializeAndRecycle
FINE: Tx: connection=TCPNIOConnection{localSocketAddress={localhost/127.0.0.1:80}, peerSocketAddress={/127.0.0.1:57802}}, frame=GoAwayFrame {streamId=0, type=7, flags=[none], length=64{lastStreamId=199, errorCode=REFUSED_STREAM}

以及pcap快照中的流277

pcap包含来自第270、271和272号的流277

269包中有一个SETTINGS包。传输中途发送SETTINGS是否正常?并且在269之后,有三个包270、271和272正在使用蒸汽277。

奇怪的是,大约在8:31:35.684我没有找到GOWay数据包。但只在8:31:36.035发送了RST/确认字符。在这一轮调试日志如下:

Sun Jul 30, 2017 8:31:36.020 PM org.glassfish.grizzly.http2.Http2FrameCodec parse
FINE: Rx [2]: connection=TCPNIOConnection{localSocketAddress={localhost/127.0.0.1:80}, peerSocketAddress={/127.0.0.1:57802}}, frame=DataFrame {streamId=465, type=0, flags=[END_STREAM], length=0, data=ByteBufferWrapper (1101850112) [visible=[java.nio.HeapByteBuffer[pos=0 lim=0 cap=0]]]}
Sun Jul 30, 2017 8:31:36.023 PM org.glassfish.grizzly.http2.Http2BaseFilter processDataFrame
FINE: Data frame received for non-existent stream: connection=TCPNIOConnection{localSocketAddress={localhost/127.0.0.1:80}, peerSocketAddress={/127.0.0.1:57802}}, frame=DataFrame {streamId=277, type=0, flags=[END_STREAM], length=0, data=ByteBufferWrapper (1101850112) [visible=[java.nio.HeapByteBuffer[pos=0 lim=0 cap=0]]]}, stream=277
Sun Jul 30, 2017 8:31:36.024 PM org.glassfish.grizzly.http2.Http2BaseFilter processFrames
FINE: Http2StreamException occurred on connection=TCPNIOConnection{localSocketAddress={localhost/127.0.0.1:80}, peerSocketAddress={/127.0.0.1:57802}} during Http2Frame processing
Sun Jul 30, 2017 8:31:36.025 PM org.glassfish.grizzly.http2.Http2BaseFilter processFrames
FINE: Http2ConnectionException occurred on connection=TCPNIOConnection{localSocketAddress={localhost/127.0.0.1:80}, peerSocketAddress={/127.0.0.1:57802}} during Http2Frame processing

日志显示收到了一个不存在的流277。这个流正是第一个日志中记录的流。不确定这个蒸汽277会在接下来的几毫秒内导致RST/确认字符。我认为它应该与数据包269~272和流277有一些问题。

BTW,这次没有FIN/确认字符。


共1个答案

匿名用户

pcap显示服务器上的异常终止。

您应该检查服务器日志以了解发生这种情况的更多详细信息。

一个可能的原因是服务器bug。

另一个可能的原因是客户端在数据包14发送了无效的HEADERS帧;尽管如此,服务器应该发送一个GOAWay帧,而不仅仅是关闭连接。

数据包17的RST是正常的,因为客户端在处理FIN之前在数据包16发送了一个HEADERS帧,所以服务器回复一个RST,表明发送的数据没有到达用户代码层。

服务器日志(可能在DEBUG级别)应该会告诉您更多关于发生的事情。