Skip to content

Thread Utilisation

Martin Thompson edited this page Nov 20, 2018 · 9 revisions

Aeron can trade 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.

Media Driver

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.

Aeron Client

The Aeron client contains a conductor agent which runs every few milliseconds (16 default) to check if new images are available for a subscription, and to check timeouts 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.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(mediaDriver.sharedAgentInvoker());