OnixS C++ FIX Engine 4.14.0
Users' manual and API documentation
Loading...
Searching...
No Matches
High Throughput Best Practices

This section describes settings that can improve the sustained message rate of the C++ FIX Engine. Their effects depend on the application, message sizes, traffic pattern, network path, and counterparty.

Start with a Release-build baseline that measures message rate, latency, CPU and memory usage, and network utilization. Change one setting at a time and repeat the measurements with representative message sizes, bursts, round-trip times, and counterparties before deploying the setting in production.

Session Tuning

The Session class exposes several settings. This section covers the subset most relevant to high-throughput workloads.

Selecting the Right Storage

See Selecting the Right Storage for the storage performance and recovery tradeoffs.

Manipulating Thread Affinity

See Manipulating Thread Affinity for guidance on assigning heavily loaded session threads to CPU cores.

Message Grouping

Many small packets incur more protocol and processing overhead than fewer larger packets. Message grouping lets an application trade some queuing latency for better network and receiver efficiency. Configure the default for all sessions with OnixS::FIX::EngineSettings::messageGrouping, or override it for an individual session with OnixS::FIX::Session::messageGrouping.

  • 0 (default) Messages are sent as soon as possible, and pending messages (if any) are grouped until the TCP buffer size is reached.
  • 1 Messages are sent as soon as possible and are never grouped.
  • 2 (or greater) Messages are sent as soon as possible, and pending messages are grouped up to the configured number.

With values 0 and 1, the Engine first tries to send each FIX message from the caller's thread and queues it for the sending thread only when the inline send cannot complete. With a value greater than 1, the Engine immediately queues the serialized packet for transmission by the sending thread. The latter behavior can improve sustained throughput while adding queuing latency.

Message grouping and session batch sending use different aggregation mechanisms and should not be enabled together. See Using session send batch for details. Use the Throughput Sample as a starting point for workload-specific measurements.

Transport Layer and the TCP/IP Stack

TCP behavior depends on the operating-system network stack, the network path, and the peer. Verify the effect of each change on the complete deployment rather than relying on a fixed platform default.

Enable Nagle's algorithm for sustained throughput

Nagle's algorithm reduces protocol and processing overhead by combining small writes. For sustained high-throughput workloads dominated by small messages, enable it with OnixS::FIX::EngineSettings::tcpNoDelayOption(false). It can delay individual messages, so set OnixS::FIX::EngineSettings::tcpNoDelayOption(true) when measured latency requirements outweigh the throughput benefit.

EngineSettings settings;
settings.tcpNoDelayOption(false);

Adjust TCP windows for the Bandwidth Delay Product

The Bandwidth Delay Product (BDP) is the amount of data that must be in flight to fill a network path. It is the product of the available link bandwidth and round-trip time (RTT):

BDP = link bandwidth * RTT

For a 100 Mbit/s path with a 50 ms RTT:

100 Mbit/s * 0.050 s / 8 = 625,000 bytes

The corresponding line-rate throughput is 12.5 MB/s. A connection needs enough effective window and buffering to keep that volume of data in flight, but the BDP is a starting point for capacity analysis rather than an exact value to assign to every socket buffer.

The socket send buffer stores data awaiting transmission, while the socket receive buffer limits the capacity available to receive data. The advertised receive window also depends on TCP window scaling, and the sender is independently limited by its congestion window and network loss. Consequently, setting both socket buffers to the BDP does not guarantee line-rate throughput.

Modern operating systems normally tune TCP buffers and receive windows automatically. On Linux, explicitly setting SO_SNDBUF or SO_RCVBUF disables automatic tuning for that socket's corresponding buffer; see the Linux TCP documentation. Windows exposes receive-window autotuning through Get-NetTCPSetting. TCP window scaling is defined by RFC 7323.

Start with operating-system-managed sizing. Override it only when measurements show that buffer or receive-window capacity constrains the connection. The following example shows how to set the socket buffers with OnixS::FIX::EngineSettings::sendBufferSize (SO_SNDBUF) and OnixS::FIX::EngineSettings::receiveBufferSize (SO_RCVBUF):

// Illustrative requirement for a 100 Mbit/s path with a 50 ms RTT.
const int SocketBufferSize = 625000;
EngineSettings settings;
settings.sendBufferSize(SocketBufferSize)
.receiveBufferSize(SocketBufferSize);
Attention
Larger buffers consume more memory and can increase the time that data remains queued when a connection degrades.