|
| 1 | +import type { Metadata } from "next"; |
| 2 | +import Link from "next/link"; |
| 3 | +import Nav from "@/components/Nav"; |
| 4 | + |
| 5 | +export const metadata: Metadata = { |
| 6 | + title: "Build a Distributed Cache in 50 Lines of Python — ATOMiK Blog", |
| 7 | + description: |
| 8 | + "A step-by-step tutorial: build a 3-node distributed cache with automatic convergence using ATOMiK's delta-state algebra. No consensus protocol, no leader election.", |
| 9 | +}; |
| 10 | + |
| 11 | +function Code({ children }: { children: string }) { |
| 12 | + return ( |
| 13 | + <pre className="rounded-lg p-4 text-sm overflow-x-auto my-4" style={{ background: "#0a0a0f", border: "1px solid #1e1e2e", color: "#22d3ee", fontFamily: "'SF Mono', 'Fira Code', 'Consolas', monospace", lineHeight: 1.7 }}> |
| 14 | + <code>{children}</code> |
| 15 | + </pre> |
| 16 | + ); |
| 17 | +} |
| 18 | + |
| 19 | +export default function DistributedCachePost() { |
| 20 | + return ( |
| 21 | + <div className="min-h-screen" style={{ background: "#0a0a0f", color: "#e0e0e8" }}> |
| 22 | + <Nav active="Blog" /> |
| 23 | + |
| 24 | + <article className="max-w-3xl mx-auto px-6 pt-16 pb-24"> |
| 25 | + <div className="mb-12"> |
| 26 | + <Link href="/blog" className="text-sm mb-6 inline-block hover:underline" style={{ color: "#4f8fff" }}>← Back to blog</Link> |
| 27 | + <time className="block text-sm font-mono mb-3" style={{ color: "#8888a0" }}>March 16, 2026</time> |
| 28 | + <h1 className="text-3xl font-bold tracking-tight mb-4 leading-tight"> |
| 29 | + Build a Distributed Cache in 50 Lines of Python |
| 30 | + </h1> |
| 31 | + <div className="flex gap-2"> |
| 32 | + {["tutorial", "python", "distributed-systems"].map((tag) => ( |
| 33 | + <span key={tag} className="text-xs px-2 py-0.5 rounded-full" style={{ background: "rgba(34, 211, 238, 0.1)", color: "#22d3ee", border: "1px solid rgba(34, 211, 238, 0.2)" }}>{tag}</span> |
| 34 | + ))} |
| 35 | + </div> |
| 36 | + </div> |
| 37 | + |
| 38 | + <div className="space-y-6 text-base leading-relaxed" style={{ color: "#c8c8d4" }}> |
| 39 | + <p> |
| 40 | + Traditional distributed caches need leader election, consensus rounds, and |
| 41 | + conflict resolution. With ATOMiK, you can build a 3-node cache where writes |
| 42 | + from any node converge automatically — in about 50 lines of Python. |
| 43 | + </p> |
| 44 | + |
| 45 | + <h2 className="text-2xl font-bold pt-4" style={{ color: "#e0e0e8" }}>Setup</h2> |
| 46 | + <Code>{`pip install atomik-core`}</Code> |
| 47 | + |
| 48 | + <h2 className="text-2xl font-bold pt-4" style={{ color: "#e0e0e8" }}>Step 1: Create the cache node</h2> |
| 49 | + <p>Each node maintains its own <code style={{ color: "#22d3ee" }}>DeltaStream</code> — a collection of delta-state contexts indexed by address.</p> |
| 50 | + <Code>{`from atomik_core import DeltaStream |
| 51 | +
|
| 52 | +class CacheNode: |
| 53 | + def __init__(self, node_id: str): |
| 54 | + self.node_id = node_id |
| 55 | + self.stream = DeltaStream() |
| 56 | + self.peers: list["CacheNode"] = [] |
| 57 | +
|
| 58 | + def connect(self, peer: "CacheNode"): |
| 59 | + self.peers.append(peer) |
| 60 | + peer.peers.append(self)`}</Code> |
| 61 | + |
| 62 | + <h2 className="text-2xl font-bold pt-4" style={{ color: "#e0e0e8" }}>Step 2: Write = LOAD + broadcast</h2> |
| 63 | + <p> |
| 64 | + When a node writes a new value, it LOADs the value locally and broadcasts |
| 65 | + the delta to all peers. The delta is just 8 bytes — the XOR difference. |
| 66 | + </p> |
| 67 | + <Code>{` def put(self, key: int, value: int): |
| 68 | + """Write a value and broadcast the delta.""" |
| 69 | + old = self.stream.read(key) |
| 70 | + self.stream.load(key, value) |
| 71 | + delta = old ^ value # XOR delta |
| 72 | + # Broadcast to peers |
| 73 | + for peer in self.peers: |
| 74 | + peer.receive_delta(key, delta)`}</Code> |
| 75 | + |
| 76 | + <h2 className="text-2xl font-bold pt-4" style={{ color: "#e0e0e8" }}>Step 3: Receive = ACCUM</h2> |
| 77 | + <p> |
| 78 | + When a peer receives a delta, it accumulates it. XOR is commutative — |
| 79 | + the order deltas arrive doesn't matter. Every node converges to the same state. |
| 80 | + </p> |
| 81 | + <Code>{` def receive_delta(self, key: int, delta: int): |
| 82 | + """Apply a delta from a peer.""" |
| 83 | + self.stream.accum(key, delta) |
| 84 | +
|
| 85 | + def get(self, key: int) -> int: |
| 86 | + """Read the current value.""" |
| 87 | + return self.stream.read(key)`}</Code> |
| 88 | + |
| 89 | + <h2 className="text-2xl font-bold pt-4" style={{ color: "#e0e0e8" }}>Step 4: Wire it up</h2> |
| 90 | + <Code>{`# Create 3 nodes |
| 91 | +a = CacheNode("A") |
| 92 | +b = CacheNode("B") |
| 93 | +c = CacheNode("C") |
| 94 | +
|
| 95 | +# Full mesh topology |
| 96 | +a.connect(b) |
| 97 | +a.connect(c) |
| 98 | +b.connect(c) |
| 99 | +
|
| 100 | +# Initialize all nodes with the same reference |
| 101 | +for node in [a, b, c]: |
| 102 | + node.stream.load(0, 0xCAFEBABE) |
| 103 | +
|
| 104 | +# Node A writes a new value |
| 105 | +a.put(0, 0xDEADBEEF) |
| 106 | +
|
| 107 | +# All nodes converge — no consensus needed |
| 108 | +assert a.get(0) == 0xDEADBEEF |
| 109 | +assert b.get(0) == 0xDEADBEEF |
| 110 | +assert c.get(0) == 0xDEADBEEF |
| 111 | +print("All 3 nodes converged!")`}</Code> |
| 112 | + |
| 113 | + <h2 className="text-2xl font-bold pt-4" style={{ color: "#e0e0e8" }}>Why it works</h2> |
| 114 | + <p>The magic is XOR commutativity. When Node A writes <code style={{ color: "#22d3ee" }}>0xDEADBEEF</code> to a slot that held <code style={{ color: "#22d3ee" }}>0xCAFEBABE</code>, the delta is:</p> |
| 115 | + <Code>{`delta = 0xCAFEBABE ^ 0xDEADBEEF = 0x14531455`}</Code> |
| 116 | + <p> |
| 117 | + Nodes B and C each accumulate this delta. Since <code style={{ color: "#22d3ee" }}>reference XOR accumulator = current_state</code>, they reconstruct the same value: |
| 118 | + </p> |
| 119 | + <Code>{`0xCAFEBABE ^ 0x14531455 = 0xDEADBEEF ✓`}</Code> |
| 120 | + <p> |
| 121 | + If multiple nodes write simultaneously, deltas compose. Node B writes to |
| 122 | + key 1 while Node C writes to key 2 — both deltas propagate and apply |
| 123 | + independently. No conflicts, no resolution logic, no coordinator. |
| 124 | + </p> |
| 125 | + |
| 126 | + <h2 className="text-2xl font-bold pt-4" style={{ color: "#e0e0e8" }}>Concurrent writes to the same key</h2> |
| 127 | + <p> |
| 128 | + What happens if A and B both write to key 0 at the same time? Both deltas |
| 129 | + propagate to all nodes. The final state is deterministic — it's the XOR of |
| 130 | + both deltas applied to the reference. The "last writer wins" semantic is |
| 131 | + replaced by "all writers compose" — which is correct for many workloads |
| 132 | + (counters, flags, accumulated state). |
| 133 | + </p> |
| 134 | + <p> |
| 135 | + For workloads where you need last-writer-wins, use <code style={{ color: "#22d3ee" }}>SWAP</code> |
| 136 | + to create epochs — each SWAP resets the accumulator and promotes the current |
| 137 | + state to the new reference. |
| 138 | + </p> |
| 139 | + |
| 140 | + <h2 className="text-2xl font-bold pt-4" style={{ color: "#e0e0e8" }}>Add wire serialization</h2> |
| 141 | + <p> |
| 142 | + In v0.3.0, <code style={{ color: "#22d3ee" }}>DeltaMessage</code> gained |
| 143 | + compact wire format support: |
| 144 | + </p> |
| 145 | + <Code>{`from atomik_core import DeltaMessage |
| 146 | +
|
| 147 | +# On sender |
| 148 | +msg = DeltaMessage(addr=0, delta=0x14531455, seq=1) |
| 149 | +wire = msg.to_bytes() # 16 bytes, network byte order |
| 150 | +
|
| 151 | +# On receiver |
| 152 | +msg = DeltaMessage.from_bytes(wire) |
| 153 | +stream.accum(msg.addr, msg.delta)`}</Code> |
| 154 | + |
| 155 | + <h2 className="text-2xl font-bold pt-4" style={{ color: "#e0e0e8" }}>What you get</h2> |
| 156 | + <ul className="list-disc pl-6 space-y-2"> |
| 157 | + <li><strong>Zero coordination.</strong> No leader election, no consensus rounds, no distributed locks.</li> |
| 158 | + <li><strong>8 bytes per update.</strong> Regardless of the value size, the delta is always 8 bytes.</li> |
| 159 | + <li><strong>O(1) everything.</strong> Write, read, and sync are all constant-time.</li> |
| 160 | + <li><strong>Automatic convergence.</strong> All nodes reach the same state regardless of message ordering.</li> |
| 161 | + <li><strong>Proven correct.</strong> 92 Lean4 theorems guarantee the algebra works.</li> |
| 162 | + </ul> |
| 163 | + |
| 164 | + <div className="rounded-xl border p-8 mt-8 text-center" style={{ background: "#12121a", borderColor: "#1e1e2e" }}> |
| 165 | + <h3 className="text-xl font-bold mb-3">Try it yourself</h3> |
| 166 | + <Code>{`pip install atomik-core |
| 167 | +python -c " |
| 168 | +from atomik_core import DeltaStream |
| 169 | +s = DeltaStream() |
| 170 | +s.load(0, 0xCAFEBABE) |
| 171 | +s.accum(0, 0x14531455) |
| 172 | +print(f'State: 0x{s.read(0):08x}') |
| 173 | +"`}</Code> |
| 174 | + <div className="flex flex-wrap justify-center gap-4 mt-6"> |
| 175 | + <Link href="/demo" className="px-6 py-2.5 rounded-lg text-sm font-semibold" style={{ background: "#4f8fff", color: "#fff" }}>Interactive Demo</Link> |
| 176 | + <Link href="/docs/quickstart" className="px-6 py-2.5 rounded-lg text-sm font-semibold" style={{ background: "transparent", color: "#e0e0e8", border: "1px solid #1e1e2e" }}>Full Documentation</Link> |
| 177 | + </div> |
| 178 | + </div> |
| 179 | + </div> |
| 180 | + </article> |
| 181 | + </div> |
| 182 | + ); |
| 183 | +} |
0 commit comments