lgoyal6 / tautq

tautq.

A distributed webhook-delivery service across five nodes with no coordinator, built on a reliable-UDP transport and SWIM membership written from scratch. A job is durable on a majority before the submit is acknowledged.

The knee is at about 800 jobs a second, and past 1000 it does not degrade gracefully. Those rows are in the CSV. They are shown here as what they are rather than left out or drawn as a curve.

flat p99 band
63 ms up to 600 jobs a second
at the knee
107 ms p99, at 800/s
past it
0 completed at 1000/s
the cause
~9 fsyncs per job, cluster-wide
Figure 1

The ramp, and where it stops holding

Twenty seconds at each offered rate. Up to 600 a second the tail sits in a flat band: the worker poll interval plus delivery plus two majority commits. The band is what a healthy system looks like, and leaving it is the signal.

Loading
Offered rate
offered
-
accepted
-
completed
-
p50
-
p99
-

Why it saturates where it does

Every job costs roughly nine fsyncs cluster-wide: submit, lease and done on the owner, plus the replica appends behind each. At 800 a second that is about 1,400 fsyncs per second per node, and the design commits one at a time. The transport is not the limit; the disk barrier is.

Group commit already exists in the write-ahead log as an unbatched call and a separate sync. Turning it on is the known next step, and it is not implemented, so the number on this page is the number without it.

flat band
63 ms p99, to 600 a second.Poll interval plus two majority commits.
the knee
800 a second.p99 leaves the band and reaches 107 ms.
the fix, not yet done
Group commit.The arithmetic says fsync, not transport.
Figure 2

What packet loss costs

Held at 200 jobs a second, well under the knee, so loss is the only thing changing. Loss is injected on every node's UDP ingress, which means a dropped packet can be a submit, a replica append, or a membership probe.

Loading 200 jobs a second at every point
UDP loss
loss
-
completed
-
p50
-
p95
-
p99
-

Nothing is lost up to 20% packet loss. Every job that was accepted still completed at every point on this chart, which is what the retransmit and the majority commit are for. What changes is the tail.

At 10% loss the p99 is 127 ms, roughly double the clean figure. At 20% it is 1,019 ms, sixteen times. A retry costs a round trip and the round trips compound, so the tail moves long before the throughput does.

correctness
Unchanged to 20% loss.Everything accepted still completed.
the tail
63 ms to 1,019 ms.Sixteen times, at 20% loss.
where it turns
Between 10% and 20%.p95 goes 79 ms to 633 ms.
Figure 3

The rows that are not published

Two steps past the knee are in the CSV and are not in the results table. Here they are, and here is why they are not a measurement of anything.

why they are excluded

Past about 1000 a second the cluster does not degrade gracefully: nodes become intermittently unresponsive, submits and scrapes time out, and the step stops offering the load it was told to. At 1000 the harness offered 2,960 of the 20,000 it was asked for and nothing completed inside the window, so the percentile columns are a sentinel rather than a latency. At 1200 the completions are backlog from earlier steps draining, which is why that row reports more completed than it offered.

Figure 4

Where it loses