Java套接字在MSS超出时发送延迟

试图解决一个问题,即传出消息的延迟时间似乎与套接字刷新行为有关。 我已经从一个quickfixj发起者到一个接受者的数据包捕获传出的FIX消息。

为了总结环境,java intiator将一个套接字连接到另一个服务器上的服务器套接字。 两台服务器都在运行Redhat Enterprise Linux 5.10。 从接口上的netstat的MSS是0.网卡的MTU都是1500(我相信对于回送接口inifinite)。 在应用程序端,通过quickfixj将消息编码到一个字节数组中并写入套接字。 套接字configuration为启用TCP_NODELAY。

我几乎可以肯定,我可以消除应用程序作为延迟的原因,因为当接受者(ServerSocket)在使用回送接口的启动器所在的服务器上运行时,没有发送者延迟。 这是使用回送接口的一些数据包捕获条目的示例:

"No.","Time","Source","Destination","Protocol","Length","SendingTime (52)","MsgSeqNum (34)","Destination Port","Info","RelativeTime","Delta","Push" "0.001606","10:23:29.223638","127.0.0.1","127.0.0.1","FIX","1224","20150527-09:23:29.223","5360","6082","MarketDataSnapshotFullRefresh","0.001606","0.000029","Set" "0.001800","10:23:29.223832","127.0.0.1","127.0.0.1","FIX","1224","20150527-09:23:29.223","5361","6082","MarketDataSnapshotFullRefresh","0.001800","0.000157","Set" "0.001823","10:23:29.223855","127.0.0.1","127.0.0.1","FIX","1224","20150527-09:23:29.223","5362","6082","MarketDataSnapshotFullRefresh","0.001823","0.000023","Set" "0.002105","10:23:29.224137","127.0.0.1","127.0.0.1","FIX","825","20150527-09:23:29.223","5363","6082","MarketDataSnapshotFullRefresh","0.002105","0.000282","Set" "0.002256","10:23:29.224288","127.0.0.1","127.0.0.1","FIX","2851","20150527-09:23:29.224,20150527-09:23:29.224,20150527-09:23:29.224","5364,5365,5366","6082","MarketDataSnapshotFullRefresh","0.002256","0.000014","Set" "0.002327","10:23:29.224359","127.0.0.1","127.0.0.1","FIX","825","20150527-09:23:29.224","5367","6082","MarketDataSnapshotFullRefresh","0.002327","0.000071","Set" "0.287124","10:23:29.509156","127.0.0.1","127.0.0.1","FIX","1079","20150527-09:23:29.508","5368","6082","MarketDataSnapshotFullRefresh","0.287124","0.284785","Set" 

有一点值得关注的是,尽pipe数据包长度(这里最大的是2851),每个数据包上都设置了PUSH标志。 2 /我在这里测量的延迟量度是在编码之前由消息设置的“发送时间”,以及数据包捕获时间“Time”。 数据包捕获在与发送数据的发起者相同的服务器上完成。 对于1万个数据包的抓包,使用环回时,“发送时间”和“时间”没有太大的区别。 出于这个原因,我认为我可以消除应用程序作为发送延迟的原因。

当接受者移动到局域网中的另一台服务器时,发送延迟开始变得比MTU大的数据包变差。 这是一个捕获的片段:

 "No.","Time","Source","Destination","Protocol","Length","SendingTime (52)","MsgSeqNum (34)","Destination Port","Info","RelativeTime","Delta","Push" "68.603270","10:35:18.820635","10.XX.33.115","10.XX.33.112","FIX","1223","20150527-09:35:18.820","842","6082","MarketDataSnapshotFullRefresh","68.603270","0.000183","Set" "68.603510","10:35:18.820875","10.XX.33.115","10.XX.33.112","FIX","1223","20150527-09:35:18.820","843","6082","MarketDataSnapshotFullRefresh","68.603510","0.000240","Set" "68.638293","10:35:18.855658","10.XX.33.115","10.XX.33.112","FIX","1514","20150527-09:35:18.821","844","6082","MarketDataSnapshotFullRefresh","68.638293","0.000340","Not set" "68.638344","10:35:18.855709","10.XX.33.115","10.XX.33.112","FIX","1514","20150527-09:35:18.821","845","6082","MarketDataSnapshotFullRefresh","68.638344","0.000051","Not set" 

这里重要的是当数据包小于MSS(从MTU派生)时,那么PUSH标志被设置,并且没有发送者延迟。 这是可以预料的,因为禁用Nagle的algorithm会导致在这些较小的数据包上设置PUSH。 当数据包大小大于MSS时 – 在这种情况下数据包大小为1514 – 数据包捕获时间和发送时间之间的差异已经跳到35ms。

这个35毫秒的延迟看起来不太可能是由编码消息的应用程序引起的,因为在回送接口上<1ms发送了大的分组大小的消息。 捕获也发生在发送端,所以似乎也不是MTU分割可能的原因。 最可能的原因似乎是,由于没有设置PUSH标志 – 因为数据包大于MSS,所以操作系统级别的套接字和/或TCP堆栈在35ms之后才决定刷新它。 另一台服务器上的testing接受者不是一个慢速的使用者,并且在同一个LAN上,所以ACK是及时的。

任何人都可以指出什么可能导致此套接字发送> MSS数据包的延迟? 与美国的一个真正的交易对手相比,这个发送者的延迟时间高达300ms。 我想如果数据包的大小大于MSS,那么无论先前的ACKS是什么,只要不超过套接字缓冲区大小,数据包就会立即发送。 Netstat通常显示0个socket和风大小,即使从启动开始,这个问题似乎也发生在所有MSS数据包上。 这看起来像套接字决定不会立即冲洗出于某种原因,但不确定哪些因素可能会导致这种情况。

编辑:正如EJP所指出的那样,linux中没有flush。 据我所知,套接字发送将数据放入linux内核的networking缓冲区。 对于这些非推送数据包来说,内核似乎正在等待来自先前数据包的确认。 这不是我所期望的,在TCP中,我希望数据包仍然会被传递,直到套接字缓冲区被填满。

这不是一个全面的答案,因为TCP行为会因许多因素而有所不同。 但在这种情况下,这是我们面临的问题的原因。

在拥塞控制实现中,拥塞窗口允许在没有确认的情况下发送增加量的分组,只要它没有检测到拥塞的迹象即重传。 一般来说,当发生这些问题时,拥塞算法将重置拥塞窗口,限制发送ack之前可以发送的数据包。 这体现在我们所见到的发送者延迟中,因为数据包保存在内核缓冲区中,等待先前数据包的确认。 没有TCP_NODELAY,TCP_CORK等类型的指令将覆盖这方面的拥塞控制行为。

在我们的情况下,往返于另一个地点的往返时间变长了。 然而,由于这是一个每天只有很少数据包丢失的专用线路,因此阻塞控制踢的原因并不是重新传输。最后,通过在Linux中禁用以下标志,似乎已经解决了这个问题。 这也会导致拥塞窗口被重置,但是通过检测空闲而不是丢包:

“tcp_slow_start_after_idle – BOOLEAN如果设置,则提供RFC2861的行为,并在空闲时间后超时拥塞窗口,在当前RTO定义一个空闲周期,如果未设置,拥塞窗口在空闲周期后不会超时。

(注意,如果遇到这些问题,也可以调查其他形式的拥塞控制算法,而不是你的内核当前可能设置的算法)。