Per-core Worker Model#
1. Overview#
The per-core worker model assigns a dedicated worker execution context to a CPU core (or equivalent hardware slice). Each worker hosts an independent runtime, scheduling loop, and local state for the partitions it owns. The model trades coarse-grained multiprocessing and locks for per-worker isolation and cooperative, event-driven concurrency inside each worker to achieve low-latency, high-throughput operation.
2. Motivation#
Reduce synchronization overhead: by keeping most state and execution local to a worker, the design minimizes cross-thread locking and atomic contention.
Predictable latency: per-core affinity reduces context-switch jitter and improves cache utilization for hot data and code paths.
Scalable concurrency: many lightweight async tasks can run cooperatively inside a worker without spawning OS threads for each task.
Operational isolation: faults or overloads can be contained to a worker and handled via drain/restart or partition migration.
3. Per-worker model#
Affinity: a worker is typically pinned to a CPU core (or logical core) and runs a single-threaded event loop or an io_uring-backed runtime.
Runtime components inside a worker:
Event loop / async executor: cooperatively schedules tasks (async functions, syscalls, timers).
Local task queues: high-priority and background queues to separate latency-sensitive work from housekeeping.
Partition-local state: storage and caches for partitions assigned to this worker (physical relations keyed by (table_id, partition_id)).
Networking endpoint: a per-worker TCP listener (when tcp_multi_port enabled) or shared acceptor with handoff.
Concurrency model: cooperative multitasking using async/await primitives (or transpiled equivalents). Tasks yield on I/O or when awaiting remote RPC results, allowing other tasks to make progress without OS thread switches.
Implementation notes:
Use of io_uring or an efficient async runtime (Tokio) inside the worker to achieve high I/O concurrency with low overhead.
Workers allocate and manage fixed resources (thread-local caches, pre-registered buffers) to reduce runtime allocation costs.
6. Inter-worker communication#
Message-passing: workers communicate via well-defined message channels or RPC over an internal message bus rather than shared-memory locks for coordination and remote partition access.
Remote partition RPCs: when a worker receives a request for a partition it does not own, it forwards the request to the owning worker via the internal RPC channel. The requester awaits the response asynchronously.
Backpressure and flow control: senders must handle backpressure (bounded queues) and apply retries or circuit-breaker logic if a target worker is overloaded.
Ordered vs unordered messages: important operations (e.g., commit-phase messages) may require ordering guarantees; the message layer supports ordering or causal sequencing when needed.
Batch and coalescing: small remote requests are often batched or coalesced to reduce per-message overhead and improve throughput.
Failure handling:
Detect remote worker failure quickly (timeouts, connection errors) and trigger topology refresh and partition re-assignment.
Drain and replay: when migrating partitions, workers drain outstanding messages and may replay or forward inflight operations during migration.
7. Data locality and partitioning#
For a comprehensive explanation of the partition model, placement, and the partition -> worker mapping, see the Partitioning document: ./partitioning.md
Partition placement: logical partitions are assigned to workers (partition_id -> worker_id). Workers keep local copies of the placement and expose endpoints for their owned partitions.
Local execution: operations for partitions owned by the local worker execute without inter-worker RPCs, exploiting cache locality and minimized locking.
Routing: the client or adapter resolves partition -> worker mapping (via topology) and opens sessions bound to the target worker to achieve direct locality.
Hot partition mitigation: hot partitions can be monitored and moved, or split into finer-grained partitions, to distribute load across workers.
Interaction with per-core model:
Because each worker concentrates storage and execution for its partitions, per-core affordances (CPU caches, local buffers, pinned threads) amplify locality benefits.
Sharded TCP ports and per-worker listeners improve accept affinity and reduce kernel-networking contention, aligning network flows with partition ownership.
Summary
The per-core worker model balances high performance and operational simplicity by localizing state and using cooperative asynchronous concurrency inside each worker while relying on message-passing for cross-worker coordination. It is particularly effective for workloads with strong locality and predictable partitioning semantics.