Diferenças de desempenho TCP entre RH Linux e Solaris em java?

1

Ao comparar o desempenho do soquete TCP do Java entre o RH Linux e o Solaris, um dos meus testes é feito usando um cliente java enviando strings e lendo as respostas de um servidor de echo java. Eu meço o tempo gasto para enviar e receber os dados (ou seja, o loop de volta ida e volta).

O teste é executado 100.000 vezes (mais ocorrências estão dando resultados semelhantes). Dos meus testes, o Solaris é em média 25/30% mais rápido do que o RH Linux, no mesmo computador com as configurações padrão de rede e sistema, os mesmos argumentos da JVM (se houver) etc.

Eu não entendo uma diferença tão grande, existem alguns parâmetros de sistema / rede que estou faltando?

O código usado (cliente e servidor) é mostrado abaixo se alguém estiver interessado em executá-lo (a contagem de ocorrências deve ser dada na linha de comando):

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(); }
    }
  }
}

Estou usando o JRE 1.6.0_18 para ambos os sistemas operacionais, em um único Nehalem dual core de 2,3 GHz. Os 2 SO ar Solaris 10 e RH Linux 5.4 com o RT Kernel 2.6.24.7.

Muito obrigado.

    
por Jul 06.07.2010 / 09:55

2 respostas

2

No Solaris, isso é chamado de "TCP Fusion", o que significa que dois pontos de extremidade TCP locais serão "fundidos". Assim, eles ignoram completamente o caminho dos dados TCP.

Tente desativá-lo e execute seu teste novamente:

# echo do_tcp_fusion/W 0 | mdb -kw
do_tcp_fusion:  0x1             =       0x0

Você provavelmente deve tentar criar um ambiente de teste que imite sua produção o mais próximo possível. Isso provavelmente significa configurar uma rede real com adaptadores de rede.

Se você quiser brincar com a limitação de conexão ou outras situações de rede complexas, sugiro que você coloque uma caixa do FreeBSD entre seus dois pontos de extremidade e brinque com ipfw / dummynet de pf / altq.

    
por 07.07.2010 / 02:04
2

O Solaris 10 tem uma pilha de rede bastante impressionante. Mas acho que o que você está experimentando é a otimização de loopback de TCP.

Basicamente, quando determinadas condições são atendidas, o processamento do protocolo é desabilitado para conexões de loopback.

Você pode ler sobre isso neste post impressionante: Solaris 10 Networking - A Magia Revelada

    
por 06.07.2010 / 13:08