Skip to content

Latest commit

 

History

History
233 lines (187 loc) · 16.3 KB

File metadata and controls

233 lines (187 loc) · 16.3 KB

Chronicle Threads - Functional Requirements Specification

1. Purpose and Scope

This document specifies the functional requirements for the Chronicle Threads library (OpenHFT / Chronicle Software). It is aimed at architects, developers, and performance engineers who intend to use Chronicle Threads as the execution engine for ultra-low-latency, event-driven Java systems.

Out of scope are: * Detailed Non-Functional Requirement (NFR) specifications beyond the key performance targets identified in the Key Performance Targets section. * Licensing and commercial support details. * The detailed product roadmap (though the Open Issues / Future Enhancements section outlines potential future enhancements).

2. Definitions

Term Meaning

EventLoop

A single-threaded loop that repeatedly invokes EventHandler instances.

EventHandler

Application-provided component that implements action(); executed by an EventLoop.

EventGroup

A container that manages one or more `EventLoop`s, potentially including a dedicated monitor loop.

Pauser

Strategy object that controls how an idle loop waits (e.g., busy-spin, yield, sleep).

Fast Thread

A thread-usually pinned to an isolated CPU core-running a latency-critical event loop.

Hot Path / Fast Path

The code execution path that is performance-critical and frequently executed, where low latency and minimal overhead are paramount.

Loop-Block Monitor

Background handler that measures EventHandler run-time and logs outliers exceeding a configured threshold.

NUMA

Non-Uniform Memory Access; a memory architecture where memory access time depends on the memory location relative to a processor.

Chronicle Affinity

A library used for managing thread affinity, allowing threads to be pinned to specific CPU cores.

3. Overall Architectural Goals

  • Minimise end-to-end latency and jitter for event processing.

  • Provide a deterministic single-threaded execution model for event handlers within an EventLoop, removing the need for locks in the hot path of handler logic.

  • Allow fine-grained control of the latency versus CPU consumption trade-off.

  • Integrate effectively with other Chronicle components (e.g., Chronicle Queue, Chronicle Map, Chronicle Wire, Chronicle Services, Chronicle Tune).

4. High-Level Functional Requirements

4.1. Event-Loop Lifecycle and Configuration

  1. Creation and Configuration THR-FN-001 The library SHALL provide builder APIs (e.g., EventLoopBuilder, EventGroupBuilder) for fluent and immutable configuration of event loops and groups.

  2. Start/Stop Operations THR-FN-002 An EventLoop or EventGroup SHALL support idempotent start() and graceful close() operations. A graceful close() implies that active handlers are allowed to complete their current action, and associated resources are released.

  3. Non-Restartable Loops THR-FN-003 Attempting to start() an EventLoop or EventGroup that has already been `close()`d SHALL be rejected or have no effect, as loops are not designed to be restartable.

4.2. Handler Management

  1. Dynamic Registration THR-FN-004 Clients SHALL be able to add an EventHandler to a running EventGroup at runtime.

  2. Handler Priority THR-FN-005 Each EventHandler SHALL declare a HandlerPriority. The system SHALL support a range of priorities influencing execution order and/or loop assignment. (Refer to net.openhft.chronicle.core.threads.HandlerPriority enum for the exhaustive list of priorities, e.g., HIGH, MEDIUM, LOW, TIMER, BLOCKING, REPLICATION, CONCURRENT, MONITOR, DAEMON). An EventGroup SHALL be configured with a set of supported priorities; loops are only created for enabled priorities and attempts to add a handler whose priority has no corresponding loop SHALL be rejected.

  3. Execution Contract THR-FN-006 An EventHandler’s `action() method MUST be invoked serially on the EventLoop’s dedicated thread. THR-FN-007 The `action() method MUST return a boolean: true if useful work was done (suggesting the handler may have more immediate work), false otherwise.

  4. Self-Deregistration THR-FN-008 An EventHandler MAY request its own deregistration from the EventLoop by throwing net.openhft.chronicle.core.threads.InvalidEventHandlerException.

  5. Error Isolation and Reporting THR-NF-O-009 Unchecked exceptions thrown by an EventHandler’s `action() method SHALL NOT terminate the EventLoop itself. The offending handler SHALL be removed, and the error SHALL be reported using the standard net.openhft.chronicle.core.Jvm.warn() logging mechanism by default.

4.3. Idle Strategy (Pauser)

  1. Supported Pauser Modes THR-FN-010 The library SHALL ship with a set of standard Pauser strategies, configurable via PauserMode enum values, including at least: BUSY, TIMED_BUSY, YIELDING, BALANCED, MILLI, and SLEEPY. (Refer to net.openhft.chronicle.threads.PauserMode.java and README.adoc for details on each mode).

  2. Custom Pauser Pluggability THR-FN-011 Applications SHALL be able to supply custom Pauser implementations via programmatic configuration (e.g., through builder APIs like EventGroupBuilder.withPauser(Pauser customPauser)).

  3. Adaptive Back-off Parameterisation THR-FN-012 Adaptive pausers (such as LongPauser, which underpins modes like BALANCED and SLEEPY) SHALL allow parameterisation of their back-off behaviour, including aspects like minimum busy-spin duration, yield duration, and minimum/maximum sleep times.

  4. TimingPauser Support THR-NF-O-013 TimingPauser implementations (e.g., LongPauser, BusyTimedPauser) SHALL expose pause-related metrics (e.g., total time paused via timePaused(), pause count via countPaused()) and SHALL optionally throw java.util.concurrent.TimeoutException when a configured timeout duration is exceeded during a timed pause.

  5. Zero-Allocation Hot Path THR-NF-P-014 The hot path methods Pauser.pause() and Pauser.reset() for built-in pausers SHALL NOT allocate heap objects.

4.4. Thread Affinity and CPU Isolation

  1. CPU Affinity API THR-FN-015 The library SHALL provide mechanisms to bind EventLoop threads to specific CPU cores, utilizing Chronicle Affinity. This SHALL be configurable via builder APIs (e.g., EventGroupBuilder.withBinding(String affinity)).

  2. CPU Isolation Guidance THR-DOC-016 Documentation (README.adoc) SHALL recommend OS-level isolation of CPU cores (e.g., using isolcpus on Linux) for EventLoop threads when latency-sensitive pausers (like PauserMode.BUSY or PauserMode.TIMED_BUSY) are used, to minimize jitter.

  3. NUMA Awareness THR-FN-017 Builders SHOULD allow configuration that facilitates pinning EventLoop threads to specific NUMA nodes. This is typically achieved via the binding string syntax provided to Chronicle Affinity, which can specify core layouts respecting NUMA topology.

4.5. Monitoring and Diagnostics

  1. Loop Block Monitoring THR-NF-O-018 For an EventGroup, a dedicated monitor loop (e.g., MonitorEventLoop) SHALL, by default, measure the wall-clock duration of EventHandler invocations on other event loops within the group. THR-NF-O-019 If an EventHandler’s `action() method duration exceeds a configurable threshold (defaulting to a value specified by loop.block.threshold.ns), the framework SHALL capture and log a stack trace of the event loop thread executing that handler.

  2. Monitoring Configuration Toggles THR-OPS-020 Loop block monitoring MAY be disabled globally via a system property (e.g., disableLoopBlockMonitor=true). The monitoring interval SHALL also be configurable (e.g., MONITOR_INTERVAL_MS).

  3. Pauser Metrics Accessibility THR-NF-O-021 Key metrics from Pauser instances, such as timePaused() and countPaused(), SHALL be programmatically accessible. Implementations of PauserMonitorFactory MAY provide handlers to monitor and log these.

  4. Low-Overhead Monitoring THR-NF-P-022 When all EventHandler invocations are within their execution thresholds, the loop block monitoring mechanism MUST impose negligible overhead (target < 1 us overhead per monitored loop per second, excluding logging actions if a threshold is breached).

4.6. Configuration and Deployment

  1. System Property Overrides THR-OPS-023 Default behaviours and parameters (e.g., pauser modes, monitor intervals, logging thresholds) SHALL be overridable via JVM system properties. (Refer to systemProperties.adoc for a comprehensive list; Appendix B provides examples).

  2. Programmatic Configuration Precedence THR-OPS-024 Programmatic configurations provided via builder APIs SHALL take precedence over global system property settings.

  3. Graceful JVM Shutdown Hook THR-OPS-025 An EventGroup instance, when configured appropriately (e.g., via ((net.openhft.chronicle.core.io.AbstractCloseable) eventGroup).addShutdownHook(true)), SHALL attempt to close() automatically on JVM exit.

  4. JDK Compatibility THR-NF-O-026 Chronicle Threads SHALL run on Java 11 LTS or newer. The library SHALL default to using platform threads. While aiming for compatibility with JDK Project Loom (virtual threads) for suitable use cases (e.g., blocking handlers not requiring core affinity), full support and affinity guarantees with virtual threads depend on JDK evolution and are subject to considerations detailed in the Open Issues / Future Enhancements section.

5. Key Performance Targets

These non-functional targets guide the design and optimization of Chronicle Threads for ultra-low-latency scenarios. They are primarily applicable when using performance-oriented pausers (e.g., BUSY) on suitably configured systems (e.g., with isolated cores).

THR-NF-P-027 Latency: Single-hop message processing through an event handler SHALL target ⇐ 10 us at the 99.99th percentile on commodity x86_64 hardware with a busy pauser and isolated cores. THR-NF-P-028 Jitter: Peak-to-peak variation in handler execution time SHALL target ⇐ 2 us under steady load conditions for well-behaved handlers. THR-NF-P-029 Throughput: A single "fast core" EventLoop SHALL be capable of processing >= 5 million simple (e.g., 64-byte payload) events per second. THR-NF-P-030 Heap Allocation: In the hot path of event processing (i.e., within the EventLoop and EventHandler.action() calls for common use cases), heap allocation SHALL target ⇐ 0.1 Bytes per event on average. Pauser hot paths are covered by THR-NF-P-014. THR-NF-P-031 CPU Utilisation: * PauserMode.BUSY SHALL consume 100% of its assigned (and ideally isolated) CPU core. * Adaptive pauser modes (e.g., BALANCED, SLEEPY) SHALL reduce CPU consumption significantly (e.g., target < 20%) when the event loop is idle.

6. Documentation, Testing, and Traceability

ID Requirement Artefact(s)

THR-DOC-032

Publish an architecture overview that illustrates loop composition, handler routing, and affinity guidance, keeping it aligned with the functional catalogue.

architecture-overview.adoc

THR-DOC-033

Maintain an operational controls playbook detailing CPU isolation, monitoring thresholds, and configuration precedence so operators can enforce safe defaults.

operational-controls.adoc

THR-DOC-034

Record security considerations for handler admission, affinity, telemetry integrity, and dependency posture, updating the review after material changes.

thread-security-review.adoc

THR-DOC-035

Provide a thread-safety guide that explains confinement rules, hand-off patterns, and testing practices for event loop handlers.

thread-safety-guide.adoc

THR-TEST-036

Automate benchmark and soak tests that demonstrate compliance with latency, jitter, throughput, and allocation targets.

thread-performance-targets.adoc

7. Use-Case Scenarios

7.1. Matching Engine

A financial matching engine processes incoming orders and market data. Multiple EventHandler instances (e.g., for order book management, risk checks, trade execution) share a HIGH priority EventLoop pinned to an isolated CPU core (Core 2). (Illustrates: THR-FN-005, THR-FN-006, THR-FN-015, THR-NF-P-027) A MEDIUM priority EventLoop on a separate core (Core 3) handles journalling of trades and significant events to Chronicle Queue. (Illustrates: THR-FN-005, THR-FN-015) A MONITOR loop, possibly on a non-isolated core, supervises both application loops. (Illustrates: THR-NF-O-018)

7.2. Bursty Telemetry Ingestion

An EventLoop configured with a PauserMode.BALANCED ingests UDP packets containing telemetry data. The EventHandler parses these packets (e.g., using Chronicle Wire) and forwards them to a Chronicle Queue for downstream processing. During off-peak hours, CPU usage for this loop drops significantly (e.g., below 5%) due to the pauser’s adaptive back-off. During bursts, it processes events with low latency. (Illustrates: THR-FN-010, THR-FN-012, THR-NF-P-031)

8. References

  • Chronicle Threads README.adoc (Provides overview, usage examples, and pauser details)

  • systemProperties.adoc (Comprehensive list of configurable JVM system properties)

  • net.openhft.chronicle.core.threads.HandlerPriority Javadoc (Definitive list of handler priorities)

  • net.openhft.chronicle.threads.PauserMode Javadoc (Definitive list of pauser modes)

  • Chronicle Affinity library documentation (For details on CPU binding syntax and capabilities)

  • architecture-overview.adoc (Runtime topology)

  • operational-controls.adoc (Operational safeguards)

  • thread-performance-targets.adoc (Benchmark methodology)

  • thread-security-review.adoc (Security posture)

  • thread-safety-guide.adoc (Confinement practices)

9. Open Issues / Future Enhancements

This section lists areas identified for potential future development or requiring further investigation. They are not committed functional requirements for the current version.

  • Support for carrier-thread reuse with JDK virtual threads while retaining affinity guarantees where possible.

  • First-class asynchronous I/O helper components to better integrate frameworks like Netty or java.nio.channels directly with `EventLoop`s.

  • Live reconfiguration of Pauser parameters via JMX or a similar management interface.

  • Enhanced built-in metrics publication mechanisms beyond basic pauser counters and loop-block logs.

10. Appendices

10.1. A Builder Example

EventGroup eg = EventGroup.builder()
        .withName("MatchingEngineGroup") // Sets the base name for the EventGroup and its child loops
        .withLoopCount(2) // Example: might influence number of certain types of loops if applicable
        .withPauserMode(PauserMode.BUSY) // Sets default pauser for core loops
        .withPriorities(EnumSet.of(HandlerPriority.HIGH, HandlerPriority.MEDIUM, HandlerPriority.MONITOR)) // Specify which handler priorities this group will support; if configured with an empty set only the monitor loop is present and handlers with any other priority are rejected
        .build();

// Add application-specific handlers
eg.addHandler(new MatchingEngineOrderHandler()); // Assuming this implements EventHandler
eg.addHandler(new JournalWriterHandler());      // Assuming this implements EventHandler

eg.start();

// finally
eg.close();

10.2. B System Properties Quick Reference

This is a non-exhaustive list of key system properties. For a comprehensive list, refer to the systemProperties.adoc document.

Property Effect / Default (Illustrative)

pauserMode

Global override for default pauser selection (e.g., busy, balanced). Used if not specified by builder.

loop.block.threshold.ns

Nanoseconds before a handler invocation is flagged as a block (Default: 100,000,000 ns = 100 ms).

MONITOR_INTERVAL_MS

Sampling interval for the monitor loop (Default: 100 ms).

disableLoopBlockMonitor

Set to true to disable loop block monitoring (Default: false).

eventGroup.conc.threads

Default number of threads for CONCURRENT priority handlers (Default: Varies, e.g., CPU cores / 4).

chronicle.disk.monitor.disable

Set to true to disable the disk space monitor (Default: false).

chronicle.disk.monitor.threshold.percent

Disk usage percentage above which warnings are issued (Default: 5%).