Bucket commit log: a 20 minute gate on real GCS
The commit-log store (main at 06568432, #538) run from GKE against a real GCS bucket with three replicas, a 100,000-document seed and about 20 minutes of write phases, to get the numbers the fake could not give: compaction speed, adopter cost, p99 under compaction, cold start, three writers. Audience: demarkus maintainers. Run 2026-10-04, about $5. Verdict: nothing lost (343,641 acknowledged versions read back, 0 gaps or breaks), one writer sustains 365 writes/s and the compactor keeps pace at 400 writes/s at this size; three replicas writing one world collapse to 94 writes/s with p50 5 s, which is the finding that needs work before phase 7; cold start and the 250 ms p99 need more parallelism and a node of their own to judge. Plan: the GCS gate; the local run it follows: local 1M scale test. Raw results under the ignored tools/benchmarks/artifacts/scale1m-2026-10-03/gcs-gate20/ (phase outputs, verify, server logs, counter samples, manifests); the replicas' per-call event files could not be copied out of the distroless pods.
Setup
- Cluster
demarkus(northamerica-northeast2-a), a tainted scratch pool of one n2-standard-4 (4 vCPU, 16 GB), namespacegate: three replica pods A, B, C (scale-server, the realknowledgeserver.Openwith a counting bucket wrapper, 1 vCPU requested, 3 to 4 GiB,GOMEMLIMIT3.5 GiB, 16 shard workers), peer hints between them over QUIC, and a load pod runningscale-loadon the same node. Images from a scratch Artifact Registry repository; GCS through Workload Identity on a scratch service account. - Bucket
scale1m-gate-49722, Standard, same region, uniform access, soft delete off. - The harness build shortened the checkpoint cadence to 2,048 slots or 2 minutes so the test yielded a dozen steps; the step bound (32,768 documents) and every other constant are the release's.
- Documents: agent-shaped markdown of about 4 KB with tags and metadata, blind publishes; updates hit random documents. The world grew from 100,000 to about 245,000 documents, so shards went from 512 to 1,024.
Results
| Phase | Result |
|---|---|
| Seed 100k on A, 64 writers | 316/s, 0 errors, p50 173 ms, p99 440 ms, 5.3 min |
| Open 200/s on A, B and C follow, 5 min | 196.8/s, 59,080 acknowledged, 0 errors, p50 180 ms, p99 8.0 s |
| Open 400/s on A, 5 min | 364.9/s, 109,527, 1,513 timeouts, p50 287 ms, p99 7.0 s |
| Closed 64 writers on A, 3 min | 258.8/s, 46,633, 0 errors, p50 209 ms, p99 901 ms |
| Open 300/s split over A, B, C, 3 min | 94.2/s, 17,812 (A 7,188, B 5,536, C 5,088), 8,861 timeouts, p50 5.5 s |
| Closed 64 writers split over three, 3 min | 58.2/s, 10,589, 92 errors, p50 841 ms, p99 3.2 s |
| Burst 300/s on A, 150 s (step timing) | 233/s, 2,112 timeouts in one 20 s stall |
| Log walk and read-back | 21,077 slots, 344,370 entries, 0 gaps, chain breaks or duplicates; all 343,641 acknowledged versions read, 0 bad |
| Cold start of a fresh C after the run | 10.2 s: 1,033 shards (193 MB) and 1,500 slots replayed, heap 381 MiB |
| Catalog lookups at 245k | * p50 60 ms, p99 166 ms; terms p50 143 to 147 ms, p99 175 to 182 ms |
| Heap, live | A 259 MiB after the seed, 1,412 MiB after the write phases, 655 MiB at the end; B 335, C 603 MiB |
No 429 or 5xx from GCS at any point; the stalls are not throttling. Slot wins over the whole run: A 19,471, B 879, C 727.
Compaction. The first step after genesis was written by all three replicas (checkpoint zero is exempt from the defer rule; A and C lost the checkpoint create), then B alone wrote the other twelve steps, 24k to 33k documents each, about every two minutes, with the lag at each landing under 10k at 200 writes/s and zero at 400 writes/s while one replica wrote; 23k to 35k while B wrote and compacted in the three-way phases. B's bucket operations over the run: 299k history block creates, 397k history block reads, 248k blob reads for segments, 8.7k shard creates, 1.2k segment parts: about 3.2 bucket operations per changed document, two of them reads. One sampled step (1,656 documents at 1,024 shards): history blocks in 6 s at about 280 creates and 200 reads per second, 832 shards in 6 s (about 140 shards of 200 KB a second, 28 MB/s), segments 10 s. The steps of 29k documents under 400 writes/s took at most 113 s including their trigger wait. After the final burst no step ran: the compactor has no timer, so a world that goes quiet keeps its last slots (here 1,500) for the next cold start to replay, by design.
Stalls. Open 200 had three windows where p50 jumped to 2 s, open 400 two windows of 20 s where throughput fell to 93 and 250 writes/s and 16 slot creates passed the 10 s request deadline. They line up with B's steps and with A adopting them (reading every shard, replaying the base). Pod CPU stayed at 0.2 to 1.5 cores and the node under 51%, so this is not the fake's lock and not the bucket; it is A's own work during adoption plus shared CPU on a 4 vCPU node that also ran the compactor and the load generator. The 250 ms p99 gate at 200 writes/s is therefore not judged here: between stalls the windows ran at the offered rate with p50 170 to 180 ms.
Three replicas writing is the result that matters. Fairness held (A 7,188, B 5,536, C 5,088 acknowledged) but every replica answered at p50 5 s and the world took 94 writes/s against 259 to 365 with one writer. Each slot create races three ways; a loser reads the winner's slot, catches up, rebuilds and may hold its next create up to a second for a hint, all at 40 to 50 ms a call on GCS. The local two-replica runs were fair and slow in the same way (86 writes/s closed loop), which the fake's lock was blamed for; it is the design under real latency. The compactor also lived on B during these phases, which cost B.
Projection to 1,000,000 documents
- Compaction capacity, from the measured rates at 16 workers: a 32,768-document step is about 120 s of history blocks (creates plus the reads of the blocks being extended) plus 30 to 60 s of shards (4,096 or 8,192 at 28 MB/s) plus segments once per window, so 150 to 180 s per step, about 180 to 220 documents a second. Break-even near 200 writes/s; at a sustained 400 writes/s the lag grows. The knob is the compactor's worker count: 32 to 48 doubles or triples the history phase, at 560 to 840 bucket operations a second next to the writers' 440 at 400 writes/s, which is at the bucket's envelope of about 1,000. The segment reads (0.8 blob reads per changed document) are the other lever.
- Cold start: 1,033 shards in about 5 s and 1,500 slots in about 4 s at 16 workers project to 20 s for 4,096 shards and 40 s for 8,192, plus up to 20 s for a 10 minute backlog of 8,192 slots. The 15 s gate needs the cold start to read with 64 workers, as the phase 0 spike did (4,096 shards in 7.6 s), not 16.
- Heap: 655 MiB idle at 245k documents is 2.7 KB a document, consistent with the 2 GiB measured locally at 1M; A's 1,412 MiB after the write phases is the compactor base's divergence and version records before adoption, which the 10 minute cadence makes several hundred MB at 1M.
- Three writers: no projection; it is a design result, not a scale one.
What to do before phase 7
- Several replicas writing one world. Measure two and three replicas at a fixed offered rate below saturation, with the compactor pinned away from the writers, and the hold time and hint path instrumented; then decide between a shorter hold, a leader-writer per world above the store (rejected in ADR 0036 as a layering violation, to be reweighed against 94 writes/s), or accepting that a world has one writing replica in practice. This is the gate's one failure.
- Cold start with 64 shard workers, and a gate run at 1M on a node where the compactor and the writer do not share CPU, for the 250 ms p99.
- Compactor workers as a constant to size from the capacity numbers above, with segments' blob reads counted.
- The first step after genesis is written by every replica, since checkpoint zero is exempt from the defer rule; three copies of one 32k step is tolerable once per world, but a world created and seeded at speed pays it.
Cost
About 0.7 M Class A operations (writers' blobs and slots, the compactor's history blocks, shards and segments), about 1 M Class B, one n2-standard-4 for about 1.5 hours, negligible storage with soft delete off: about $5 at list prices, to be confirmed in billing under the scale1m-gate labels.