In this article we list the main reasons that make CoralFIX a very fast and easy to use FIX engine.
- Network I/O: The most important part of a FIX engine in terms of performance is the network I/O library. That’s because FIX parsing can be done in nanoseconds while TCP latencies are in microseconds. So it is not enough to be super fast when parsing the FIX message while your bottleneck may be in the network I/O. In addition to parsing a FIX message very fast (in nanoseconds), CoralFIX uses CoralReactor under the hood, which brings our years of experience with Java NIO and network I/O. We provide our own selector implementation which is much faster than the standard JDK implementation.
- Non-Blocking I/O: CoralFIX is built from the ground up to use non-blocking sockets through Java NIO selectors. That has several advantages over blocking sockets:
- Ultra-Low-Latency: Blocking sockets are very slow and can block for any arbitrary amount of time when you try to send and receive data. Non-blocking sockets on the other hand never block and sending/receiving data becomes as fast as simply copying data to/from the underlying native socket buffer.
- Scalability: The same CoralFIX thread can not only handle hundreds of clients but it can also handle clients, servers and any mix of the two. For blocking sockets on the other hand, the old one-thread-per-client approach must be used, which is very hard to scale when the number of threads surpasses the number of available CPU cores. Thread pools or any other trick will not match the flexibility and scalability of non-blocking sockets running inside the same super-fast thread.
- Simplicity: The single-threaded approach of CoralFIX eliminates all the issues that are so common to multithreaded programming. You suddenly don’t have to worry about thread synchronization, lock contention, race-conditions, deadlocks, thread starvation, context switches and many other pitfalls that arise when different threads need to coordinate and share state. Because CoralFIX clients and servers run inside the same thread, all these problems disappear and you can re-allocate your brain power to other tasks.
- Zero Garbage: All Coral Blocks components produce zero garbage for the GC in the critical path. With CoralFIX you are able to send/receive billions of messages without ever producing any garbage. No GC interruption, ever!
- Zero Depedencies: At Coral Blocks we use Java as a syntax language. Our libraries have zero external dependencies and we don’t even rely on the JDK standard libraries. With CoralFIX you have total control over the critical path.
- Zero Copy: When parsing a ByteBuffer into a FixMessage object, CoralFIX does not copy any bytes or create any objects. The resulting FixMessage object is backed up by the same ByteBuffer that was parsed. The parsing process simply delimits the tags and values of the FIX message. Moreover all values are lazy parsed, in other words, a price value won’t be parsed to a double until you explicitly call getDouble(FixTags.Price). Or you can call getByteBuffer(FixTags.Price) to return your value delimited in the original ByteBuffer, without any parsing.
- Thread Affinity: Although not a requirement, it is recommended that you pin your critical threads to dedicated cpu cores. CoralFIX supports thread affinity out-of-the-box and can pin your critical threads to the cpu cores you specify. To pin your critical threads, all you have to do is pass the cpu core id in the command-line options below:
-DnioReactorProcToBind=CORE_ID -DlogProcToBindAsyncThread=CORE_ID -DfixStoreProcToBind=CORE_ID
config.add("auditLog", true);
config.add("supportPersistence", true);
config.add("persistSequences", true);
config.add("fixVersion", FixVersions.VERSION_44);
NioReactor nio = NioReactor.create(); MapConfiguration config = new MapConfiguration(); config.add("fixVersion", FixVersions.VERSION_44); config.add("senderComp", "testClient"); Client client = new FixApplicationClient(nio, "localhost", 45451, config); client.open(); nio.start();
// add a start session timer daily at 14:30:00 EST config.add("startSessionTimer", "D-EST-14:30:00"); // add a stop session timer weekly on Sunday at 16:00:00 EST config.add("stopSessionTimer", "W-SUNDAY-EST-16:00:00");
// Get a FIX message ready to be sent out, with sequences, header and everything taken care for you FixMessage outFixMsg = getOutFixMessage(MsgTypes.NewOrderSingle); // Add any kind of value as a tag outFixMsg.add(Price, 50.34); outFixMsg.add(ClOrdID, "A123"); outFixMsg.add(Side, '2'); // Add a repeating group FixGroup partyIds = outFixMsg.createGroup(NoPartyIDs); partyIds.nextElement().add(PartyID, "BLAH").add(PartyIDSource, 'D').add(PartyRole, 54); partyIds.nextElement().add(PartyID, "TRD").add(PartyIDSource, 'D').add(PartyRole, 36); // Send out the message to the client send(outFixMsg);
tcpdump
and Wireshark to measure the tick-to-trade latencies and they are around 8 micros.
Conclusion
Although it is important for a FIX engine to be as fast as possible, and we got that covered through fast parsing and networking, at Coral Blocks we believe that ease of use is even more important. Not just CoralFIX but all of our components must be very easy to understand, integrate and use. Our licensing model also allows us to have a commitment to our clients in providing first-class support and to share our know-how throughout the license period. We are passionate about what we do and we enjoy working side-by-side with our clients to bring outstanding results.