影响Linux下Java UDP包最大值的主要因素分析
dennis.hu.cd 2010-11-17 http://blog.csdn.net/gobitan
编写前
最近一直纠结于Java UDP包大小限制的问题。耗费了大量时间,现在问题终于解决了,总结一下,希望对有类似问题的朋友有所帮助。
问题来源
产品系统中有一个基于Java UDP包的socket的应用。该应用主要负责整个集群系统之间的信息交换,能够支持的UDP包值的大小影响到了集群系统的扩展。
产品现场报过来的Case显示:系统仅支持不到8个节点,这显然远没有达到我们集群系统的设计目标。经过多次测试,发现当前系统所能支持的UDP包的最大值为19290,与UDP包的理论值相去甚远。
UDP理论值
要对该问题有一个清晰的认识,必须先从理论上弄清楚。UDP包封装于IP数据包中,因此IP数据包的大小决定了UDP数据报的大小。理论上,IP数据报的最大长度是65535字节,这是由IP首部16比特总长度字段所限制的。去除20字节的IP首部和8个字节的UDP首部,UDP数据报中用户数据的最大长度为65507字节。但是,大多数实现所提供的长度比这个最大值小(参考资料1,第119页)。
主要因素分析
影响Linux环境下Java UDP包最大值的因素很多,主要有以下两个方面:
(1) 操作系统网络内核参数
(2) Java代码
(1)网络内核参数
影响Java UDP能够接收的最大值主要有两个方面的参数:
第一:socket接收缓冲区参数
net.core.rmem_default 代表socket的接收缓冲区的默认值
可以通过man tcp帮助中查到此参数的详细解释。如果此参数设置过小,将影响到能够接收到的UDP包的大小。
net.core.rmem_max 代表socket的接收缓冲区的最大值
可以通过man tcp帮助中查到此参数的详细解释。如果源代码中设置的值比此值大,这此值为准。
Redhat linux5.3最初的设置如下:
net.core.rmem_default = 126976
net.core.rmem_max = 131071
经过测试,该设置能够支持的UDP包最大值为19290字节。
改成如下之后能突破19290字节的限制。
net.core.rmem_default = 262144
net.core.rmem_max = 524288
第二:IP分片缓冲区参数
net.ipv4.ipfrag_low_thresh
net.ipv4.ipfrag_high_thresh
用于组装分片的IP数据报的最大内存量,它将直接影响到能够接收到最大的UDP包的大小。因为超过MTU值的包都会被分片,分片的IP包达到目的端后需选缓存起来,等所有包都到达之后再组装。如果缓存不够用,多余的将被丢弃,这会导致组装失败。
redhat linux5.3最初的设置如下:
net.ipv4.ipfrag_low_thresh = 196608
net.ipv4.ipfrag_high_thresh = 262144
该设置能够支持的最大UDP大小约40000字节。
改成如下之后,可达65356字节。
net.ipv4.ipfrag_low_thresh = 393216
net.ipv4.ipfrag_high_thresh = 524288
以上参数的设置操作:
(1)可以通过”sysctl –a|grep thresh”查看到。
(2)可以通过” sysclt -w net.ipv4.ipfrag_high_thresh = 524288”来设置。但操作系统重启后该值将失效。
(3)可以通过将其加入/etc/sysctl.conf文件中,然后执行”sysctl -p”来使其永久生效。
(2)Java源代码
DatagramSocket的setReceiveBufferSize方法所设置的缓冲区大小将直接影响能够接收的UDP包最大值。如果设置成65356,实际上能够接收的大小最大值只有19290。
可将其值设置为262144之后即可支持65356
问题总结:
解决支持UDP包大小的关键三个点:
net.core.rmem_default 操作系统内核参数:接收缓冲区
net.ipv4.ipfrag_low_thresh 操作系统内核参数:IP分片组装缓冲区
DatagramSocket.setReceiveBufferSize Java设置的接收缓冲区
疑问:
到目前为止,我确实解决了上面的问题。但是我在另外一套环境中进行了测试发现:
上面提到的三个因素都不修改的情况下,同样的测试程序依然可以支持到接近理论值65356。
说明:两套环境的硬件均为HP ProLiant BL460c G6,操作系统也一样。内核参数我进行了比较,未发现特别疑问。
hpb1207# cat /etc/redhat-release
Red Hat Enterprise Linux Server release 5.3 (Tikanga)
hpb1207# uname -a
Linux hpb1207 2.6.18-128.el5 #1 SMP Wed Dec 17 11:41:38 EST 2008 x86_64 x86_64 x86_64 GNU/Linux
hpb1207# ethtool -i eth0
driver: bnx2x
version: 1.45.23
firmware-version: BC:5.2.7 PHY:baa0:0105
bus-info: 0000:02:00.0
暂时记下,希望能在后面的工作中把这个疑问解开!如果谁知道问题所在,请不吝赐教!
参考资料:
(1)《TCP/IP详解卷1:协议》(美) W. Richard Stevens 著, 范建华等译
(2)man tcp
(3)man ip