Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Performance issue using Javas Object streams with Sockets

I'm trying to do local IPC using Sockets and Object streams in Java however I'm seeing poor performance.

I am testing the ping time of sending an object via an ObjectOutputStream to receiving a reply via an ObjectInputStream over a Socket.

Here's the Requestor:

public SocketTest(){

    int iterations = 100;
    try {
        Socket socket = new Socket("localhost", 1212);

        ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream()); 
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream()); 

        double start = System.currentTimeMillis();
        for (int i = 0; i < iterations; ++i) {

            Request request = new Request();
            objectOutputStream.writeObject(request);

            Response response = (Response)objectInputStream.readObject();
        }
        double finish = System.currentTimeMillis();
        System.out.println("Per ping: " + (finish - start) / iterations );

    } catch (Exception e) {
        e.printStackTrace();
    }
}

Here's the responder:

public ServerSocketTest(){

    try {

        ServerSocket serverSocket = new ServerSocket(1212);
        Socket socket = serverSocket.accept();

        ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
        ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream());

        Request request = (Request)objectInputStream.readObject();
        while (request != null) {

            Response response = new Response();
            objectOutputStream.writeObject(response);
            request = (Request)objectInputStream.readObject();
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

The result I'm getting is:

Per ping: 80.35

80 msec is far to slow for local traffic.

Request and Response classes are very small and their serialisation is fast.

I have tried naively adding:

socket.setKeepAlive(true);  
socket.setTcpNoDelay(true);

with little effect.

performing a ping localhost:

64 bytes from localhost.localdomain (127.0.0.1): icmp_seq=0 ttl=64 time=0.035 ms  
64 bytes from localhost.localdomain (127.0.0.1): icmp_seq=1 ttl=64 time=0.037 ms  
64 bytes from localhost.localdomain (127.0.0.1): icmp_seq=2 ttl=64 time=0.049 ms  
64 bytes from localhost.localdomain (127.0.0.1): icmp_seq=3 ttl=64 time=0.039 ms  
64 bytes from localhost.localdomain (127.0.0.1): icmp_seq=4 ttl=64 time=0.056 ms  

is also fast.

Java version 1.6.0_05l Running on RedHat 2.4

like image 240
Jonathan Avatar asked Feb 12 '10 10:02

Jonathan


2 Answers

So construct the BufferedOutputStream & flush it before constructing the BufferedInputStream. To avoid hanging.

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4788782

it says as per documentation

If you modify the test case such that both the AServer and AClient construct the ObjectOutputStream before the ObjectInputStream, the test does not block. This is the expected behaviour given the following documentation:

ObjectOutputStream constructor:
Creates an ObjectOutputStream that writes to the specified
OutputStream. This constructor writes the serialization stream header to the underlying stream; callers may wish to flush the stream immediately to ensure that constructors for receiving
ObjectInputStreams will not block when reading the header.

ObjectInputStream constructor:
Creates an ObjectInputStream that reads from the specified
InputStream. A serialization stream header is read from the stream and verified. This constructor will block until the corresponding
ObjectOutputStream has written and flushed the header.

like image 27
Houtman Avatar answered Oct 22 '22 03:10

Houtman


Have you tried embedding both reques ts and responses in BufferedInputStream/BufferedOutputStream ? It should widely improve performances.

like image 177
Riduidel Avatar answered Oct 22 '22 05:10

Riduidel