<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Hugo Vantighem</title>
    <description>The latest articles on DEV Community by Hugo Vantighem (@hugo_vantighem).</description>
    <link>https://dev.to/hugo_vantighem</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3947999%2Fe0a53736-f880-455e-9965-c3b4bf950342.jpg</url>
      <title>DEV Community: Hugo Vantighem</title>
      <link>https://dev.to/hugo_vantighem</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/hugo_vantighem"/>
    <language>en</language>
    <item>
      <title>Invariant-Driven Architecture: 20M transactions on a €80/mo Cloud VM.</title>
      <dc:creator>Hugo Vantighem</dc:creator>
      <pubDate>Mon, 25 May 2026 06:27:00 +0000</pubDate>
      <link>https://dev.to/hugo_vantighem/invariant-driven-architecture-20m-transactions-on-a-eu80mo-cloud-vm-47b4</link>
      <guid>https://dev.to/hugo_vantighem/invariant-driven-architecture-20m-transactions-on-a-eu80mo-cloud-vm-47b4</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;📎 This is Part 2. &lt;strong&gt;&lt;a href="https://dev.to/hugo_vantighem/postgres-grade-serializable-at-20k-opss-on-a-laptop-dont-try-this-at-home-f27"&gt;Part 1 — Postgres-grade serializable at 20k ops/s on a laptop (don't try this at home)&lt;/a&gt;&lt;/strong&gt; presented 20,000+ durable, invariant-validated transactions per second — on a MacBook Air M3, 8 cores, fan barely audible.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A laptop number is only half the story. The natural next test is whether the same architecture holds on a small, cheap public VM with &lt;strong&gt;network-attached storage&lt;/strong&gt; and &lt;strong&gt;strict &lt;code&gt;fsync(2)&lt;/code&gt; durability&lt;/strong&gt; — three constraints that each, on its own, tend to move the bottleneck by an order of magnitude on most stacks. So that's what I ran.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Setup
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;VM:&lt;/strong&gt; Scaleway POP2-2C-8G — 2 vCPUs AMD EPYC 7543 @ 2.8 GHz, 8 GiB RAM. Yes — &lt;em&gt;two&lt;/em&gt; vCPUs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Disk:&lt;/strong&gt; SBS Block storage, 100 GB, 15,000 provisioned IOPS. Network-attached, &lt;em&gt;not&lt;/em&gt; local NVMe.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OS:&lt;/strong&gt; Ubuntu 22.04, kernel 5.15. Linux strict &lt;code&gt;fsync(2)&lt;/code&gt; — every commit hits the SSD for real, no Apple-style controller-cache shortcut.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Software:&lt;/strong&gt; the exact same codebase that ran on the M3, with NATS + Mongo + Mongo Express as the side stack in Docker.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Price:&lt;/strong&gt; ~€80/month order-of-magnitude — ~€54 of compute (POP2-2C-8G at €0.0735/h) plus ~€20–25 of SBS volume with provisioned IOPS. Hourly that's €0.11.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Two names, one stack
&lt;/h3&gt;

&lt;p&gt;Two terms surface across this series. They sit at different layers, so it's worth pinning them now.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Invariant-Driven Architecture (IDA)&lt;/strong&gt; — the &lt;em&gt;design philosophy&lt;/em&gt;. The system, end to end (ingress, sequencer, system, storage), is engineered around a single obsession: validating and enforcing business invariants on every commit, with no compromise on throughput. It's a DDD-based philosophy.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Atomic State Platform&lt;/strong&gt; — the &lt;em&gt;concrete implementation&lt;/em&gt;. The software we're benchmarking right here — that just put down 33,091 sustained items per second on a €80/mo Scaleway VM.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;IDA is &lt;strong&gt;how&lt;/strong&gt;. Atomic State is &lt;strong&gt;what&lt;/strong&gt;. The €80/mo VM is &lt;strong&gt;where&lt;/strong&gt;. The rest of this post is &lt;strong&gt;how much&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. The Visual Punch — 10 minutes non-stop, 20 million items 📈
&lt;/h2&gt;

&lt;p&gt;The first test is the one that closes the &lt;em&gt;"but does it sustain?"&lt;/em&gt; question forever.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;BENCH_DURATION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;10m &lt;span class="nv"&gt;BATCH_SIZE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1000 make cloud-bench-broker
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Result, over 600 consecutive seconds on the POP2:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Throughput sustained&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;33,091 items/s&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Total items committed&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;19,855,000&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WAL bytes written&lt;/td&gt;
&lt;td&gt;7.6 GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;p99 round-trip&lt;/td&gt;
&lt;td&gt;71 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Integrity audit&lt;/td&gt;
&lt;td&gt;✅ INTEGRITY_OK (1,000 aggregates)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Durability&lt;/td&gt;
&lt;td&gt;FSYNC-ON (Linux strict)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Yes, that's &lt;em&gt;higher&lt;/em&gt; than the laptop — and on network-attached storage, not local NVMe. SBS is block storage over the data-center fabric; every &lt;code&gt;fsync&lt;/code&gt; round-trips to the SBS backend before it returns. Measured &lt;code&gt;fsync&lt;/code&gt; latency on this volume: &lt;strong&gt;2.0 ms&lt;/strong&gt; (vs 130 µs on the laptop's local NVMe — 15× slower per call). The 33,091 items/s holds &lt;em&gt;despite&lt;/em&gt; the network disk, not because of a fast one. Pebble's group commit amortises that 2 ms across the whole batch — roughly 2 µs of effective &lt;code&gt;fsync&lt;/code&gt; cost per item. That ratio is the architectural lever.&lt;/p&gt;

&lt;p&gt;More on why the cloud beats the laptop on this same scenario in §4. For now, the headline isn't the number. &lt;strong&gt;The headline is the steadiness.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I sampled the engine's &lt;code&gt;/metrics&lt;/code&gt; and the host's resource counters every 15 s through the entire run. Three things every senior engineer should care about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;pebble_health.l0_files&lt;/code&gt; stays in &lt;code&gt;[0, 6]&lt;/code&gt; the whole 10 minutes. Never higher. Compaction kicks in the moment L0 hits 6, completes before the next batch needs the slot.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;compactions_in_progress&lt;/code&gt; oscillates &lt;code&gt;0 ↔ 1&lt;/code&gt; — Pebble is keeping up in real time, never queueing.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;estimated_debt_bytes&lt;/code&gt; never crosses 100 MB — less than 1% of the WAL written.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At this scale — 34 MB/s sustained ingestion, ~20 GB of raw data committed — a mis-tuned LSM-tree triggers a &lt;strong&gt;Write Stall&lt;/strong&gt;: the engine has to pause writes while compaction catches up, and the curve falls off a cliff. We see none of that. The &lt;code&gt;puts&lt;/code&gt; counter climbs linearly from 0 to 19.85 M across the whole 10 minutes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1xvt5eg9wsbb9jzuyssu.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1xvt5eg9wsbb9jzuyssu.webp" alt=" " width="800" height="489"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;CPU%, L0 files and debt_MB never drift outside the bands shown above during the active 10-minute window.&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[preflight] measured: lat_avg=2 051 µs iops=487
[preflight] Mac ref:  lat_avg=131 µs   iops=7 568 (M-series NVMe, same fio command)
[preflight] gate:     lat_avg &amp;lt;= 5 000 µs (override via SCW_FSYNC_MAX_LAT_US)
✅ PASS - instance is fsync-fast enough for a meaningful bench.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's what "industrial-grade" looks like on a VM that costs €0.11/h.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. The Ceiling Demo — batch=1000 vs batch=2000
&lt;/h2&gt;

&lt;p&gt;Now the test that tells us where the wall is. Same VM, same 1-minute window, double the batch:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh7vlegtgmb1xl82infyu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh7vlegtgmb1xl82infyu.png" alt=" " width="800" height="109"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;+2.8% throughput for +59% tail latency. Past 1,000 items per batch, more batching is just queueing. We've squeezed the disk dry.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Let's do the math on what the bottleneck is. The cloud-up preflight measured 2.0 ms average &lt;code&gt;fsync&lt;/code&gt; latency on this SBS volume (&lt;code&gt;fio --rw=randwrite --bs=4k --direct=1 --sync=1&lt;/code&gt;, the same command everywhere). At 33k items/s and one &lt;code&gt;fsync&lt;/code&gt; per batch, that's 60 ms of &lt;code&gt;fsync&lt;/code&gt; wall-time per second — 6% of the budget. Pebble's group commit already amortises &lt;code&gt;fsync&lt;/code&gt; across the whole batch.&lt;/p&gt;

&lt;p&gt;The remaining 94% of wall-time is CPU:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HTTP/JSON serialization on the producer&lt;/li&gt;
&lt;li&gt;1,000 invariant evaluations per chunk&lt;/li&gt;
&lt;li&gt;Pebble's batch building + commit&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The network-attached disk is no longer the wall. &lt;strong&gt;Two 2.8 GHz AMD EPYC vCPUs at sustained 70% CPU are.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The fact that doubling the batch buys 2.8% is the experimental proof: there's no more disk to amortise, only CPU to share.&lt;/p&gt;
&lt;h3&gt;
  
  
  The full numbers, side by side
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzorzta4ewfha4nqibv30.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzorzta4ewfha4nqibv30.png" alt=" " width="800" height="374"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Full side-by-side numbers for batch=1000 vs batch=2000.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Read the bold rows together: we halved the number of &lt;code&gt;fsync&lt;/code&gt;s (33.3 → 17.1 per second) and throughput barely moved (+2.8%). If the disk were the wall, cutting &lt;code&gt;fsync&lt;/code&gt;s in half would have bought a lot more. It didn't — because CPU holds a flat ~70% plateau across both runs. That's the ceiling, in two numbers.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv68udx3620q8qwrm0fk6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv68udx3620q8qwrm0fk6.png" alt=" " width="799" height="327"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Engine + system samples, every 5 s (abridged — start / mid / end). Same CPU band, same L0 transient peak (10), and acks (= fsyncs) running at exactly half the rate on bs=2000 for the same puts — one fsync per batch, batches twice as big, no throughput dividend.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  3. The Proof by Absurdity — 64 Workers on 2 Cores
&lt;/h2&gt;

&lt;p&gt;This is the test every junior engineer expects to &lt;em&gt;help&lt;/em&gt; throughput, and every senior engineer expects to &lt;em&gt;kill&lt;/em&gt; it. The reflex: &lt;em&gt;"if the engine is slow, scale out the producer."&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;make cloud-bench-perf-dense   &lt;span class="c"&gt;# 64 workers, batch=100&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Same VM. Same disk. Same system. The only change is the producer pattern.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0n4hrcb8d6btc6ekmap5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0n4hrcb8d6btc6ekmap5.png" alt=" " width="800" height="143"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Read that twice. &lt;strong&gt;CPU usage drops from 70% to 30% — and throughput collapses 5.5×.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That asymmetry is the signature of context-switching hell. The Linux scheduler spends its cycles swapping 64 producer goroutines + 64 HTTP request handlers + the system + 3 Docker containers across 2 physical cores. The real work-per-cycle drops; the cores &lt;em&gt;look&lt;/em&gt; idle because they spend their time saving and restoring register state. The engine's single-writer queue becomes the rendezvous point — workers pile up — p99 explodes to 1.7 seconds.&lt;/p&gt;

&lt;p&gt;This is the design principle of the engine stated as a measurement:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The engine is &lt;strong&gt;single-writer by design&lt;/strong&gt; — one writer to Pebble, no lock contention.&lt;/li&gt;
&lt;li&gt;The ingress &lt;strong&gt;must batch upstream&lt;/strong&gt; of the engine to amortise &lt;code&gt;fsync&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;More producer threads = &lt;strong&gt;less&lt;/strong&gt; throughput on a CPU-constrained host. Mathematically, not ideologically.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqoka1aidt0tkvyn9dza2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqoka1aidt0tkvyn9dza2.png" alt=" " width="800" height="396"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  4. The Mac Parallel — More Cores Buy More Headroom
&lt;/h2&gt;

&lt;p&gt;The same three scenarios, on the MacBook Air M3 from Part 1 (8 cores, 16 GB):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5gb32sjh8fgvyds15z15.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5gb32sjh8fgvyds15z15.png" alt=" " width="800" height="143"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Three readings:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;(a) On a single-worker pattern, the cloud Linux wins.&lt;/strong&gt; Mac &lt;code&gt;fsync(2)&lt;/code&gt; is ~15× faster than the cloud SBS per call (~130 µs vs ~2 ms), but at batch=1000 the per-batch &lt;code&gt;fsync&lt;/code&gt; is amortised over 1,000 items — and the rest of the pipeline (HTTP serialization, internal sequencing, scheduler) now dominates.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;(b) When the workload has CPU work to spare and concurrency is contained, the extra cores cash in.&lt;/strong&gt; Going from batch=1000 to batch=2000 adds compute per batch but releases parallelism inside the engine (more items concurrently invariant-checked by the system). The Mac has 6 extra cores to spend on it, so its throughput climbs +54% (23,755 → 36,549). The cloud, pinned at 2 vCPUs, gains only +2.8% on the identical change — it has no spare core to convert the extra parallelism into work.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;(c) The Mac does not flinch at 64 workers&lt;/strong&gt; — it has the cores to absorb them. This is the exact scenario where the 2-vCPU cloud VM collapsed to 5,992 (§3). The 8-core Mac runs the identical 64-worker, batch=100, payload=0 B workload at 43,392 items/s — 7.2× the cloud, and above its own single-worker broker run (23,755). Context-switching only becomes hell when threads vastly outnumber cores; with 8 cores the scheduler keeps up and the engine's single writer stays fed. The perf-dense collapse was never about the workload — it was about core count.&lt;/p&gt;

&lt;p&gt;The hierarchy of constraints is universal, regardless of OS, disk brand, or vendor SKU:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;batch size &amp;gt; producer concurrency &amp;gt; raw fsync speed&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Match those three to your hardware and your real ingress pattern, and the throughput follows. Get them wrong and a top-end laptop loses to a €80/month VM — or wins against one — depending on the day.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Numbers, at a Glance
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F92rjqrv5yf0zkio0osjf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F92rjqrv5yf0zkio0osjf.png" alt=" " width="799" height="220"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;€80/month is the order of magnitude — ~€54 of compute, ~€20–25 of provisioned-IOPS SBS volume. Hourly: €0.11. The whole bench session that produced the cloud rows of this table cost ~€0.05 of cloud time — at this scale, validating an architecture decision on a representative VM is essentially free.&lt;/p&gt;

&lt;h2&gt;
  
  
  How the runs were captured
&lt;/h2&gt;

&lt;p&gt;Each row above came from the same harness: a fresh VM with a clean Pebble, system + Mongo projection started as systemd units, NATS + Mongo + Mongo Express brought up in Docker, and the engine's &lt;code&gt;/metrics&lt;/code&gt; endpoint sampled every 5–15 seconds during the run. An &lt;code&gt;fio&lt;/code&gt; pre-flight (&lt;code&gt;--rw=randwrite --bs=4k --direct=1 --sync=1&lt;/code&gt;, 5 s) gates the run on a configurable &lt;code&gt;fsync&lt;/code&gt; latency threshold; on this VM it measured 2,051 µs average, well under the 5 ms gate. Every number in the tables above is either a direct read from &lt;code&gt;/metrics&lt;/code&gt;, a count from the bench JSON output, or a delta between consecutive samples — nothing synthetic, no extrapolation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;20 million durable, invariant-validated transactions in 10 minutes, on a public-cloud VM that costs less per month than a SaaS subscription. Every run ends with &lt;code&gt;INTEGRITY_OK&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;What Atomic State Platform does on the M3 in Part 1, it does unchanged on a €80/mo Linux VM:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The single-writer engine means the &lt;strong&gt;disk stops being the wall&lt;/strong&gt; as soon as you batch upstream.&lt;/li&gt;
&lt;li&gt;Smaller, slower-&lt;code&gt;fsync&lt;/code&gt; CPUs reach the &lt;strong&gt;same throughput envelope&lt;/strong&gt; on cheap cloud as a powerful laptop — provided the producer pattern is cooperative.&lt;/li&gt;
&lt;li&gt;Bigger machines buy &lt;strong&gt;headroom for concurrency&lt;/strong&gt;, not raw throughput.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You don't need a 64-core server. You don't need an NVMe array. You don't need a datacenter rack. &lt;strong&gt;You need the right pattern, applied to the right SKU.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Next
&lt;/h2&gt;

&lt;p&gt;Part 3 unpacks the deeper claim: how Invariant-Driven Architecture lets Atomic State Platform sidestep the classical database stack outright — no Postgres, no Redis, no event-sourcing scaffolding. Just a system with a single &lt;code&gt;fsync&lt;/code&gt; per batch, doing what nothing else does on a €80/mo box.&lt;/p&gt;

</description>
      <category>database</category>
      <category>performance</category>
      <category>go</category>
      <category>cloud</category>
    </item>
    <item>
      <title>Postgres-grade Serializable at 20k+ ops/s — on a laptop. Don’t try this at home.</title>
      <dc:creator>Hugo Vantighem</dc:creator>
      <pubDate>Sat, 23 May 2026 17:14:52 +0000</pubDate>
      <link>https://dev.to/hugo_vantighem/postgres-grade-serializable-at-20k-opss-on-a-laptop-dont-try-this-at-home-f27</link>
      <guid>https://dev.to/hugo_vantighem/postgres-grade-serializable-at-20k-opss-on-a-laptop-dont-try-this-at-home-f27</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;They didn't know it was impossible, so they did it.&lt;/em&gt; — Mark Twain&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In the software industry, we've been raised with a dogma: you must choose between &lt;strong&gt;Massive Performance&lt;/strong&gt; (NoSQL, eventual consistency) and &lt;strong&gt;Domain Rigor&lt;/strong&gt; (SQL, strong consistency, serializable).&lt;/p&gt;

&lt;p&gt;We are told that locks, latencies, and ACID properties are the natural enemies of speed. That if you want to scale, you have to let go of your business invariants.&lt;/p&gt;

&lt;p&gt;I decided to test another hypothesis. And I broke the myth.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Result: 20,000+ Validated Transactions per Second
&lt;/h2&gt;

&lt;p&gt;This isn't a "fire and forget" ingestion log.&lt;/p&gt;

&lt;p&gt;This isn't a volatile cache experiment.&lt;/p&gt;

&lt;p&gt;What you see here is &lt;strong&gt;Business Transaction Durability&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Invariants validated&lt;/strong&gt; — every business rule is checked before commit.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;State persisted&lt;/strong&gt; — every change is durably written to disk.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Strong Consistency&lt;/strong&gt; — Serializable-level isolation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At 20,000+ ops/s, we are not just talking about speed. We are talking about the ability to maintain &lt;strong&gt;absolute domain integrity under massive load&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;And the kicker: this is running on a &lt;strong&gt;MacBook Air M3&lt;/strong&gt; — 8 cores, 16 GB of RAM, the same machine I write the code on. No 64-core server. No NVMe array. No datacenter rack. One laptop, fan barely audible, doing the work of a small cluster.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why General-Purpose Databases Hit a Ceiling
&lt;/h2&gt;

&lt;p&gt;Most databases are built for general cases. They treat every row the same way because they don't know your business.&lt;/p&gt;

&lt;p&gt;This &lt;strong&gt;"Domain Ignorance"&lt;/strong&gt; leads to generic row locks, MVCC bookkeeping, cross-table coordination, and massive overhead — costs you pay on &lt;em&gt;every single transaction&lt;/em&gt;, whether your domain needs them or not.&lt;/p&gt;

&lt;h2&gt;
  
  
  Not Magic — Discipline
&lt;/h2&gt;

&lt;p&gt;For the skeptics: this isn't sorcery. It's discipline applied to the right layer — designing the system so the hardware does exactly what it's good at, and nothing else.&lt;/p&gt;

&lt;p&gt;I'm not reinventing the storage wheel. The foundation is &lt;strong&gt;Pebble&lt;/strong&gt;, the same proven LSM-tree engine that powers CockroachDB. But the engine is just the floor. The real lever is the &lt;strong&gt;orchestration of the domain logic on top of it&lt;/strong&gt; — and that's what Part 2 puts a name on.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Note on the Benchmark Scope
&lt;/h2&gt;

&lt;p&gt;I know what you're thinking. &lt;em&gt;"20k+ ops/s? That must be an internal memory trick."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;It isn't. To ensure these numbers reflect real-world usage, the benchmark covers the &lt;strong&gt;entire lifecycle&lt;/strong&gt; of a business transaction:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Client-side serialization&lt;/strong&gt; — the payload starts from the app.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Local communication&lt;/strong&gt; — end-to-end roundtrip.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Server-side deserialization &amp;amp; parsing.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Business Invariants validation.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Disk persistence&lt;/strong&gt; with full durability guarantees — &lt;code&gt;fsync&lt;/code&gt; on every commit.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The workload: &lt;code&gt;batch=1000&lt;/code&gt;, &lt;code&gt;payload=1KB&lt;/code&gt;, single-node, single laptop. Here's the run, with the system-level disk stats captured live during the bench:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;[23755.87 items/s] | items=1424000 | batch=1000 | payload=1KB | durability=FSYNC-ON
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv5i5y85as7v7b7dk0kc9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv5i5y85as7v7b7dk0kc9.png" alt=" " width="800" height="516"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Live capture during the bench (batch=1000, 1KB, fsync ON). Disk on fire, CPU bored.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Two things jump out of that stats panel — and together they're the whole point:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The disk is screaming.&lt;/strong&gt; Sustained 100–200 MB/s with the ⚡ markers firing almost every second. This is real &lt;code&gt;fsync&lt;/code&gt;'d traffic hitting the SSD, not a memory cache pretending to be durable. If you pulled the power cord mid-run, every committed transaction would still be there on reboot.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The CPU is bored&lt;/strong&gt; (~18% on an 8-core M3). The compute is idle while the disk pegs out — that asymmetry is the whole story.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And this isn't the ceiling. With bigger batches the same laptop pushes further; even at &lt;code&gt;batch=1&lt;/code&gt;, it doesn't fall off a cliff. The full envelope is Part 2.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Next?
&lt;/h2&gt;

&lt;p&gt;This is just Part 1. In a few days, &lt;strong&gt;Part 2&lt;/strong&gt; finishes the picture and lands the real punchline: business rules aren't a tax on performance — they're the contract that lets the machine fly. And the whole thing runs on hardware your team could expense, not a cloud bill that needs board approval.&lt;/p&gt;

&lt;p&gt;Stay tuned. The era of the "Impossible Trade-off" is over.&lt;/p&gt;

</description>
      <category>database</category>
      <category>performance</category>
      <category>postgres</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
