在比较RH Linux和Solaris之间的java TCP套接字性能时,我的一个testing是通过使用java客户端发送string并从java echo服务器读取回复来完成的。 我测量了发送和接收数据所花费的时间(即回程往返)。
testing运行100,000次(更多发生的结果相似)。 在我的testing中,Solaris的平均速度比RH Linux快25/30%,在默认系统和networking设置的相同计算机上,相同的JVM参数(如果有的话)等等
我不明白这么大的差别,是否有一些我缺less的系统/networking参数?
所使用的代码(客户端和服务器)显示如下,如果有人有兴趣运行它(发生次数必须在命令行中给出):
import java.io.*; import java.net.*; import java.text.*; public class SocketTest { public final static String EOF_STR = "EOF"; public final static String[] st = {"toto" ,"1234567890" ,"12345678901234567890" ,"123456789012345678901234567890" ,"1234567890123456789012345678901234567890" ,"12345678901234567890123456789012345678901234567890" ,"123456789012345678901234567890123456789012345678901234567890" }; public static void main(String[] args) throws UnknownHostException, IOException, InterruptedException { double mean = 0.0; int port = 30000; int times = Integer.parseInt(args[0]); String resultFileName = "res.dat"; new EchoServerSimple(port); // instanciate and run Socket s = new Socket("127.0.0.1", port); s.setTcpNoDelay(true); PrintWriter pwOut = new PrintWriter(s.getOutputStream(), true); BufferedReader brIn = new BufferedReader(new InputStreamReader(s.getInputStream())); long[] res = new long[times]; int j = 0; for(int i = 0; i < times; i++) { if(j >= st.length) j = 0; long t0 = System.nanoTime(); pwOut.println(st[j++]); brIn.readLine(); res[i] = System.nanoTime() - t0; mean += ((double)res[i]) / times; } pwOut.println(EOF_STR); s.close(); print(res, resultFileName); System.out.println("Mean = "+new DecimalFormat("#,##0.00").format(mean)); } public static void print(long[] res, String output) { try { PrintWriter pw; pw = new PrintWriter(new File(output)); for (long l : res) { pw.println(l); } pw.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } } static class EchoServerSimple implements Runnable { private ServerSocket _serverSocket; public EchoServerSimple(int port) { try { _serverSocket = new ServerSocket(port); } catch (IOException e) { e.printStackTrace(); } new Thread(this).start(); } public void run() { try { Socket clientSocket = _serverSocket.accept(); clientSocket.setTcpNoDelay(true); PrintWriter pwOut = new PrintWriter(clientSocket.getOutputStream(), true); BufferedReader brIn = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); try { while(true) { String s = brIn.readLine(); pwOut.println(s); if(s.equals(EOF_STR)) { clientSocket.close(); break; } } } catch (Exception e) { e.printStackTrace(); try { clientSocket.close(); } catch (IOException e1) { e1.printStackTrace(); } } } catch (IOException e) {e.printStackTrace(); } } } }
我在单核2.3GHz双核Nehalem上使用了JRE 1.6.0_18。 2 OS是带有RT Kernel 2.6.24.7的Solaris 10和RH Linux 5.4。
非常感谢。
在称为“TCP融合”的Solaris中,这意味着两个本地TCP端点将“融合”。 因此,他们将完全绕过TCP数据path。
尝试禁用它并再次运行您的testing:
#echo do_tcp_fusion / W 0 | mdb -kw do_tcp_fusion:0x1 = 0x0
您应该尝试创build一个模拟您的产品尽可能接近的testing环境。 这可能意味着通过networking适配器build立真正的networking。
如果你想玩连接节stream或其他复杂的networking情况,我build议你在两个端点之间放置一个FreeBSD盒子,并使用pf / altq的ipfw / dummynet。
Solaris 10拥有非常令人印象深刻的networking堆栈。 但是我认为你正在经历的是TCP环回优化。
基本上,当满足某些条件时,回送连接的协议处理被禁用。
您可以在这个令人印象深刻的博客文章阅读有关它: Solaris 10 Networking – 魔术揭晓