0004. Dispatch a key's next batch when its previous one completes¶
Status: Accepted
Context¶
A batch delay trades latency for batch size: every input waits up to maxBatchDelay so that more can join it. Tuned for
peak load, it adds latency at every other load; tuned for low load, batches stay small at peak, which is exactly when
size matters. A fixed delay is right at one load only.
With one batch in flight per key (0003), there is a better signal than a timer: the key's previous batch. While it is in flight, new inputs for the key cannot be sent anyway.
Decision¶
PerKeyConfig.maxBatchDelay defaults to zero. A key's waiting inputs are dispatched as soon as the key is free and a
worker is available, so the next batch carries everything that arrived during the previous round trip:
- at low load, an input goes out alone, immediately: no added latency;
- at high load, batches grow by themselves to the arrival rate times the round-trip time, up to
maxBatchSizeandmaxBatchWeight; - as long as one batch can carry what arrives during one round trip, an input waits at most for the round trip in
flight plus its own. Beyond that rate the key is saturated: inputs queue, and
maxQueueingdecides when to reject.
This is the group-commit pattern, and the way end-to-end batching databases (TigerBeetle, for one) keep latency low without a batching window.
A positive maxBatchDelay is still available, for a downstream that charges per call regardless of load and rewards
fuller batches even when the key is idle.
Consequences¶
- Batch size is no longer a configured constant but a function of load; dashboards should show the batch fill ratio
(batch size over
maxBatchSize) to read the load from it. - With zero delay,
maxBatchSizeandmaxBatchWeightare the only limits on a batch; they must reflect the downstream's real per-request limits.