2

I am working on task involving reading from the socket trading quotes and I need to achieve minimum latency and high throughput.

I started with the simpliest possible java nio prototype like this

ByteBuffer buf = ByteBuffer.allocateDirect(BUFFER_SIZE);
try {
       buf.clear();
       int numBytesRead = socketChannel.read(buf);

       if (numBytesRead == -1) {  
           socketChannel.close();
       } else {
           buf.flip();
           byte[] byteArrived = new byte[buf.remaining];
           buf.get(byteArrived,0,byteArrived.length);
           // here we send byteArrived to the parser
       }
   } catch (IOException e) {    
}

I guess it is lame to create byte[] array every time, but due to the lack of knowledge I dont know how to parse ByteBuffer ( because I need to unmarshall byte protocol into messages and pass them into business logic). Can you recommend how to avoid mass garbage creation?

Also I would like to ask about best practices how to organize socket reading with low latency and high throughput? I read about LMAX and disruptor framework and they achieved 6M transactions on the single thread.

mprabhat
  • 20,107
  • 7
  • 46
  • 63
Egor Lakomkin
  • 1,374
  • 14
  • 26

2 Answers2

4

You can achieve higher than that with Disruptor and other methods. A lot depends on the size and complexity of message (as well as what you do with the message !!)

If you want to serialize/deserialze with ByteBuffer, use the putXxxx and getXxxx methods. To make this process easier, I suggest putting the length of each message first so you can check you have a full message before attempting to parse it.

You might find this presentation interesting http://vanillajava.blogspot.com/2011/11/low-latency-slides.html

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • Messages are pretty simple 12 bytes or 27 bytes long. – Egor Lakomkin Nov 29 '11 at 20:23
  • In that case you can get between 250Kmsg/s and 40M msg/s depending on whether you want lowest latency (as low as 5 us) or highest throughput (but have 25 us latency) Of course this all has to come from somewhere and go to somewhere. There is no point worrying about it unless you have a demand and you consumer(s) can process messages that fast. – Peter Lawrey Nov 29 '11 at 20:26
  • As advised - put the length as first field, and keep in mind that single read from socket may deliver more than one message, as well as partial message. Other things to consider: a) instantiate buffer once b) create pool of objects wrapping byte[] and providing bean-style accessors / other methods (then serialization / deserialization is as simple as copying bytes between IO buffer and object internal array) – Andrey Nudko Nov 29 '11 at 21:48
  • thank you for your advices, but I cannot put message length in the body, because the protocol is defined already by the data provider(i should rely on that there is 3 types of binary messages, all of them have fixed length ). So you recommend create ByteBuffer once, but I didnt get the "pool of objects wrapping byte[]". Also there is no method to getByte from ByteBuffer, because I need for instance to get one byte and unmarshall it to lower bits/higher buts for instance. I have done naive way, but I want to improve performance,latency and dont create so much garbage while parsing the messages. – Egor Lakomkin Nov 30 '11 at 07:04
  • If you want to `get` as byte, you can just use `get()` You should be able to do all the parsing without creating any garbage. ;) – Peter Lawrey Nov 30 '11 at 08:25
1

Assuming you can adapt your parser API to accept (byte[] buffer, int offset, int length) as arguments, you can just pass (bb.array(), 0, bb.limit()) as parameters and not have to create the new byte[] at all per read. However this isn't likely to be the rate-determining step.

user207421
  • 305,947
  • 44
  • 307
  • 483