影响Linux下Java UDP包最大值的主要因素分析

影响LinuxJava 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”来使其永久生效。

 

2Java源代码

 DatagramSocketsetReceiveBufferSize方法所设置的缓冲区大小将直接影响能够接收的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 著, 范建华等译

2man tcp

3man ip

 

你可能感兴趣的:(java,linux,redhat,集群,socket,测试)