Join GitHub today
Aeron can tradeoff CPU utilisation for throughput + latency by different thread configurations
Aeron is an agent based design and is configurable how it creates threads and assigns them to agents in the media driver and the client. For some applications the default settings are desirable whereas other applications are better suited to invoking the Aeron agents directly by delegation from their own duty cycles. The Aeron agents many be composed into a service which is agent based itself, e.g. the Aeron Archiver operates this way.
The media driver has 3 agents - Sender, Receiver, and Conductor. The creation and assignment of agents to threads can be controlled with the
aeron.threading.mode setting as follows:
INVOKER: No threads. The client is responsible for using the
MediaDriver.Context.driverAgentInvoker()to invoke the duty cycle directly.
SHARED: All Agents share a single thread. 1 thread in total.
SHARED_NETWORK: Sender and Receiver shares a thread, conductor has its own thread. 2 threads in total.
DEDICATED: The default and dedicates one thread per Agent. 3 threads in total.
If running in
INVOKER mode then the service that has Aeron contained within it needs to regularly invoke the the
AgentInvoker which can be obtained from the
MediaDriver.Context.driverAgentInvoker() property after the driver is launched. This mode can be suitable for a service running on a system with limited CPU resource.
For maximum throughput and the lowest latency then running in
DEDICATED mode is the best option if the server has sufficient available cores to run all the threads. Reducing the number of threads does not significantly reduce throughput especially for relatively low numbers of streams. For higher numbers of streams (high 10s or above) then dedicated threads provide greater throughput.
Dedicated threads provide the lowest possible latency when CPU cores are available to run those threads. This allows the threads to react as soon as possible without having to wait for alternative tasks to complete. Alternative tasks that can pollute CPU caches which further increases latency.
If you are altering the thread configuration you should think carefully about how this interacts with the
IdleStrategy options that can also be configured on a per thread basis.
The Aeron client contains a conductor agent which runs every few milliseconds (16 default) to check of new images are available for a subscription and to check timeout and heartbeat to the driver for indicating the client is alive. This agent can be invoked directly like the driver to avoid having another thread by enabling the
Aeron.Context.useConductorAgentInvoker(boolean) property before connecting the client. After the client has been connected the AgentInvoker can be obtained from the
Aeron.Context.conductorAgentInvoker() property. This should be regularly invoked to keep the client alive. When this mode is enabled it is possible for further optimise the client by eliding the client lock if used from a single thread by setting the following property:
final Aeron.Context clientCtx = new Aeron.Context() .useConductorAgentInvoker(true) .clientLock(new NoOpLock);
If the client conductor agent is being invoked directly and the driver is in
ThreadingMode.INVOKER then the client also needs to set the
Aeron.Context.driverAgentInvoker(AgentInvoker) property to support synchronous calls from the client to the driver for adding publications and subscriptions.
final MediaDriver.Context driverCtx = new MediaDriver.Context() .threadingMode(ThreadingMode.INVOKER); final MediaDriver mediaDriver = MediaDriver.launch(driverCtx); final Aeron.Context clientCtx = new Aeron.Context() .useConductorAgentInvoker(true) .clientLock(new NoOpLock) .driverAgentInvoker(driverCtx.driverAgentInvoker());