<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Cloud Tuned]]></title><description><![CDATA[Your starting point for anything cloud: AWS, Azure, GCP, Serverless, Architecture, Hybrid Cloud, Systems Design and other Information Technology topics.]]></description><link>https://cloudtuned.dev</link><generator>RSS for Node</generator><lastBuildDate>Tue, 30 Jun 2026 04:34:54 GMT</lastBuildDate><atom:link href="https://cloudtuned.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Docker & Kubernetes: What They Are, Why They Matter, and How to Get Started]]></title><link>https://cloudtuned.dev/docker-kubernetes-what-they-are-why-they-matter-and-how-to-get-started</link><guid isPermaLink="true">https://cloudtuned.dev/docker-kubernetes-what-they-are-why-they-matter-and-how-to-get-started</guid><category><![CDATA[Docker]]></category><category><![CDATA[Kubernetes]]></category><dc:creator><![CDATA[Cloud Tuned]]></dc:creator><pubDate>Sun, 16 Mar 2025 23:30:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/602bee9a4bb9c4083f02795d/2acb5bdf-30bd-48b4-a16c-0377fcb37928.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="hn-embed-widget" id="docker-kubernetes-widget"></div>]]></content:encoded></item><item><title><![CDATA[Introduction to Rancher: Wrangling Kubernetes Clusters at Scale]]></title><description><![CDATA[Introduction to Rancher: Wrangling Kubernetes Clusters at Scale
Managing one Kubernetes cluster is a challenge. Managing a dozen of them — across different clouds, data centres, and edge locations — c]]></description><link>https://cloudtuned.dev/introduction-to-rancher-wrangling-kubernetes-clusters-at-scale</link><guid isPermaLink="true">https://cloudtuned.dev/introduction-to-rancher-wrangling-kubernetes-clusters-at-scale</guid><category><![CDATA[rancher]]></category><category><![CDATA[k8s]]></category><category><![CDATA[Kubernetes]]></category><dc:creator><![CDATA[Cloud Tuned]]></dc:creator><pubDate>Sat, 15 Mar 2025 23:30:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/602bee9a4bb9c4083f02795d/dabe092f-ccdd-41cb-a77d-88e0ec1c8a7c.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1>Introduction to Rancher: Wrangling Kubernetes Clusters at Scale</h1>
<p>Managing one Kubernetes cluster is a challenge. Managing a dozen of them — across different clouds, data centres, and edge locations — can feel like herding cattle. That's exactly the problem Rancher was built to solve.</p>
<hr />
<h2>What Is Rancher?</h2>
<p>Rancher is a <strong>free, open-source tool</strong> created by Rancher Labs (acquired by SUSE in 2020) that lets you manage multiple Kubernetes clusters from a single place. If Kubernetes orchestrates and deploys containers, then Rancher does the same thing — one level up — for Kubernetes clusters themselves.</p>
<p>It supports clusters running in public clouds (AWS EKS, Azure AKS, Google GKE), on-premises data centres, hybrid environments, and even Internet of Things (IoT) devices. Rancher is also a Cloud Native Computing Foundation (CNCF)-compliant tool, meaning it works with virtually any standard Kubernetes distribution.</p>
<p>The name isn't an accident. There's a well-known saying in cloud infrastructure: <em>"servers are cattle, not pets."</em> When you've got a lot of cattle, you need a rancher to manage the herd.</p>
<hr />
<h2>Why Use Rancher?</h2>
<p>The central value proposition is <strong>centralised multi-cluster management</strong>, but it goes deeper than that:</p>
<ul>
<li><p><strong>Multi-cloud and hybrid cloud support</strong> — manage all your clusters to a single standard, regardless of where they live.</p>
</li>
<li><p><strong>CNCF compliance</strong> — broad compatibility across the Kubernetes ecosystem.</p>
</li>
<li><p><strong>Deep integration with managed Kubernetes services</strong> — Rancher can interact directly with cloud provider APIs alongside the Kubernetes API, so you keep the benefits of managed platforms while using Rancher.</p>
</li>
<li><p><strong>Security at scale</strong> — implement access controls and compliance policies across every cluster from one console, without micromanaging each one individually.</p>
</li>
<li><p><strong>CI/CD automation</strong> — connect Git repositories for automated, Git-based deployments to multiple clusters at once.</p>
</li>
</ul>
<hr />
<h2>Core Features</h2>
<p>Rancher's feature set breaks down into four main areas:</p>
<h3>1. Cluster Explorer</h3>
<p>A GUI console that gives you full visibility into your Kubernetes objects — namespaces, nodes, workloads (CronJobs, DaemonSets, Deployments, StatefulSets, Pods), service discovery, storage objects, and RBAC roles — all in one place. If it's a Kubernetes object, Cluster Explorer will surface it.</p>
<h3>2. Continuous Delivery</h3>
<p>Rancher's built-in CD tooling connects directly to Git repositories and automates deployments to specific clusters or cluster groups. You can manage Git-based workflows, define workspaces, and keep your delivery pipelines aligned across your entire infrastructure.</p>
<h3>3. Apps &amp; Marketplace</h3>
<p>Built on Helm charts — YAML-based scripts for deploying complex applications on Kubernetes — the marketplace comes pre-loaded with catalogues for common services like Prometheus, Longhorn, and Nginx. You can also import third-party catalogues or build your own internal catalogue, making it easy for teams to deploy standardised services without reinventing the wheel each time.</p>
<h3>4. Security</h3>
<p>Rancher integrates with Kubernetes-native RBAC so you can manage user access across all clusters from one console. It supports pod security policies at an organisational level, and authenticates with a wide range of third-party identity providers — including Active Directory, GitHub, Okta, and Keycloak — so you can plug Rancher into whatever your organisation already uses.</p>
<hr />
<h2>The Rancher Ecosystem</h2>
<p>Rancher Labs built more than just Rancher. A few closely related tools are worth knowing about:</p>
<h3>Rancher Kubernetes Engine (RKE)</h3>
<p>RKE is a CNCF-certified Kubernetes distribution that runs <strong>entirely inside Docker containers</strong>. Rather than manually installing and configuring Kubernetes — a notoriously complex process — RKE wraps that complexity into a straightforward setup that can run on any operating system capable of running Docker, whether bare-metal or virtualised servers.</p>
<p>Key use cases include:</p>
<ul>
<li><p>Running Kubernetes in data centres where managed cloud services aren't available</p>
</li>
<li><p>Avoiding vendor lock-in by keeping clusters portable across cloud providers</p>
</li>
<li><p>Maintaining control over underlying infrastructure that managed services typically abstract away</p>
</li>
<li><p>Strict security environments — RKE2 (also called RKE Government) adds compliance with CIS benchmarks and FIPS requirements</p>
</li>
</ul>
<h3>K3s</h3>
<p>K3s is a <strong>lightweight Kubernetes distribution</strong> purpose-built for IoT and edge computing. The name is a nod to Kubernetes (abbreviated K8s) — K3s is intentionally smaller.</p>
<p>The entire K3s binary is under 40MB and includes all dependencies needed to get a cluster running. It's optimised for low-compute environments, making it ideal for:</p>
<ul>
<li><p>Resource-constrained hardware</p>
</li>
<li><p>Remote sites with limited connectivity (satellite offices, oil rigs)</p>
</li>
<li><p>IoT devices</p>
</li>
<li><p>Running production-grade Kubernetes on something as modest as a Raspberry Pi</p>
</li>
</ul>
<p>K3s was donated by Rancher Labs to the CNCF in 2020 and is now an official CNCF project.</p>
<h3>Longhorn</h3>
<p>Longhorn is a <strong>cloud-native distributed block storage solution</strong> for Kubernetes. It tackles one of the trickier challenges in Kubernetes: persistent storage for stateful workloads.</p>
<p>Kubernetes nodes are designed to be ephemeral — they can fail at any moment without taking the cluster down. That's great for stateless workloads, but if you need data to persist, storing it only on a node that might disappear is a problem. Longhorn addresses this by replicating data across multiple nodes, so if one goes down, the data remains available.</p>
<p>Its advantages include cloud-native integration (backing up data to object storage, cross-availability zone failover), resilience (backup clusters separate from primary), and ease of use (one-click installation, live upgrades without downtime).</p>
<hr />
<h2>A Quick Tour of the Console</h2>
<img src="https://cdn.hashnode.com/uploads/covers/602bee9a4bb9c4083f02795d/685c207f-4900-48ea-9181-16c6b965ec43.webp" alt="" style="display:block;margin:0 auto" />

<p>In practice, Rancher's interface is straightforward. From the main dashboard you can see all clusters under management at a glance. The <strong>Cluster Manager</strong> view gives you high-level cluster health and metadata, while <strong>Cluster Explorer</strong> lets you drill into the granular details of every Kubernetes object.</p>
<p>Continuous Delivery is accessible from the same navigation, where you paste in a Git repo URL, define the branches to watch, and configure deployment targets. Apps &amp; Marketplace sits alongside it, offering a searchable catalogue of Helm charts ready to deploy with a few clicks. Security settings — authentication providers, user roles, and pod security policies — live under the Global section of the Cluster Manager.</p>
<hr />
<h2>Use Cases at a Glance</h2>
<table>
<thead>
<tr>
<th>Scenario</th>
<th>How Rancher Helps</th>
</tr>
</thead>
<tbody><tr>
<td>Large enterprise with multiple teams</td>
<td>Central shared services team manages all clusters; app teams keep their own</td>
</tr>
<tr>
<td>Multi-cloud or hybrid cloud</td>
<td>Unified management and standardisation across all environments</td>
</tr>
<tr>
<td>Strict compliance requirements</td>
<td>Organisation-wide pod security policies without manual cluster-by-cluster work</td>
</tr>
<tr>
<td>Edge and IoT deployments</td>
<td>K3s runs lightweight clusters on low-power, low-connectivity devices</td>
</tr>
<tr>
<td>GitOps and CI/CD</td>
<td>Continuous Delivery connects Git repos to automated cluster deployments</td>
</tr>
</tbody></table>
<hr />
<h2>Getting Started</h2>
<p>Because Rancher is open source, there's no licensing cost to get started. You can pull the Docker image and have an instance running locally in minutes. The official <a href="https://ranchermanager.docs.rancher.com/">Rancher documentation</a> is a solid next step, as is the Rancher community Slack for connecting with other users.</p>
<p>If you want to go deeper on the Kubernetes side, resources like the Kubernetes Deep Dive course or the Certified Kubernetes Administrator (CKA) exam preparation materials pair well with this foundation.</p>
<hr />
<p>Rancher doesn't try to replace Kubernetes — it makes managing it at scale genuinely tractable. Whether you're running two clusters or twenty, across one cloud or five, it's a tool worth having in your infrastructure toolkit.</p>
]]></content:encoded></item><item><title><![CDATA[Networking Fundamentals: A Beginner's Guide to How the Internet Actually Works]]></title><description><![CDATA[Networking Fundamentals: A Beginner's Guide to How the Internet Actually Works
You use computer networks every single day — to send emails, stream videos, join video calls, and browse the web. But wha]]></description><link>https://cloudtuned.dev/networking-fundamentals-a-beginner-s-guide-to-how-the-internet-actually-works</link><guid isPermaLink="true">https://cloudtuned.dev/networking-fundamentals-a-beginner-s-guide-to-how-the-internet-actually-works</guid><category><![CDATA[networking]]></category><dc:creator><![CDATA[Cloud Tuned]]></dc:creator><pubDate>Fri, 14 Mar 2025 23:30:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/602bee9a4bb9c4083f02795d/e278ad81-8a33-4553-a1fc-30dfcadd7faa.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1>Networking Fundamentals: A Beginner's Guide to How the Internet Actually Works</h1>
<p>You use computer networks every single day — to send emails, stream videos, join video calls, and browse the web. But what's actually happening behind the scenes? This guide breaks down the core concepts of computer networking from the ground up, no prior knowledge required.</p>
<hr />
<h2>What Is a Computer Network?</h2>
<p>At its most basic, a computer network is nothing more than two computers connected together and communicating. That's it. Everything else — the internet, your home Wi-Fi, your office network — is just a scaled-up version of that simple idea.</p>
<p>Networks exist because they make our digital lives enormously more practical:</p>
<ul>
<li><strong>Exchanging data</strong> — sharing photos, videos, and files between devices</li>
<li><strong>Sharing resources</strong> — one printer serving an entire office, rather than one per desk</li>
<li><strong>Communication</strong> — email, instant messaging, video calls, and everything in between</li>
</ul>
<h3>A Brief History</h3>
<p>Computer networking has come a long way in a short time:</p>
<ul>
<li><strong>Late 1960s</strong> — The Pentagon's ARPANET project connected four universities together for the first time, and the first email was sent</li>
<li><strong>1970s–80s</strong> — The Ethernet standard and TCP/IP protocols were created, establishing the rules for how data should be transmitted and how computers should talk to each other</li>
<li><strong>1980s</strong> — The Domain Name System (DNS) was invented to help the growing number of computers find each other; dial-up networking and AOL brought email to millions of homes</li>
<li><strong>1990s</strong> — The World Wide Web arrived, along with web browsers</li>
<li><strong>2000s</strong> — Broadband replaced dial-up; Amazon Web Services launched in 2006, kicking off the cloud era</li>
<li><strong>Today</strong> — Cloud computing means companies no longer need to buy expensive equipment worldwide — they simply deploy their applications to the cloud and they're available everywhere</li>
</ul>
<hr />
<h2>Types of Networks</h2>
<p>Not all networks are the same size or scope. The two most common types are:</p>
<p><strong>LAN — Local Area Network</strong>
A network that connects devices within a small area: your home, a school, or an office building. Your home Wi-Fi is a LAN.</p>
<p><strong>WAN — Wide Area Network</strong>
A network that connects smaller networks (like LANs) across large geographic distances — between cities or countries. The internet itself is the world's largest WAN, made up of countless public and private networks all connected together.</p>
<hr />
<h2>Network Topologies: How Devices Are Arranged</h2>
<p>The <em>topology</em> of a network describes how devices relate to each other — how they're physically cabled together and how data flows between them. Here are the main ones:</p>
<table>
<thead>
<tr>
<th>Topology</th>
<th>How It Works</th>
<th>Pros</th>
<th>Cons</th>
</tr>
</thead>
<tbody><tr>
<td><strong>Ring</strong></td>
<td>Each device connects to two neighbours in a circle</td>
<td>Simple structure</td>
<td>If one device fails, the loop breaks</td>
</tr>
<tr>
<td><strong>Point-to-Point</strong></td>
<td>One device connected directly to one other</td>
<td>Fast communication</td>
<td>Only two devices</td>
</tr>
<tr>
<td><strong>Mesh</strong></td>
<td>Every device connects to every other device</td>
<td>Very redundant and fault-tolerant</td>
<td>Expensive due to cabling</td>
</tr>
<tr>
<td><strong>Star</strong></td>
<td>All devices connect to a central hub</td>
<td>Easy to manage</td>
<td>The hub is a single point of failure</td>
</tr>
<tr>
<td><strong>Bus</strong></td>
<td>All devices on one single cable</td>
<td>Works well for small networks</td>
<td>The main cable is a single point of failure</td>
</tr>
<tr>
<td><strong>Tree</strong></td>
<td>Devices arranged in branches</td>
<td>Flexible and scalable</td>
<td>If a branch's top device fails, everything below goes offline</td>
</tr>
<tr>
<td><strong>Hybrid</strong></td>
<td>Mix of two or more topologies</td>
<td>Very flexible for growth</td>
<td>Complex and expensive</td>
</tr>
</tbody></table>
<p>In practice, most modern networks use a hybrid approach.</p>
<hr />
<h2>The Building Blocks of a Network</h2>
<p>Every computer network is made up of five core components:</p>
<ol>
<li><p><strong>Devices</strong> — Computers, tablets, phones, gaming consoles. Each has a unique identifier called a <em>MAC address</em> that tells other devices exactly where to send traffic.</p>
</li>
<li><p><strong>Connections</strong> — How devices physically connect: Ethernet cables, coax cable, or wirelessly.</p>
</li>
<li><p><strong>Switches</strong> — Network equipment that connects the various devices on your local network to each other.</p>
</li>
<li><p><strong>Routers</strong> — Network equipment that directs traffic <em>between</em> networks — from your home LAN out to the wider internet, for example.</p>
</li>
<li><p><strong>Servers</strong> — Computers out on the internet that serve files, web pages, and applications.</p>
</li>
</ol>
<hr />
<h2>The OSI Model: A Map of How Networks Communicate</h2>
<p>The <strong>Open Systems Interconnection (OSI) Model</strong> is a theoretical framework that describes what happens to data as it travels from a hardware connection all the way up to an application on your screen — or vice versa.</p>
<p>It was developed in the 1980s to solve a real problem: how do devices from different manufacturers, running different software, communicate on the same network? The OSI model provides a common set of standards so that any device, from any vendor, can participate in a network.</p>
<p>It has <strong>seven layers</strong>, from the bottom (hardware) to the top (user-facing applications):</p>
<table>
<thead>
<tr>
<th>Layer</th>
<th>Name</th>
<th>What It Does</th>
<th>Example</th>
</tr>
</thead>
<tbody><tr>
<td>7</td>
<td><strong>Application</strong></td>
<td>How your app interfaces with the network</td>
<td>HTTP, FTP, DNS</td>
</tr>
<tr>
<td>6</td>
<td><strong>Presentation</strong></td>
<td>Formats data so both sides can understand it</td>
<td>JPEG, MPEG, ASCII↔Binary</td>
</tr>
<tr>
<td>5</td>
<td><strong>Session</strong></td>
<td>Starts, manages, and stops communication sessions; keeps app data separate</td>
<td>NFS, SQL</td>
</tr>
<tr>
<td>4</td>
<td><strong>Transport</strong></td>
<td>Packages your message and ensures full delivery</td>
<td>TCP, UDP</td>
</tr>
<tr>
<td>3</td>
<td><strong>Network</strong></td>
<td>Routes data across LANs and WANs</td>
<td>IP addresses, Routers</td>
</tr>
<tr>
<td>2</td>
<td><strong>Data Link</strong></td>
<td>Packages data into frames for physical transmission; checks integrity</td>
<td>Network cards, Switches, ARP</td>
</tr>
<tr>
<td>1</td>
<td><strong>Physical</strong></td>
<td>The actual transmission of bits — electrical signals, radio waves, cables</td>
<td>Ethernet cables, Bluetooth, Wi-Fi</td>
</tr>
</tbody></table>
<p>Layers 5–7 are called the <strong>upper layers</strong> (application-focused); layers 1–4 are the <strong>lower layers</strong> (hardware-focused).</p>
<p><strong>Why does this matter in practice?</strong> When network engineers troubleshoot problems, they often refer to OSI layers. "It's a Layer 1 problem" means someone should check whether the cable is plugged in. "It's a Layer 3 problem" means the issue is with IP addressing or routing.</p>
<h3>TCP vs UDP — What's the Difference?</h3>
<p>Both are <strong>transport layer protocols</strong> (Layer 4), but they work differently:</p>
<ul>
<li><strong>TCP</strong> is a two-way agreement: "I'm going to send you something" → "Got it, send away" → data is exchanged. It guarantees delivery.</li>
<li><strong>UDP</strong> is fire-and-forget: data is sent and may or may not arrive. Used for things like live video streaming where speed matters more than perfection.</li>
</ul>
<hr />
<h2>IP Addresses: Your Device's Mailing Address</h2>
<p>An <strong>IP address</strong> is a unique number that identifies a device on a network. Think of it like a mailing address — it's how other computers find and connect to yours.</p>
<p>A full IP address has three parts:</p>
<ul>
<li><strong>Network ID</strong> — like the city and street in a postal address; tells routers which network to send data to</li>
<li><strong>Host ID</strong> — like the building number; identifies the specific device</li>
<li><strong>Port</strong> — like the door of the building; tells traffic which application or service to go to (written as <code>:80</code> after the IP)</li>
</ul>
<h3>IPv4 vs IPv6</h3>
<p><strong>IPv4</strong> (e.g. <code>192.168.2.14</code>) has been around since the 1980s. It uses 32-bit addresses, giving roughly 4.3 billion possible addresses — a number that's rapidly running out as more devices come online.</p>
<p><strong>IPv6</strong> (e.g. <code>2001:0db8:85a3:0000:0000:8a2e:0370:7334</code>) uses 128-bit addresses, providing 340 <em>trillion trillion trillion</em> addresses. It became the standard in 2017 and is where networking is headed.</p>
<h3>NAT — Network Address Translation</h3>
<p>At home, your ISP gives you a single public IP address. But you likely have many devices — phone, laptop, TV, tablet. <strong>NAT</strong> is what makes this work: it routes traffic from your single public IP to the correct device on your private network. Think of it like a mail clerk at a large office building — all mail arrives at one point, and the clerk delivers it to the right person.</p>
<h3>Ports: Different Doors for Different Traffic</h3>
<p>There are 65,535 ports. The first 1,024 are reserved for well-known services:</p>
<table>
<thead>
<tr>
<th>Port</th>
<th>Service</th>
</tr>
</thead>
<tbody><tr>
<td>25</td>
<td>SMTP (email)</td>
</tr>
<tr>
<td>53</td>
<td>DNS</td>
</tr>
<tr>
<td>80</td>
<td>HTTP (web pages)</td>
</tr>
<tr>
<td>443</td>
<td>HTTPS (secure web pages)</td>
</tr>
</tbody></table>
<h3>Subnetting</h3>
<p><strong>Subnetting</strong> is dividing a large network into smaller, more manageable networks using a <em>subnet mask</em>. Smaller networks are easier to manage, use IP addresses more efficiently, and generally perform better because routers know exactly which data goes where.</p>
<hr />
<h2>DNS: The Phone Book of the Internet</h2>
<p>Remembering IP addresses for every website you visit would be impossible. <strong>DNS (Domain Name System)</strong> solves this by translating human-friendly domain names (like <code>google.com</code>) into IP addresses that computers use.</p>
<h3>How a DNS Query Works</h3>
<p>When you type <code>www.example.com</code> into your browser, here's what happens — faster than you can blink:</p>
<ol>
<li><strong>Your device</strong> asks a <strong>Recursive Name Server</strong> (usually provided by your ISP): "What's the IP for <a href="http://www.example.com">www.example.com</a>?"</li>
<li>The recursive server doesn't know, so it asks a <strong>Root Name Server</strong>: "Who handles .com domains?"</li>
<li>The root server points it to the <strong>TLD (Top-Level Domain) Server</strong> for .com</li>
<li>The TLD server points it to the <strong>Authoritative Name Server</strong> for example.com</li>
<li>The authoritative server knows the answer and returns the IP address</li>
<li>The recursive server passes that IP back to your device — and remembers it for a while in case you need it again</li>
</ol>
<p>This whole process takes milliseconds and happens every time you visit a website.</p>
<h3>Domain Name Structure</h3>
<p>A full domain name has several levels, read right to left:</p>
<pre><code>www  .  example  .  com  .
 ↑         ↑        ↑    ↑
Sub-    Second-   Top-  Root
domain   level   level
</code></pre>
<hr />
<h2>Routing: How Data Gets From Here to There</h2>
<p><strong>Routing</strong> is the process of moving data from one network to another. It's done by <strong>routers</strong>, which forward data packets and decide the best path for them to take — like a GPS that constantly recalculates based on traffic conditions.</p>
<h3>How Data Actually Travels</h3>
<p>When you visit a website, your data doesn't travel as one big chunk. It gets broken into small <strong>packets</strong>, each stamped with:</p>
<ul>
<li>A <strong>source address</strong> (your IP)</li>
<li>A <strong>destination address</strong> (the website's IP)</li>
<li>A <strong>sequence number</strong> so the destination can reassemble them in the right order, even if they arrive out of sequence</li>
</ul>
<p>Routers pass these packets along — each one potentially choosing a different path — until they reach the destination.</p>
<h3>Routing Tables and Protocols</h3>
<p>Every router maintains a <strong>routing table</strong> — essentially a map of which networks it knows about and how to reach them. Routers share this information with each other using <strong>routing protocols</strong>, a common language for communicating network information.</p>
<h3>Static vs Dynamic Routes</h3>
<ul>
<li><strong>Static routes</strong> — fixed paths, manually set by a network administrator; the data always takes the same route</li>
<li><strong>Dynamic routes</strong> — flexible paths that change based on network conditions (congestion, outages, speed). Most internet traffic uses dynamic routing.</li>
</ul>
<hr />
<h2>Useful Networking Commands</h2>
<p>If you want to explore networking hands-on, here are some commands available on Linux (and often Windows/macOS equivalents):</p>
<table>
<thead>
<tr>
<th>Task</th>
<th>Modern Command</th>
<th>Legacy Command</th>
</tr>
</thead>
<tbody><tr>
<td>Find your IP address</td>
<td><code>ip address show</code></td>
<td><code>ifconfig</code></td>
</tr>
<tr>
<td>View routing information</td>
<td><code>ip route</code></td>
<td><code>route</code> or <code>netstat -rn</code></td>
</tr>
<tr>
<td>View DNS configuration</td>
<td><code>nmcli</code></td>
<td><code>cat /etc/resolv.conf</code></td>
</tr>
<tr>
<td>Look up a domain's IP</td>
<td><code>dig google.com</code></td>
<td><code>nslookup google.com</code></td>
</tr>
<tr>
<td>Trace the route to a host</td>
<td><code>traceroute google.com</code></td>
<td><code>traceroute google.com</code></td>
</tr>
<tr>
<td>Check if a host is reachable</td>
<td><code>ping google.com</code></td>
<td><code>ping google.com</code></td>
</tr>
</tbody></table>
<blockquote>
<p><strong>Note on <code>ping</code>:</strong> Many servers filter out ping responses for security reasons, so no response doesn't necessarily mean the host is down.</p>
</blockquote>
<hr />
<h2>Putting It All Together</h2>
<p>Here's a quick mental model of how everything connects when you browse a website:</p>
<ol>
<li>You type <code>example.com</code> → <strong>DNS</strong> translates it to an IP address</li>
<li>Your data is broken into <strong>packets</strong> with source/destination addresses</li>
<li>Your home <strong>router</strong> sends them out via <strong>NAT</strong> through your single public IP</li>
<li><strong>Routers</strong> across the internet pass the packets along, each choosing the best <strong>route</strong></li>
<li>The packets arrive at the destination server (possibly out of order) and are reassembled using their <strong>sequence numbers</strong></li>
<li>The server responds and the whole process happens in reverse</li>
</ol>
<hr />
<h2>Where to Go From Here</h2>
<p>Now that you have the foundations, some great next topics to explore are:</p>
<ul>
<li><strong>Subnetting Fundamentals</strong> — go deeper into dividing networks</li>
<li><strong>Routing Fundamentals</strong> — understand how routers make their decisions in detail</li>
<li><strong>Linux Networking</strong> — hands-on configuration and troubleshooting</li>
<li><strong>Cloud Networking</strong> — how AWS, Azure, and Google Cloud implement virtual networks</li>
</ul>
<p>Networking is one of those topics where the basics unlock everything else in IT and cloud computing. Once you understand how data moves, the rest starts to make a lot more sense.</p>
]]></content:encoded></item><item><title><![CDATA[Distributed Systems: Wrap-Up]]></title><description><![CDATA[Series: System Design · Distributed Systems — Pillar 8 of 8

Systems Design



#
Post
What it covers



00
Distributed Systems: What Happens When Machines Disagree
Twenty concepts covering network par]]></description><link>https://cloudtuned.dev/distributed-systems-wrap-up</link><guid isPermaLink="true">https://cloudtuned.dev/distributed-systems-wrap-up</guid><category><![CDATA[systemdesign]]></category><category><![CDATA[distributedsystems]]></category><category><![CDATA[architecture]]></category><category><![CDATA[backend]]></category><category><![CDATA[SoftwareDevelopment]]></category><category><![CDATA[softwarearchitecture]]></category><category><![CDATA[engineering]]></category><dc:creator><![CDATA[Cloud Tuned]]></dc:creator><pubDate>Fri, 14 Mar 2025 12:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/602bee9a4bb9c4083f02795d/54fb130c-9e94-4337-8004-f47a17c1ba5e.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote>
<p><strong>Series:</strong> System Design · Distributed Systems — Pillar 8 of 8</p>
</blockquote>
<h2>Systems Design</h2>
<table>
<thead>
<tr>
<th>#</th>
<th>Post</th>
<th>What it covers</th>
</tr>
</thead>
<tbody><tr>
<td>00</td>
<td><a href="/distributed-systems-what-happens-when-machines-disagree">Distributed Systems: What Happens When Machines Disagree</a></td>
<td>Twenty concepts covering network partitions, consensus, clocks, distributed transactions, CDC, erasure coding, and observability. The final pillar.</td>
</tr>
<tr>
<td>01</td>
<td><a href="/network-partitions-the-failure-mode-you-cant-design-away">Network Partitions: The Failure Mode You Can't Design Away</a></td>
<td>Network partitions are inevitable. Learn what happens when nodes can't communicate, how systems choose between availability and consistency, and what that means in practice.</td>
</tr>
<tr>
<td>02</td>
<td><a href="/split-brain-when-two-nodes-both-think-theyre-the-leader">Split-Brain: When Two Nodes Both Think They're the Leader</a></td>
<td>Split-brain occurs when two nodes both believe they're the primary. Learn how it happens, why it causes data corruption, and how STONITH and fencing prevent it.</td>
</tr>
<tr>
<td>03</td>
<td><a href="/heartbeats-how-nodes-know-their-peers-are-alive">Heartbeats: How Nodes Know Their Peers Are Alive</a></td>
<td>Heartbeats let nodes detect peer failures. Learn how timeouts, phi accrual failure detectors, and the tradeoff between false positives and detection speed work.</td>
</tr>
<tr>
<td>04</td>
<td><a href="/leader-election-agreeing-on-whos-in-charge">Leader Election: Agreeing on Who's in Charge</a></td>
<td>Leader election coordinates which node acts as primary. Learn the bully algorithm, Raft-based election, and why exactly-one-leader guarantees are hard to achieve.</td>
</tr>
<tr>
<td>05</td>
<td><a href="/consensus-algorithms-agreeing-on-a-value-across-failures">Consensus Algorithms: Agreeing on a Value Across Failures</a></td>
<td>Consensus lets distributed nodes agree on a value despite failures. Learn what FLP impossibility means, what Paxos and Raft provide, and where consensus is used.</td>
</tr>
<tr>
<td>06</td>
<td><a href="/quorum-how-many-nodes-must-agree">Quorum: How Many Nodes Must Agree?</a></td>
<td>Quorum determines how many nodes must agree for an operation to succeed. Learn how R + W &gt; N ensures consistency in distributed databases like Cassandra and DynamoDB.</td>
</tr>
<tr>
<td>07</td>
<td><a href="/paxos-the-algorithm-that-started-it-all">Paxos: The Algorithm That Started It All</a></td>
<td>Paxos is the foundational distributed consensus algorithm. Learn how its two phases work, why it's hard to implement, and what systems use it in production.</td>
</tr>
<tr>
<td>08</td>
<td><a href="/raft-consensus-made-understandable">Raft: Consensus Made Understandable</a></td>
<td>Raft makes distributed consensus understandable. Learn how leader election, log replication, and safety work in the algorithm that powers etcd, CockroachDB, and TiKV.</td>
</tr>
<tr>
<td>09</td>
<td><a href="/gossip-protocol-decentralised-cluster-communication">Gossip Protocol: Decentralised Cluster Communication</a></td>
<td>Gossip protocols propagate information across a cluster without a central coordinator. Learn how epidemic spreading works and where it's used in production.</td>
</tr>
<tr>
<td>10</td>
<td><a href="/logical-clocks-when-physical-time-isnt-enough">Logical Clocks: When Physical Time Isn't Enough</a></td>
<td>Physical clocks drift and can't establish event order in distributed systems. Logical clocks track causality instead. Learn why this matters and how it works.</td>
</tr>
<tr>
<td>11</td>
<td><a href="/lamport-timestamps-ordering-events-without-a-global-clock">Lamport Timestamps: Ordering Events Without a Global Clock</a></td>
<td>Lamport timestamps assign logical counters to events to establish causal order in distributed systems. Learn how they work and what they can and can't tell you.</td>
</tr>
<tr>
<td>12</td>
<td><a href="/vector-clocks-knowing-when-events-are-truly-concurrent">Vector Clocks: Knowing When Events Are Truly Concurrent</a></td>
<td>Vector clocks detect causality and concurrency in distributed systems. Learn how they work, how Dynamo uses them for conflict detection, and their limitations.</td>
</tr>
<tr>
<td>13</td>
<td><a href="/distributed-transactions-when-one-machine-isnt-enough">Distributed Transactions: When One Machine Isn't Enough</a></td>
<td>Distributed transactions are hard. Learn why cross-service atomicity is expensive, when to use it, and when eventual consistency is the right alternative.</td>
</tr>
<tr>
<td>14</td>
<td><a href="/two-phase-commit-coordinating-a-distributed-decision">Two-Phase Commit: Coordinating a Distributed Decision</a></td>
<td>2PC ensures distributed atomicity through prepare and commit phases. Learn how it works, the coordinator failure problem, and why it's rarely used in modern systems.</td>
</tr>
<tr>
<td>15</td>
<td><a href="/three-phase-commit-solving-2pcs-blocking-problem">Three-Phase Commit: Solving 2PC's Blocking Problem</a></td>
<td>3PC adds a pre-commit phase to eliminate 2PC's blocking problem. Learn how it works, what assumptions it requires, and why it's rarely used in production.</td>
</tr>
<tr>
<td>16</td>
<td><a href="/delivery-semantics-what-does-delivered-actually-mean">Delivery Semantics: What Does "Delivered" Actually Mean?</a></td>
<td>Message delivery guarantees define system reliability. Learn what at-most-once, at-least-once, and exactly-once mean, what they cost, and when each is appropriate.</td>
</tr>
<tr>
<td>17</td>
<td><a href="/change-data-capture-streaming-your-database-in-real-time">Change Data Capture: Streaming Your Database in Real Time</a></td>
<td>CDC streams database changes in real time by reading the write-ahead log. Learn how Debezium works, what CDC enables, and when to use it.</td>
</tr>
<tr>
<td>18</td>
<td><a href="/erasure-coding-fault-tolerance-without-full-replication">Erasure Coding: Fault Tolerance Without Full Replication</a></td>
<td>Erasure coding stores data across nodes using math, not full replication. Learn how Reed-Solomon works, how S3 uses it, and when it beats 3x replication.</td>
</tr>
<tr>
<td>19</td>
<td><a href="/merkle-trees-efficiently-finding-whats-different">Merkle Trees: Efficiently Finding What's Different</a></td>
<td>Merkle trees efficiently detect which parts of a large dataset differ between nodes. Learn how Bitcoin, Cassandra, and Git use them for verification and anti-entropy.</td>
</tr>
<tr>
<td>20</td>
<td><a href="/observability-understanding-your-system-at-runtime">Observability: Understanding Your System at Runtime</a></td>
<td>Logs, metrics, and distributed traces are how you understand a system at runtime. Learn what each pillar provides, the tools involved, and how they work together.</td>
</tr>
<tr>
<td>21</td>
<td><strong>Distributed Systems: Wrap-Up</strong> ← you are here</td>
<td>A recap of all 20 distributed systems concepts and the complete URL shortener architecture spanning all 8 pillars. The final post in the series.</td>
</tr>
</tbody></table>
<hr />
<h1>Distributed Systems: Wrap-Up</h1>
<p>Twenty concepts in the final pillar. This post ties them together and closes the series with a complete picture of the URL shortener's architecture across all eight pillars.</p>
<hr />
<h2>The one thing to remember from each post</h2>
<p><strong>Network Partitions</strong> — partitions are inevitable. Every distributed system must have an explicit policy: stay available and accept potential inconsistency (AP), or refuse requests until the partition heals (CP). CAP doesn't tell you which to choose — it tells you the choice is unavoidable.</p>
<p><strong>Split-Brain</strong> — two nodes simultaneously acting as primary cause data corruption. Prevention requires fencing (STONITH): ensure the old primary cannot write before promoting a new one. Never run critical databases in a two-node configuration without a tiebreaker.</p>
<p><strong>Heartbeats</strong> — nodes detect peer failures through absence of periodic signals. Too short a timeout causes false positives; too long delays recovery. Phi accrual failure detectors adapt to observed network behaviour, reducing false positives under load.</p>
<p><strong>Leader Election</strong> — Raft's term-based election: increment term, campaign for votes, win with a majority, prevent old leaders from reasserting via term comparison. The election gap (old leader dead to new leader established) is the fundamental cost of leader-based coordination.</p>
<p><strong>Consensus Algorithms</strong> — Paxos, Raft, Zab allow distributed nodes to agree on a value despite a minority of failures. Safety (all decide the same thing) is unconditional; liveness (a decision is eventually made) requires a functioning majority.</p>
<p><strong>Quorum</strong> — R + W &gt; N guarantees consistency: the read quorum and write quorum overlap. Increase W and R for consistency; decrease for availability. Cassandra's tunable consistency levels let you choose per operation.</p>
<p><strong>Paxos</strong> — prepare (gather promises not to accept older proposals) then accept (commit the value if promises hold). The foundational consensus algorithm. Correct but hard to implement; the inspiration for Raft.</p>
<p><strong>Raft</strong> — leader election + log replication + safety. A candidate must win majority votes with an up-to-date log. The leader replicates entries to followers; commits when a majority acknowledge. Term numbers prevent old leaders from reclaiming authority.</p>
<p><strong>Gossip Protocol</strong> — each node randomly selects a few peers and exchanges state every second. Information propagates exponentially fast (O(log N) rounds) with no central coordinator. Used by Cassandra, Redis Cluster, and Consul for cluster membership.</p>
<p><strong>Logical Clocks</strong> — physical clocks drift and can't establish causal order between events on different machines. Logical clocks track the happened-before relation instead.</p>
<p><strong>Lamport Timestamps</strong> — monotonically increasing counters: increment on events, take max+1 on message receive. If A → B then ts(A) &lt; ts(B). Can't detect concurrency.</p>
<p><strong>Vector Clocks</strong> — one counter per process. Comparing two vector clocks reveals whether one happened-before the other or they're concurrent (each has a higher counter in some dimension). The basis of conflict detection in Dynamo and Riak.</p>
<p><strong>Distributed Transactions</strong> — atomicity across multiple nodes is expensive and fragile. Most cross-service coordination that appears to require distributed transactions can be handled with Saga patterns instead. Use CockroachDB or Spanner when you genuinely need distributed ACID.</p>
<p><strong>Two-Phase Commit</strong> — prepare (all vote, hold locks) then commit/abort (coordinator sends decision). Guarantees atomicity but blocks if coordinator fails after votes but before commit message. The foundation of XA transactions.</p>
<p><strong>Three-Phase Commit</strong> — adds a pre-commit phase to allow independent commit decisions if coordinator fails. Works under crash failures; unsafe under network partitions. Rarely used in practice.</p>
<p><strong>Delivery Semantics</strong> — at-most-once (fast, lossy), at-least-once (reliable, possible duplicates), exactly-once (expensive, achievable within Kafka-to-Kafka). At-least-once with idempotent consumers is the practical choice for almost everything.</p>
<p><strong>Change Data Capture</strong> — read the database's WAL and stream every change as an event. The application writes once (to the database); CDC handles fan-out to Elasticsearch, data warehouses, cache invalidation, and the Outbox relay. Debezium is the standard tool.</p>
<p><strong>Erasure Coding</strong> — split data into k data chunks and n−k parity chunks; any k of n reconstruct the data. 10+4 Reed-Solomon tolerates 4 node failures with 40% storage overhead versus 200% for 3× replication. Best for cold, large, infrequently accessed data.</p>
<p><strong>Merkle Trees</strong> — a tree of hashes where each parent is a hash of its children. Comparing root hashes proves identical content; different roots identify diverged subtrees in O(k log n) comparisons. Used by Cassandra for anti-entropy repair, Git for change detection, and Bitcoin for lightweight transaction verification.</p>
<p><strong>Observability</strong> — structured logs (what happened), metrics (how is the system behaving), and distributed traces (where did the time go). Together they make a distributed black box understandable at runtime. Not optional in microservices.</p>
<hr />
<h2>How the pillars connect</h2>
<p><strong>Pillar 1 (Foundations)</strong> established the theoretical limits: CAP theorem, consistency models, ACID vs BASE. Every decision in Pillars 4–8 is a concrete application of those tradeoffs.</p>
<p><strong>Pillar 2 (Networking)</strong> established the transport: DNS, CDN, HTTP/TLS. The infrastructure that every distributed system rides on.</p>
<p><strong>Pillar 3 (APIs)</strong> established communication patterns: REST, gRPC, WebSockets, webhooks. The interface between services and clients.</p>
<p><strong>Pillar 4 (Data &amp; Storage)</strong> established what to store and where: PostgreSQL, Cassandra, Redis, S3, Elasticsearch, vector databases. Every data decision in Pillar 8 references a system introduced in Pillar 4.</p>
<p><strong>Pillar 5 (Caching)</strong> established the performance layer: cache-aside, eviction, distributed cache, stampede prevention. The reason most systems don't feel slow despite touching many data stores.</p>
<p><strong>Pillar 6 (Scalability)</strong> established the infrastructure layer: load balancing, rate limiting, compression, checksums, probabilistic data structures. The plumbing between the internet and application code.</p>
<p><strong>Pillar 7 (Architecture)</strong> established the system structure: how services are decomposed, how they communicate asynchronously, how resilience is built in, how data flows through pipelines. The blueprint that Pillar 8 fills in with correctness guarantees.</p>
<p><strong>Pillar 8 (Distributed Systems)</strong> established what happens under failure: network partitions, split-brain, consensus, causal ordering, distributed transactions, data integrity, and observability. The foundation that makes all the other pillars work correctly under adversarial conditions.</p>
<hr />
<h2>The complete URL shortener architecture</h2>
<pre><code>═══════════════════════════════════════════════════════════════════
PILLAR 2: Networking
  DNS: Route 53 with geo-routing → nearest edge
  CDN: Cloudflare (Anycast, TLS termination, popular redirect caching)
═══════════════════════════════════════════════════════════════════

PILLAR 6: Scalability
  Rate limiting: Token bucket per API key (Redis counters, global)
  Load balancer: AWS ALB, least-connections algorithm
  Compression: Brotli for all text responses

PILLAR 7: Architecture (entry layer)
  BFF: Mobile BFF + Web BFF + Public API BFF
  Reverse proxy: Nginx (TLS termination, routing, compression)

═══════════════════════════════════════════════════════════════════
SERVICES
═══════════════════════════════════════════════════════════════════

Redirect Service (Go, latency-critical):
  PILLAR 5: Redis cache (consistent hashing, LFU eviction, SWR)
  PILLAR 4: PostgreSQL on cache miss (index scan on short_code)
  PILLAR 6: Bloom filter for unique visitor dedup (RedisBloom)
  PILLAR 6: HyperLogLog for unique visitor counts (Redis PFADD)
  PILLAR 8: Circuit breaker on PostgreSQL calls
  PILLAR 8: Distributed traces (OpenTelemetry → Honeycomb)

Link Service (Rails, CRUD + workflows):
  PILLAR 4: PostgreSQL (primary + 2 read replicas)
  PILLAR 7: Saga pattern for subscription upgrade workflow
  PILLAR 7: Outbox pattern (PostgreSQL outbox → Debezium CDC → Kafka)
  PILLAR 8: CDC via Debezium → link.created events to Kafka
  PILLAR 8: Circuit breakers on all external calls

Analytics Service (Python, stream + batch):
  PILLAR 4: Cassandra (click events, wide-column, TWCS compaction)
  PILLAR 4: TimescaleDB (metrics aggregates)
  PILLAR 7: CQRS: write to Cassandra, read from pre-aggregated views
  PILLAR 7: Stream processing: Kafka → Flink (real-time counters)
  PILLAR 7: Batch processing: nightly Spark job (historical aggregates)
  PILLAR 8: Gossip-based cluster membership (Cassandra ring)
  PILLAR 8: Quorum reads (LOCAL_QUORUM for dashboard queries)

User / Billing / Notification Services:
  PILLAR 4: PostgreSQL (each service owns its schema)
  PILLAR 7: Event-driven reactions to Kafka events
  PILLAR 7: Serverless (Lambda) for scheduled jobs

═══════════════════════════════════════════════════════════════════
DATA INFRASTRUCTURE
═══════════════════════════════════════════════════════════════════

PILLAR 4: Data stores
  PostgreSQL primary (EBS block storage, db.r5.8xlarge)
  PgBouncer (connection pool, transaction mode, 40 connections)
  Redis Cluster (3 primaries + 3 replicas, consistent hashing)
  Cassandra Cluster (6 nodes, gossip membership, phi accrual detection)
  InfluxDB (infrastructure metrics, time-window compaction)
  Elasticsearch (full-text search, Debezium CDC sync)
  Pinecone (semantic embeddings, HNSW ANN search)
  S3 (user uploads, exports; erasure-coded durability internally)

PILLAR 8: Distributed systems layer
  Raft consensus: etcd (Kubernetes state), CockroachDB (billing transactions)
  Gossip: Cassandra ring membership, Redis Cluster slot state
  Anti-entropy: Cassandra repair via Merkle tree comparison
  CDC: Debezium watching PostgreSQL WAL → Kafka
  Observability:
    Logs: structured JSON → Loki → Grafana
    Metrics: Prometheus → Grafana (p99 latency, error rate, saturation)
    Traces: OpenTelemetry → Honeycomb (distributed trace per request)

PILLAR 8: Failure handling
  Split-brain prevention: Patroni with EC2 instance termination fencing
  Heartbeats: 10s interval, phi accrual failure detection (Cassandra)
  Leader election: Raft (etcd), Patroni (PostgreSQL HA)
  Delivery semantics: at-least-once + idempotent consumers everywhere
  Partition policy:
    PostgreSQL: CP (Patroni requires quorum for promotion)
    Cassandra: AP tunable (LOCAL_QUORUM for reads, ONE for click writes)
    Redis: AP (last-write-wins on partition heal)

PILLAR 7 → 8 bridges:
  Saga + Outbox + CDC: subscription upgrades are saga-coordinated;
    each step uses outbox pattern for reliable event publishing;
    Debezium picks up outbox rows without polling
  Circuit breaker + Observability: every tripped circuit breaker
    emits a metric and a trace span, surfaced immediately in Grafana
</code></pre>
<hr />
<h2>What this series covered</h2>
<p>Eight pillars. Roughly 120 concepts. One URL shortener that started as a single Rails app on a single server and ended as a distributed, multi-region, observable, fault-tolerant platform.</p>
<p>The series deliberately follows the same thread: every concept was introduced when the running example created a problem that concept solves. Consistent hashing appeared because the Redis cluster needed to add nodes without invalidating the cache. The Outbox pattern appeared because the Saga needed reliable event publishing. Merkle trees appeared because Cassandra needed to repair replicas that diverged during a partition.</p>
<p>Systems design isn't a collection of unrelated tools. It's a set of problems that naturally occur as systems grow, and a set of patterns that address each problem with known tradeoffs. The goal of this series was to build that mental model — not a checklist, but a way of reasoning about what a system needs and why.</p>
<hr />
<h2>Thank you for reading</h2>
<p>This is the final post in the series. If you found it useful, the best thing you can do is share the specific posts that helped you — the ones that clicked something into place, answered a question you'd had for a while, or gave you language for something you'd been doing instinctively.</p>
<p>The series starts here: <strong><a href="#">Pillar 1 — Foundations</a></strong></p>
<hr />
<p>*← Previous: <strong><a href="/observability-understanding-your-system-at-runtime">Observability</a></strong> — structured logs, metrics, and distributed tracing: the tools that make distributed systems understandable at runtime.*<em>This is the final post in the System Design series. Start from the beginning: <a href="#">Pillar 1 — Foundations</a></em></p>
]]></content:encoded></item><item><title><![CDATA[Observability: Understanding Your System at Runtime]]></title><description><![CDATA[Series: System Design · Distributed Systems — Pillar 8 of 8

Systems Design



#
Post
What it covers



00
Distributed Systems: What Happens When Machines Disagree
Twenty concepts covering network par]]></description><link>https://cloudtuned.dev/observability-understanding-your-system-at-runtime</link><guid isPermaLink="true">https://cloudtuned.dev/observability-understanding-your-system-at-runtime</guid><category><![CDATA[systemdesign]]></category><category><![CDATA[distributedsystems]]></category><category><![CDATA[observability]]></category><category><![CDATA[tracing]]></category><category><![CDATA[metrics]]></category><category><![CDATA[backend]]></category><category><![CDATA[SoftwareDevelopment]]></category><category><![CDATA[softwarearchitecture]]></category><category><![CDATA[engineering]]></category><dc:creator><![CDATA[Cloud Tuned]]></dc:creator><pubDate>Thu, 13 Mar 2025 12:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/602bee9a4bb9c4083f02795d/0b42cafc-33ca-4600-b1fd-3d9e10b9629c.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote>
<p><strong>Series:</strong> System Design · Distributed Systems — Pillar 8 of 8</p>
</blockquote>
<h2>Systems Design</h2>
<table>
<thead>
<tr>
<th>#</th>
<th>Post</th>
<th>What it covers</th>
</tr>
</thead>
<tbody><tr>
<td>00</td>
<td><a href="/distributed-systems-what-happens-when-machines-disagree">Distributed Systems: What Happens When Machines Disagree</a></td>
<td>Twenty concepts covering network partitions, consensus, clocks, distributed transactions, CDC, erasure coding, and observability. The final pillar.</td>
</tr>
<tr>
<td>01</td>
<td><a href="/network-partitions-the-failure-mode-you-cant-design-away">Network Partitions: The Failure Mode You Can't Design Away</a></td>
<td>Network partitions are inevitable. Learn what happens when nodes can't communicate, how systems choose between availability and consistency, and what that means in practice.</td>
</tr>
<tr>
<td>02</td>
<td><a href="/split-brain-when-two-nodes-both-think-theyre-the-leader">Split-Brain: When Two Nodes Both Think They're the Leader</a></td>
<td>Split-brain occurs when two nodes both believe they're the primary. Learn how it happens, why it causes data corruption, and how STONITH and fencing prevent it.</td>
</tr>
<tr>
<td>03</td>
<td><a href="/heartbeats-how-nodes-know-their-peers-are-alive">Heartbeats: How Nodes Know Their Peers Are Alive</a></td>
<td>Heartbeats let nodes detect peer failures. Learn how timeouts, phi accrual failure detectors, and the tradeoff between false positives and detection speed work.</td>
</tr>
<tr>
<td>04</td>
<td><a href="/leader-election-agreeing-on-whos-in-charge">Leader Election: Agreeing on Who's in Charge</a></td>
<td>Leader election coordinates which node acts as primary. Learn the bully algorithm, Raft-based election, and why exactly-one-leader guarantees are hard to achieve.</td>
</tr>
<tr>
<td>05</td>
<td><a href="/consensus-algorithms-agreeing-on-a-value-across-failures">Consensus Algorithms: Agreeing on a Value Across Failures</a></td>
<td>Consensus lets distributed nodes agree on a value despite failures. Learn what FLP impossibility means, what Paxos and Raft provide, and where consensus is used.</td>
</tr>
<tr>
<td>06</td>
<td><a href="/quorum-how-many-nodes-must-agree">Quorum: How Many Nodes Must Agree?</a></td>
<td>Quorum determines how many nodes must agree for an operation to succeed. Learn how R + W &gt; N ensures consistency in distributed databases like Cassandra and DynamoDB.</td>
</tr>
<tr>
<td>07</td>
<td><a href="/paxos-the-algorithm-that-started-it-all">Paxos: The Algorithm That Started It All</a></td>
<td>Paxos is the foundational distributed consensus algorithm. Learn how its two phases work, why it's hard to implement, and what systems use it in production.</td>
</tr>
<tr>
<td>08</td>
<td><a href="/raft-consensus-made-understandable">Raft: Consensus Made Understandable</a></td>
<td>Raft makes distributed consensus understandable. Learn how leader election, log replication, and safety work in the algorithm that powers etcd, CockroachDB, and TiKV.</td>
</tr>
<tr>
<td>09</td>
<td><a href="/gossip-protocol-decentralised-cluster-communication">Gossip Protocol: Decentralised Cluster Communication</a></td>
<td>Gossip protocols propagate information across a cluster without a central coordinator. Learn how epidemic spreading works and where it's used in production.</td>
</tr>
<tr>
<td>10</td>
<td><a href="/logical-clocks-when-physical-time-isnt-enough">Logical Clocks: When Physical Time Isn't Enough</a></td>
<td>Physical clocks drift and can't establish event order in distributed systems. Logical clocks track causality instead. Learn why this matters and how it works.</td>
</tr>
<tr>
<td>11</td>
<td><a href="/lamport-timestamps-ordering-events-without-a-global-clock">Lamport Timestamps: Ordering Events Without a Global Clock</a></td>
<td>Lamport timestamps assign logical counters to events to establish causal order in distributed systems. Learn how they work and what they can and can't tell you.</td>
</tr>
<tr>
<td>12</td>
<td><a href="/vector-clocks-knowing-when-events-are-truly-concurrent">Vector Clocks: Knowing When Events Are Truly Concurrent</a></td>
<td>Vector clocks detect causality and concurrency in distributed systems. Learn how they work, how Dynamo uses them for conflict detection, and their limitations.</td>
</tr>
<tr>
<td>13</td>
<td><a href="/distributed-transactions-when-one-machine-isnt-enough">Distributed Transactions: When One Machine Isn't Enough</a></td>
<td>Distributed transactions are hard. Learn why cross-service atomicity is expensive, when to use it, and when eventual consistency is the right alternative.</td>
</tr>
<tr>
<td>14</td>
<td><a href="/two-phase-commit-coordinating-a-distributed-decision">Two-Phase Commit: Coordinating a Distributed Decision</a></td>
<td>2PC ensures distributed atomicity through prepare and commit phases. Learn how it works, the coordinator failure problem, and why it's rarely used in modern systems.</td>
</tr>
<tr>
<td>15</td>
<td><a href="/three-phase-commit-solving-2pcs-blocking-problem">Three-Phase Commit: Solving 2PC's Blocking Problem</a></td>
<td>3PC adds a pre-commit phase to eliminate 2PC's blocking problem. Learn how it works, what assumptions it requires, and why it's rarely used in production.</td>
</tr>
<tr>
<td>16</td>
<td><a href="/delivery-semantics-what-does-delivered-actually-mean">Delivery Semantics: What Does "Delivered" Actually Mean?</a></td>
<td>Message delivery guarantees define system reliability. Learn what at-most-once, at-least-once, and exactly-once mean, what they cost, and when each is appropriate.</td>
</tr>
<tr>
<td>17</td>
<td><a href="/change-data-capture-streaming-your-database-in-real-time">Change Data Capture: Streaming Your Database in Real Time</a></td>
<td>CDC streams database changes in real time by reading the write-ahead log. Learn how Debezium works, what CDC enables, and when to use it.</td>
</tr>
<tr>
<td>18</td>
<td><a href="/erasure-coding-fault-tolerance-without-full-replication">Erasure Coding: Fault Tolerance Without Full Replication</a></td>
<td>Erasure coding stores data across nodes using math, not full replication. Learn how Reed-Solomon works, how S3 uses it, and when it beats 3x replication.</td>
</tr>
<tr>
<td>19</td>
<td><a href="/merkle-trees-efficiently-finding-whats-different">Merkle Trees: Efficiently Finding What's Different</a></td>
<td>Merkle trees efficiently detect which parts of a large dataset differ between nodes. Learn how Bitcoin, Cassandra, and Git use them for verification and anti-entropy.</td>
</tr>
<tr>
<td>20</td>
<td><strong>Observability: Understanding Your System at Runtime</strong> ← you are here</td>
<td>Logs, metrics, and distributed traces are how you understand a system at runtime. Learn what each pillar provides, the tools involved, and how they work together.</td>
</tr>
<tr>
<td>21</td>
<td><a href="/distributed-systems-wrap-up">Distributed Systems: Wrap-Up</a></td>
<td>A recap of all 20 distributed systems concepts and the complete URL shortener architecture spanning all 8 pillars. The final post in the series.</td>
</tr>
</tbody></table>
<hr />
<h1>Observability: Understanding Your System at Runtime</h1>
<h2>The problem</h2>
<p>A user reports that redirects for their links are slow — sometimes 3–4 seconds instead of the normal 10ms. You look at the application dashboard: everything green. No errors logged. CPU, memory, and database query times all look normal.</p>
<p>But the user is experiencing real slowness. Somewhere in the system, something is wrong. Without instrumentation, you're debugging blind: the system is a black box, and the only signal you have is "users are unhappy."</p>
<p>This is the problem observability solves. An observable system tells you what it's doing at runtime — not just whether it's up, but why specific requests are slow, where in the call chain the latency is, what the error rate is per service, and which specific dependency is causing the problem.</p>
<hr />
<h2>The core idea</h2>
<p>Observability is the property of a system that allows you to understand its internal state from its external outputs. In practice, observability consists of three types of telemetry data — logs, metrics, and traces — each answering a different question: what happened, how is the system behaving, and where did the time go.</p>
<hr />
<h2>The analogy: a pilot's cockpit instruments</h2>
<p>An observable system is an aircraft with a full instrument panel. The pilot doesn't need to step outside to check if the engine is running — the tachometer shows RPM. They don't need to feel the altitude — the altimeter shows it. They don't need to hear turbulence — the autopilot's course deviation indicator shows it.</p>
<p>Each instrument answers a specific question. No single instrument tells the whole story — but together they give the pilot a complete picture of the aircraft's state.</p>
<p>An unobservable system is flying by feel in clouds: you know you're moving, you know roughly where you started, but you have no clear picture of where you are or what's about to go wrong.</p>
<hr />
<h2>The three pillars</h2>
<div class="hn-embed-widget" id="obs-three-pillars-widget"></div>

<h3>Logs: what happened</h3>
<p>Logs are timestamped, structured records of individual events in the system. They answer: "what exactly happened, and when?"</p>
<p><strong>Structured logging</strong> (JSON) is the modern standard. Plain text logs are machine-readable only with complex parsing; JSON logs can be queried directly:</p>
<pre><code class="language-json">{
  "timestamp": "2025-06-01T14:00:00.123Z",
  "level": "INFO",
  "service": "redirect-service",
  "trace_id": "abc123",
  "span_id": "def456",
  "message": "Redirect completed",
  "short_code": "x7Kp2",
  "destination": "https://example.com",
  "duration_ms": 8,
  "cache_hit": true,
  "user_agent": "Mozilla/5.0..."
}
</code></pre>
<p>Every log entry carries the trace ID (to correlate with a distributed trace) and span ID (to identify the specific operation within the trace).</p>
<p><strong>Log aggregation:</strong> services ship logs to a central store (Elasticsearch/Kibana, Datadog, Loki/Grafana). Engineers query across all services by time, service, trace ID, user, error message, etc.</p>
<p><strong>Key design principles:</strong> log at appropriate levels (DEBUG for development, INFO for normal operations, WARN for recoverable issues, ERROR for failures); include context (IDs, user references, relevant parameters); never log PII in production.</p>
<h3>Metrics: how is the system behaving</h3>
<p>Metrics are numeric measurements of system behaviour over time. They answer: "is the system healthy, and what's its current performance?"</p>
<p>The four Golden Signals (from Google's Site Reliability Engineering book):</p>
<ul>
<li><p><strong>Latency:</strong> how long requests take (p50, p95, p99)</p>
</li>
<li><p><strong>Traffic:</strong> how many requests per second</p>
</li>
<li><p><strong>Errors:</strong> error rate (% of requests failing)</p>
</li>
<li><p><strong>Saturation:</strong> how full the system is (CPU %, memory %, queue depth)</p>
</li>
</ul>
<p><strong>RED method (for services):</strong> Rate, Errors, Duration — the minimum viable metrics for any service.</p>
<p><strong>USE method (for infrastructure):</strong> Utilisation, Saturation, Errors — for CPUs, memory, disks, networks.</p>
<p><strong>Prometheus + Grafana</strong> is the standard open-source stack. Services expose a <code>/metrics</code> endpoint in Prometheus format; Prometheus scrapes it; Grafana visualises it.</p>
<pre><code class="language-plaintext"># Prometheus metrics exposed by the redirect service
http_requests_total{method="GET",path="/r",status="200"} 1423904
http_request_duration_seconds_bucket{le="0.01"} 1390000
http_request_duration_seconds_bucket{le="0.1"} 1423500
redirect_cache_hits_total 1401234
redirect_cache_misses_total 22670
</code></pre>
<p><strong>Alerting:</strong> alert rules fire when metrics cross thresholds. p99 latency &gt; 100ms → PagerDuty alert. Error rate &gt; 1% → alert. Queue depth &gt; 1000 → alert.</p>
<h3>Distributed tracing: where did the time go?</h3>
<div class="hn-embed-widget" id="obs-trace-anatomy-widget"></div>

<p>A trace records the journey of a single request through all the services it touched. It answers: "for this specific request, which service took how long, and where exactly was the time spent?"</p>
<p>Without tracing, a request that touches 5 services produces 5 separate log streams. Correlating them manually to understand which service was slow is laborious and error-prone.</p>
<p>With tracing, the entire request's journey is captured in one trace:</p>
<pre><code class="language-plaintext">Trace: abc123 (total: 3247ms)
  [Redirect Service: 3247ms]
    ├─ DNS lookup: 1ms
    ├─ [Redis Cache: 8ms] → MISS
    └─ [PostgreSQL Query: 3230ms] ← THE SLOW PART
         └─ query: SELECT destination FROM links WHERE short_code='x7Kp2'
              indexes used: none (missing index on short_code)
              rows scanned: 50,000,000
</code></pre>
<p>This trace immediately identifies the problem: no index on <code>short_code</code>. Without tracing, this 3-second slowness would be a mystery — the application logs show "query executed," the database logs show "slow query," but connecting them requires manual correlation.</p>
<p><strong>OpenTelemetry:</strong> the standard for instrumentation. Services emit spans (individual operations within a trace) in OpenTelemetry format. Backends (Jaeger, Honeycomb, Datadog) store and visualise traces.</p>
<p><strong>Trace propagation:</strong> when Service A calls Service B, it passes the trace ID and span ID in HTTP headers (<code>traceparent: 00-abc123-def456-01</code>). Service B creates a child span under the parent span. The entire distributed call chain is captured.</p>
<pre><code class="language-plaintext"># Request headers from Service A to Service B
traceparent: 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01
                  ↑ trace ID                    ↑ parent span ID
</code></pre>
<hr />
<h2>The relationship between pillars</h2>
<p>The three pillars answer different questions but are most powerful combined:</p>
<p><strong>An alert fires (metric): redirect p99 latency &gt; 500ms</strong> → Open traces for the time period → find the slow traces → Identify which span is slow (e.g., PostgreSQL query: 3.2s) → Check logs for that trace ID → confirm the exact query, parameters, and context → Root cause identified in minutes, not hours</p>
<p>Each pillar narrows the investigation. Metrics surface the symptom. Traces locate the service and operation. Logs provide the specific context.</p>
<p>See our interactive diagram below:</p>
<div class="hn-embed-widget" id="obs-investigation-flow-widget"></div>

<hr />
<h2>Tradeoffs</h2>
<p><strong>Sampling.</strong> High-traffic services can't record 100% of traces — the storage cost is too high. Most tracing systems sample: record 1% or 10% of traces. This means rare slow requests may not be captured. Adaptive sampling (always record traces with high latency or errors) mitigates this.</p>
<p><strong>Cardinality explosion.</strong> Metrics with high-cardinality labels (one label value per user ID, per URL, per session) create millions of time series — most systems can't handle this. Keep metric label cardinality low; use logs or traces for high-cardinality data.</p>
<p><strong>Operational overhead.</strong> Running a log aggregation stack (Elasticsearch), a metrics system (Prometheus + Grafana), and a tracing backend (Jaeger) is three separate systems to maintain. Managed services (Datadog, Honeycomb, New Relic) trade cost for operational simplicity.</p>
<p><strong>Instrumentation discipline.</strong> Observability requires intentional instrumentation — it doesn't happen automatically. Every service must emit structured logs, expose metrics, and propagate trace headers. This is an ongoing engineering effort, not a one-time setup.</p>
<hr />
<h2>The one thing to remember</h2>
<blockquote>
<p><strong>Observability is not monitoring — it's the property of a system that lets you ask arbitrary questions about its behaviour at runtime.</strong> Logs answer what happened. Metrics answer how the system is performing. Traces answer where time was spent in a specific request. Together, they turn a distributed black box into a system you can reason about during incidents. In a microservices system, observability is not optional — without it, production debugging is archaeology.</p>
</blockquote>
<hr />
<p><em>← Previous:</em> <a href="/merkle-trees-efficiently-finding-whats-different"><em><strong>Merkle Trees</strong></em></a> <em>— efficiently comparing large datasets across distributed nodes to find which parts have diverged.</em></p>
<p><em>→ Next:</em> <a href="/distributed-systems-wrap-up"><em><strong>Distributed Systems — Wrap-up</strong></em></a> <em>— tying together all 20 concepts in this final pillar and the complete series.</em></p>
]]></content:encoded></item><item><title><![CDATA[Merkle Trees: Efficiently Finding What's Different]]></title><description><![CDATA[Series: System Design · Distributed Systems — Pillar 8 of 8

Systems Design



#
Post
What it covers



00
Distributed Systems: What Happens When Machines Disagree
Twenty concepts covering network par]]></description><link>https://cloudtuned.dev/merkle-trees-efficiently-finding-whats-different</link><guid isPermaLink="true">https://cloudtuned.dev/merkle-trees-efficiently-finding-whats-different</guid><category><![CDATA[systemdesign]]></category><category><![CDATA[distributedsystems]]></category><category><![CDATA[merkletrees]]></category><category><![CDATA[Cassandra]]></category><category><![CDATA[Git]]></category><category><![CDATA[backend]]></category><category><![CDATA[SoftwareDevelopment]]></category><category><![CDATA[softwarearchitecture]]></category><category><![CDATA[engineering]]></category><dc:creator><![CDATA[Cloud Tuned]]></dc:creator><pubDate>Wed, 12 Mar 2025 12:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/602bee9a4bb9c4083f02795d/efb9153e-2174-4c75-9cba-dc3c428727e2.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote>
<p><strong>Series:</strong> System Design · Distributed Systems — Pillar 8 of 8</p>
</blockquote>
<h2>Systems Design</h2>
<table>
<thead>
<tr>
<th>#</th>
<th>Post</th>
<th>What it covers</th>
</tr>
</thead>
<tbody><tr>
<td>00</td>
<td><a href="/distributed-systems-what-happens-when-machines-disagree">Distributed Systems: What Happens When Machines Disagree</a></td>
<td>Twenty concepts covering network partitions, consensus, clocks, distributed transactions, CDC, erasure coding, and observability. The final pillar.</td>
</tr>
<tr>
<td>01</td>
<td><a href="/network-partitions-the-failure-mode-you-cant-design-away">Network Partitions: The Failure Mode You Can't Design Away</a></td>
<td>Network partitions are inevitable. Learn what happens when nodes can't communicate, how systems choose between availability and consistency, and what that means in practice.</td>
</tr>
<tr>
<td>02</td>
<td><a href="/split-brain-when-two-nodes-both-think-theyre-the-leader">Split-Brain: When Two Nodes Both Think They're the Leader</a></td>
<td>Split-brain occurs when two nodes both believe they're the primary. Learn how it happens, why it causes data corruption, and how STONITH and fencing prevent it.</td>
</tr>
<tr>
<td>03</td>
<td><a href="/heartbeats-how-nodes-know-their-peers-are-alive">Heartbeats: How Nodes Know Their Peers Are Alive</a></td>
<td>Heartbeats let nodes detect peer failures. Learn how timeouts, phi accrual failure detectors, and the tradeoff between false positives and detection speed work.</td>
</tr>
<tr>
<td>04</td>
<td><a href="/leader-election-agreeing-on-whos-in-charge">Leader Election: Agreeing on Who's in Charge</a></td>
<td>Leader election coordinates which node acts as primary. Learn the bully algorithm, Raft-based election, and why exactly-one-leader guarantees are hard to achieve.</td>
</tr>
<tr>
<td>05</td>
<td><a href="/consensus-algorithms-agreeing-on-a-value-across-failures">Consensus Algorithms: Agreeing on a Value Across Failures</a></td>
<td>Consensus lets distributed nodes agree on a value despite failures. Learn what FLP impossibility means, what Paxos and Raft provide, and where consensus is used.</td>
</tr>
<tr>
<td>06</td>
<td><a href="/quorum-how-many-nodes-must-agree">Quorum: How Many Nodes Must Agree?</a></td>
<td>Quorum determines how many nodes must agree for an operation to succeed. Learn how R + W &gt; N ensures consistency in distributed databases like Cassandra and DynamoDB.</td>
</tr>
<tr>
<td>07</td>
<td><a href="/paxos-the-algorithm-that-started-it-all">Paxos: The Algorithm That Started It All</a></td>
<td>Paxos is the foundational distributed consensus algorithm. Learn how its two phases work, why it's hard to implement, and what systems use it in production.</td>
</tr>
<tr>
<td>08</td>
<td><a href="/raft-consensus-made-understandable">Raft: Consensus Made Understandable</a></td>
<td>Raft makes distributed consensus understandable. Learn how leader election, log replication, and safety work in the algorithm that powers etcd, CockroachDB, and TiKV.</td>
</tr>
<tr>
<td>09</td>
<td><a href="/gossip-protocol-decentralised-cluster-communication">Gossip Protocol: Decentralised Cluster Communication</a></td>
<td>Gossip protocols propagate information across a cluster without a central coordinator. Learn how epidemic spreading works and where it's used in production.</td>
</tr>
<tr>
<td>10</td>
<td><a href="/logical-clocks-when-physical-time-isnt-enough">Logical Clocks: When Physical Time Isn't Enough</a></td>
<td>Physical clocks drift and can't establish event order in distributed systems. Logical clocks track causality instead. Learn why this matters and how it works.</td>
</tr>
<tr>
<td>11</td>
<td><a href="/lamport-timestamps-ordering-events-without-a-global-clock">Lamport Timestamps: Ordering Events Without a Global Clock</a></td>
<td>Lamport timestamps assign logical counters to events to establish causal order in distributed systems. Learn how they work and what they can and can't tell you.</td>
</tr>
<tr>
<td>12</td>
<td><a href="/vector-clocks-knowing-when-events-are-truly-concurrent">Vector Clocks: Knowing When Events Are Truly Concurrent</a></td>
<td>Vector clocks detect causality and concurrency in distributed systems. Learn how they work, how Dynamo uses them for conflict detection, and their limitations.</td>
</tr>
<tr>
<td>13</td>
<td><a href="/distributed-transactions-when-one-machine-isnt-enough">Distributed Transactions: When One Machine Isn't Enough</a></td>
<td>Distributed transactions are hard. Learn why cross-service atomicity is expensive, when to use it, and when eventual consistency is the right alternative.</td>
</tr>
<tr>
<td>14</td>
<td><a href="/two-phase-commit-coordinating-a-distributed-decision">Two-Phase Commit: Coordinating a Distributed Decision</a></td>
<td>2PC ensures distributed atomicity through prepare and commit phases. Learn how it works, the coordinator failure problem, and why it's rarely used in modern systems.</td>
</tr>
<tr>
<td>15</td>
<td><a href="/three-phase-commit-solving-2pcs-blocking-problem">Three-Phase Commit: Solving 2PC's Blocking Problem</a></td>
<td>3PC adds a pre-commit phase to eliminate 2PC's blocking problem. Learn how it works, what assumptions it requires, and why it's rarely used in production.</td>
</tr>
<tr>
<td>16</td>
<td><a href="/delivery-semantics-what-does-delivered-actually-mean">Delivery Semantics: What Does "Delivered" Actually Mean?</a></td>
<td>Message delivery guarantees define system reliability. Learn what at-most-once, at-least-once, and exactly-once mean, what they cost, and when each is appropriate.</td>
</tr>
<tr>
<td>17</td>
<td><a href="/change-data-capture-streaming-your-database-in-real-time">Change Data Capture: Streaming Your Database in Real Time</a></td>
<td>CDC streams database changes in real time by reading the write-ahead log. Learn how Debezium works, what CDC enables, and when to use it.</td>
</tr>
<tr>
<td>18</td>
<td><a href="/erasure-coding-fault-tolerance-without-full-replication">Erasure Coding: Fault Tolerance Without Full Replication</a></td>
<td>Erasure coding stores data across nodes using math, not full replication. Learn how Reed-Solomon works, how S3 uses it, and when it beats 3x replication.</td>
</tr>
<tr>
<td>19</td>
<td><strong>Merkle Trees: Efficiently Finding What's Different</strong> ← you are here</td>
<td>Merkle trees efficiently detect which parts of a large dataset differ between nodes. Learn how Bitcoin, Cassandra, and Git use them for verification and anti-entropy.</td>
</tr>
<tr>
<td>20</td>
<td><a href="/observability-understanding-your-system-at-runtime">Observability: Understanding Your System at Runtime</a></td>
<td>Logs, metrics, and distributed traces are how you understand a system at runtime. Learn what each pillar provides, the tools involved, and how they work together.</td>
</tr>
<tr>
<td>21</td>
<td><a href="/distributed-systems-wrap-up">Distributed Systems: Wrap-Up</a></td>
<td>A recap of all 20 distributed systems concepts and the complete URL shortener architecture spanning all 8 pillars. The final post in the series.</td>
</tr>
</tbody></table>
<hr />
<h1>Merkle Trees: Efficiently Finding What's Different</h1>
<h2>The problem</h2>
<p>Your Cassandra cluster has two replicas of the same partition. After a network partition healed, you're not sure they're in sync — some writes may have gone to only one replica during the partition. You need to identify which records differ so you can repair the inconsistency.</p>
<p>The brute-force approach: send every row from Replica A to Replica B, compare each one. For a partition with 100 million rows, that's 100 million rows transferred over the network — enormous I/O just to find a handful of diverged records.</p>
<p>A smarter approach: compare summaries of the data rather than the data itself. If the summary of all 100 million rows is the same on both replicas, no comparison needed. If they differ, recursively drill into subsections until you find the specific rows that diverged.</p>
<p>This is the Merkle tree.</p>
<hr />
<h2>The core idea (see our interactive diagram)</h2>
<div class="hn-embed-widget" id="merkle-tree-comparison-widget"></div>

<p>A Merkle tree is a binary tree where each leaf node contains the hash of a data block, and each non-leaf node contains the hash of its children's hashes. The root hash is a single value that represents the entire dataset: if any data block changes, the hash propagates up through the tree, changing the root hash. Two datasets with the same root hash have identical content; different root hashes mean something differs, and the tree structure reveals exactly where.</p>
<hr />
<h2>The analogy: a library's section catalogue</h2>
<p>A librarian checks whether two library branches have identical collections. Rather than comparing every book:</p>
<ol>
<li><p>Compare the hash of the entire "Science Fiction" section. Same? No need to check individual SF books.</p>
</li>
<li><p>Compare the hash of "Classic SF". Different → drill deeper.</p>
</li>
<li><p>Compare "Classic SF, A–L". Same. Compare "Classic SF, M–Z". Different → drill deeper.</p>
</li>
<li><p>Identify the specific shelf, then the specific book that differs.</p>
</li>
</ol>
<p>Each level narrows the search. Instead of comparing every book (O(n)), you do O(log n) comparisons to find each differing item.</p>
<hr />
<h2>How Merkle trees work</h2>
<h3>Construction (interactive diagram)</h3>
<div class="hn-embed-widget" id="merkle-tree-construction-widget"></div>



<p>Two datasets with the same root hash are guaranteed identical (assuming collision-resistant hashes). Two datasets with different root hashes differ in at least one block.</p>
<h3>Efficient comparison</h3>
<p>To find which blocks differ between two Merkle trees:</p>
<ol>
<li><p>Compare root hashes. Same → done (all data identical). Different → proceed.</p>
</li>
<li><p>Compare the two children of the root. Find which subtree(s) differ.</p>
</li>
<li><p>Recursively compare the differing subtrees.</p>
</li>
<li><p>Continue until leaf nodes — the specific differing blocks are identified.</p>
</li>
</ol>
<p>In a balanced binary tree with n leaves, this takes O(k log n) comparisons, where k is the number of differing blocks. For a dataset with 100 million blocks and only 100 differing, this is dramatically fewer comparisons than comparing all 100 million.</p>
<hr />
<h2>Where Merkle trees are used</h2>
<div class="hn-embed-widget" id="merkle-tree-use-cases-widget"></div>

<h3>Cassandra anti-entropy repair</h3>
<p>Cassandra's <code>nodetool repair</code> command uses Merkle trees to synchronise replicas. For a given token range:</p>
<ol>
<li><p>Each replica builds a Merkle tree of its data for that range</p>
</li>
<li><p>Replicas exchange their root hashes (gossip)</p>
</li>
<li><p>If hashes differ, replicas compare trees recursively to find differing rows</p>
</li>
<li><p>Only the differing rows are transferred and reconciled</p>
</li>
</ol>
<p>Without Merkle trees, repair would require comparing every row — too expensive for multi-terabyte partitions. With Merkle trees, only divergent rows are identified and repaired.</p>
<h3>Git</h3>
<p>Git's internal object model is a Merkle tree. Every file is stored as a "blob" object (content + hash). Every directory is a "tree" object containing hashes of its children (files and subdirectories). Every commit is a "commit" object containing the hash of the root tree.</p>
<p>If two commits have different root tree hashes, something in the codebase changed. Finding what changed means traversing the tree to find which subtrees (directories) differ — O(log n) comparisons instead of comparing every file.</p>
<h3>Bitcoin blockchain</h3>
<p>Each block in the Bitcoin blockchain contains a Merkle root of all transactions in that block. To verify that a specific transaction is included in a block, you need only log(n) hashes (the "Merkle proof") rather than all n transactions. Light clients (mobile wallets) use this to verify transactions without downloading the full blockchain.</p>
<h3>DynamoDB/Cassandra replication synchronisation</h3>
<p>Both use variants of Merkle trees (hash trees) for comparing replica state and identifying diverged segments for repair.</p>
<hr />
<h2>Tradeoffs</h2>
<p><strong>Tree construction cost.</strong> Building a Merkle tree over a large dataset requires hashing every data block. For a 1 TB partition, this is significant I/O and CPU — Cassandra's repair process is resource-intensive and should be run during low-traffic periods.</p>
<p><strong>Freshness vs accuracy.</strong> The tree is a snapshot at construction time. If data is changing rapidly while the tree is being built, the tree may be immediately stale. Cassandra limits repair scope to control this.</p>
<p><strong>Depth vs granularity.</strong> A deeper tree finds differences with more precision (smaller data blocks per leaf) but requires more comparison steps. The right tree depth depends on the ratio of total data to expected number of differences.</p>
<hr />
<h2>The one thing to remember</h2>
<blockquote>
<p><strong>A Merkle tree makes comparing large datasets efficient: the root hash proves identity; differing subtrees narrow the search.</strong> Instead of comparing every record (O(n)), you compare log(n) hashes to identify exactly which data blocks differ. This is how Cassandra finds inconsistent replicas without transferring terabytes of data, how Git tracks repository changes, and how Bitcoin verifies transactions without a full blockchain download.</p>
</blockquote>
<hr />
<p><em>← Previous:</em> <a href="/erasure-coding-fault-tolerance-without-full-replication"><em><strong>Erasure Coding</strong></em></a> <em>— storing data redundantly using mathematics rather than full replication.</em></p>
<p><em>→ Next:</em> <a href="/observability-understanding-your-system-at-runtime"><em><strong>Observability</strong></em></a> <em>— structured logs, metrics, and distributed tracing: the tools that make distributed systems understandable at runtime.</em></p>
]]></content:encoded></item><item><title><![CDATA[Erasure Coding: Fault Tolerance Without Full Replication]]></title><description><![CDATA[Series: System Design · Distributed Systems — Pillar 8 of 8

Systems Design



#
Post
What it covers



00
Distributed Systems: What Happens When Machines Disagree
Twenty concepts covering network par]]></description><link>https://cloudtuned.dev/erasure-coding-fault-tolerance-without-full-replication</link><guid isPermaLink="true">https://cloudtuned.dev/erasure-coding-fault-tolerance-without-full-replication</guid><category><![CDATA[systemdesign]]></category><category><![CDATA[distributedsystems]]></category><category><![CDATA[erasurecoding]]></category><category><![CDATA[storage]]></category><category><![CDATA[S3]]></category><category><![CDATA[backend]]></category><category><![CDATA[SoftwareDevelopment]]></category><category><![CDATA[softwarearchitecture]]></category><category><![CDATA[engineering]]></category><dc:creator><![CDATA[Cloud Tuned]]></dc:creator><pubDate>Tue, 11 Mar 2025 12:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/602bee9a4bb9c4083f02795d/b480e771-5247-4116-aa93-8ceefe782666.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote>
<p><strong>Series:</strong> System Design · Distributed Systems — Pillar 8 of 8</p>
</blockquote>
<h2>Systems Design</h2>
<table>
<thead>
<tr>
<th>#</th>
<th>Post</th>
<th>What it covers</th>
</tr>
</thead>
<tbody><tr>
<td>00</td>
<td><a href="/distributed-systems-what-happens-when-machines-disagree">Distributed Systems: What Happens When Machines Disagree</a></td>
<td>Twenty concepts covering network partitions, consensus, clocks, distributed transactions, CDC, erasure coding, and observability. The final pillar.</td>
</tr>
<tr>
<td>01</td>
<td><a href="/network-partitions-the-failure-mode-you-cant-design-away">Network Partitions: The Failure Mode You Can't Design Away</a></td>
<td>Network partitions are inevitable. Learn what happens when nodes can't communicate, how systems choose between availability and consistency, and what that means in practice.</td>
</tr>
<tr>
<td>02</td>
<td><a href="/split-brain-when-two-nodes-both-think-theyre-the-leader">Split-Brain: When Two Nodes Both Think They're the Leader</a></td>
<td>Split-brain occurs when two nodes both believe they're the primary. Learn how it happens, why it causes data corruption, and how STONITH and fencing prevent it.</td>
</tr>
<tr>
<td>03</td>
<td><a href="/heartbeats-how-nodes-know-their-peers-are-alive">Heartbeats: How Nodes Know Their Peers Are Alive</a></td>
<td>Heartbeats let nodes detect peer failures. Learn how timeouts, phi accrual failure detectors, and the tradeoff between false positives and detection speed work.</td>
</tr>
<tr>
<td>04</td>
<td><a href="/leader-election-agreeing-on-whos-in-charge">Leader Election: Agreeing on Who's in Charge</a></td>
<td>Leader election coordinates which node acts as primary. Learn the bully algorithm, Raft-based election, and why exactly-one-leader guarantees are hard to achieve.</td>
</tr>
<tr>
<td>05</td>
<td><a href="/consensus-algorithms-agreeing-on-a-value-across-failures">Consensus Algorithms: Agreeing on a Value Across Failures</a></td>
<td>Consensus lets distributed nodes agree on a value despite failures. Learn what FLP impossibility means, what Paxos and Raft provide, and where consensus is used.</td>
</tr>
<tr>
<td>06</td>
<td><a href="/quorum-how-many-nodes-must-agree">Quorum: How Many Nodes Must Agree?</a></td>
<td>Quorum determines how many nodes must agree for an operation to succeed. Learn how R + W &gt; N ensures consistency in distributed databases like Cassandra and DynamoDB.</td>
</tr>
<tr>
<td>07</td>
<td><a href="/paxos-the-algorithm-that-started-it-all">Paxos: The Algorithm That Started It All</a></td>
<td>Paxos is the foundational distributed consensus algorithm. Learn how its two phases work, why it's hard to implement, and what systems use it in production.</td>
</tr>
<tr>
<td>08</td>
<td><a href="/raft-consensus-made-understandable">Raft: Consensus Made Understandable</a></td>
<td>Raft makes distributed consensus understandable. Learn how leader election, log replication, and safety work in the algorithm that powers etcd, CockroachDB, and TiKV.</td>
</tr>
<tr>
<td>09</td>
<td><a href="/gossip-protocol-decentralised-cluster-communication">Gossip Protocol: Decentralised Cluster Communication</a></td>
<td>Gossip protocols propagate information across a cluster without a central coordinator. Learn how epidemic spreading works and where it's used in production.</td>
</tr>
<tr>
<td>10</td>
<td><a href="/logical-clocks-when-physical-time-isnt-enough">Logical Clocks: When Physical Time Isn't Enough</a></td>
<td>Physical clocks drift and can't establish event order in distributed systems. Logical clocks track causality instead. Learn why this matters and how it works.</td>
</tr>
<tr>
<td>11</td>
<td><a href="/lamport-timestamps-ordering-events-without-a-global-clock">Lamport Timestamps: Ordering Events Without a Global Clock</a></td>
<td>Lamport timestamps assign logical counters to events to establish causal order in distributed systems. Learn how they work and what they can and can't tell you.</td>
</tr>
<tr>
<td>12</td>
<td><a href="/vector-clocks-knowing-when-events-are-truly-concurrent">Vector Clocks: Knowing When Events Are Truly Concurrent</a></td>
<td>Vector clocks detect causality and concurrency in distributed systems. Learn how they work, how Dynamo uses them for conflict detection, and their limitations.</td>
</tr>
<tr>
<td>13</td>
<td><a href="/distributed-transactions-when-one-machine-isnt-enough">Distributed Transactions: When One Machine Isn't Enough</a></td>
<td>Distributed transactions are hard. Learn why cross-service atomicity is expensive, when to use it, and when eventual consistency is the right alternative.</td>
</tr>
<tr>
<td>14</td>
<td><a href="/two-phase-commit-coordinating-a-distributed-decision">Two-Phase Commit: Coordinating a Distributed Decision</a></td>
<td>2PC ensures distributed atomicity through prepare and commit phases. Learn how it works, the coordinator failure problem, and why it's rarely used in modern systems.</td>
</tr>
<tr>
<td>15</td>
<td><a href="/three-phase-commit-solving-2pcs-blocking-problem">Three-Phase Commit: Solving 2PC's Blocking Problem</a></td>
<td>3PC adds a pre-commit phase to eliminate 2PC's blocking problem. Learn how it works, what assumptions it requires, and why it's rarely used in production.</td>
</tr>
<tr>
<td>16</td>
<td><a href="/delivery-semantics-what-does-delivered-actually-mean">Delivery Semantics: What Does "Delivered" Actually Mean?</a></td>
<td>Message delivery guarantees define system reliability. Learn what at-most-once, at-least-once, and exactly-once mean, what they cost, and when each is appropriate.</td>
</tr>
<tr>
<td>17</td>
<td><a href="/change-data-capture-streaming-your-database-in-real-time">Change Data Capture: Streaming Your Database in Real Time</a></td>
<td>CDC streams database changes in real time by reading the write-ahead log. Learn how Debezium works, what CDC enables, and when to use it.</td>
</tr>
<tr>
<td>18</td>
<td><strong>Erasure Coding: Fault Tolerance Without Full Replication</strong> ← you are here</td>
<td>Erasure coding stores data across nodes using math, not full replication. Learn how Reed-Solomon works, how S3 uses it, and when it beats 3x replication.</td>
</tr>
<tr>
<td>19</td>
<td><a href="/merkle-trees-efficiently-finding-whats-different">Merkle Trees: Efficiently Finding What's Different</a></td>
<td>Merkle trees efficiently detect which parts of a large dataset differ between nodes. Learn how Bitcoin, Cassandra, and Git use them for verification and anti-entropy.</td>
</tr>
<tr>
<td>20</td>
<td><a href="/observability-understanding-your-system-at-runtime">Observability: Understanding Your System at Runtime</a></td>
<td>Logs, metrics, and distributed traces are how you understand a system at runtime. Learn what each pillar provides, the tools involved, and how they work together.</td>
</tr>
<tr>
<td>21</td>
<td><a href="/distributed-systems-wrap-up">Distributed Systems: Wrap-Up</a></td>
<td>A recap of all 20 distributed systems concepts and the complete URL shortener architecture spanning all 8 pillars. The final post in the series.</td>
</tr>
</tbody></table>
<hr />
<h1>Erasure Coding: Fault Tolerance Without Full Replication</h1>
<h2>The problem</h2>
<p>Amazon S3 stores every object with eleven nines (99.999999999%) durability — the probability of losing an object is essentially zero. If S3 achieved this through 3× replication (three full copies of every object), storing 1 PB of data would require 3 PB of raw storage. At S3's scale (hundreds of exabytes), this is an enormous storage overhead.</p>
<p>Is there a way to achieve the same durability guarantee with less storage overhead?</p>
<p>Yes: erasure coding.</p>
<hr />
<h2>The core idea</h2>
<p>Erasure coding divides data into k data chunks, encodes them into n total chunks (n &gt; k) using a mathematical transformation, and distributes the n chunks across n nodes. Any k of the n chunks are sufficient to reconstruct the original data. The system can tolerate losing up to n − k chunks (nodes) without data loss.</p>
<p>The overhead: n/k instead of a full replication factor. A common configuration is 10+4 (k=10, n=14): the original data is encoded into 14 chunks; any 10 are sufficient for recovery; 4 nodes can fail without data loss. Storage overhead: 14/10 = 1.4× — versus 3× replication for equivalent fault tolerance.</p>
<hr />
<h2>The analogy: a torn photograph reconstructed from fragments</h2>
<p>A photograph is cut into 14 pieces and distributed to 14 people. The rule: any 10 of the 14 pieces are sufficient to reconstruct the complete photograph. Even if 4 people lose their pieces, the photograph can still be recovered from the remaining 10.</p>
<p>The encoding adds some redundancy (14 pieces instead of 10 direct copies), but far less redundancy than keeping 3 complete photographs.</p>
<hr />
<h2>How erasure coding works (interactive diagram)</h2>
<div class="hn-embed-widget" id="erasure-coding-encode-widget"></div>

<h3>Reed-Solomon codes</h3>
<p>The most common erasure coding scheme. The original data is treated as a polynomial; the k data chunks are the polynomial's coefficients. The n total chunks are evaluations of the polynomial at n distinct points. Any k evaluations are sufficient to recover the original polynomial (and thus the data) through polynomial interpolation.</p>
<pre><code class="language-plaintext">Original data: 10 chunks of 100 MB each = 1 GB

Encoding (10+4 Reed-Solomon):
  Compute 4 additional "parity" chunks using polynomial math
  Result: 14 chunks × 100 MB = 1.4 GB stored (1.4× overhead)
  
  Any 10 of 14 chunks reconstruct the original
  System tolerates loss of any 4 chunks (nodes)
  
vs 3× replication:
  3 complete copies × 1 GB = 3 GB stored (3× overhead)
  Tolerates loss of any 2 copies
</code></pre>
<h3>The reconstruction process (interactive diagram)</h3>
<div class="hn-embed-widget" id="erasure-coding-recovery-widget"></div>

<p>If a node fails and its chunk is lost, the system must reconstruct it:</p>
<ol>
<li><p>Read any k surviving chunks</p>
</li>
<li><p>Apply the inverse Reed-Solomon transform (polynomial interpolation)</p>
</li>
<li><p>Recover the original data</p>
</li>
<li><p>Re-encode the missing chunk</p>
</li>
<li><p>Write the recovered chunk to a replacement node</p>
</li>
</ol>
<p>This is more computationally expensive than simply copying a replica — reconstruction requires reading k chunks and computing the inverse transform. For large objects, reconstruction is I/O and CPU intensive.</p>
<hr />
<h2>Where erasure coding is used</h2>
<p><strong>Amazon S3:</strong> uses erasure coding internally (specific scheme not disclosed). Objects are split across multiple storage nodes; the system can recover from multiple simultaneous node failures.</p>
<p><strong>HDFS (Hadoop):</strong> HDFS 3.x supports erasure coding via EC policies. Common configuration: 6+3 (6 data blocks, 3 parity blocks). For cold data that's rarely accessed, erasure coding reduces storage from 3× to 1.5× while maintaining the same fault tolerance.</p>
<p><strong>Ceph:</strong> supports erasure-coded pools alongside replicated pools. Cold data goes to EC pools for storage efficiency.</p>
<p><strong>Meta's Tectonic:</strong> Meta's internal distributed filesystem uses erasure coding for the vast majority of cold data storage.</p>
<p><strong>RAID 5/6 (local disks):</strong> the familiar RAID scheme is erasure coding: RAID 5 is k+1 (one parity disk), RAID 6 is k+2 (two parity disks).</p>
<hr />
<h2>Tradeoffs</h2>
<div class="hn-embed-widget" id="erasure-coding-vs-replication-widget"></div>

<p><strong>Storage efficiency vs recovery cost.</strong> Erasure coding is more storage-efficient than replication. The cost: recovery requires reading k chunks (more I/O than copying one replica) and computing the inverse transform (more CPU). For hot data accessed frequently, the reconstruction cost makes erasure coding impractical.</p>
<p><strong>Write overhead.</strong> Writing a new object requires computing all n chunks (encoding), not just writing k copies. Encoding is fast (Reed-Solomon is a well-optimised operation), but it's more work than a simple replicate-and-write.</p>
<p><strong>Latency.</strong> Reading an erasure-coded object requires reading from k nodes simultaneously. Network round-trips to k nodes add latency compared to reading from the nearest replica.</p>
<p><strong>Best for cold/archive data.</strong> Erasure coding's efficiency advantage is most valuable for large, infrequently accessed datasets (backups, logs, cold storage). For frequently accessed hot data, replication's simpler read path (read from nearest replica, no reconstruction) usually wins.</p>
<hr />
<h2>The one thing to remember</h2>
<blockquote>
<p><strong>Erasure coding achieves fault tolerance with less storage overhead than replication by splitting data into k data chunks and n−k parity chunks, such that any k of the n total chunks reconstruct the original.</strong> A 10+4 configuration tolerates 4 node failures with only 40% storage overhead — versus 200% overhead for 3× replication. The cost is more complex reads and writes, and expensive reconstruction when chunks are lost. Erasure coding is the right choice for large, cold datasets where storage cost matters more than read performance.</p>
</blockquote>
<hr />
<p><em>← Previous:</em> <a href="/change-data-capture-streaming-your-database-in-real-time"><em><strong>Change Data Capture</strong></em></a> <em>— streaming database changes in real time by reading the write-ahead log.</em></p>
<p><em>→ Next:</em> <a href="/merkle-trees-efficiently-finding-whats-different"><em><strong>Merkle Trees</strong></em></a> <em>— efficiently comparing large datasets across distributed nodes to find which parts have diverged.</em></p>
]]></content:encoded></item><item><title><![CDATA[Change Data Capture: Streaming Your Database in Real Time]]></title><description><![CDATA[Series: System Design · Distributed Systems — Pillar 8 of 8

Systems Design



#
Post
What it covers



00
Distributed Systems: What Happens When Machines Disagree
Twenty concepts covering network par]]></description><link>https://cloudtuned.dev/change-data-capture-streaming-your-database-in-real-time</link><guid isPermaLink="true">https://cloudtuned.dev/change-data-capture-streaming-your-database-in-real-time</guid><category><![CDATA[systemdesign]]></category><category><![CDATA[distributedsystems]]></category><category><![CDATA[cdc]]></category><category><![CDATA[debezium]]></category><category><![CDATA[kafka]]></category><category><![CDATA[backend]]></category><category><![CDATA[SoftwareDevelopment]]></category><category><![CDATA[softwarearchitecture]]></category><category><![CDATA[engineering]]></category><dc:creator><![CDATA[Cloud Tuned]]></dc:creator><pubDate>Mon, 10 Mar 2025 12:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/602bee9a4bb9c4083f02795d/24a9ac1d-62ac-46ba-b4f6-b373e74ba392.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote>
<p><strong>Series:</strong> System Design · Distributed Systems — Pillar 8 of 8</p>
</blockquote>
<h2>Systems Design</h2>
<table>
<thead>
<tr>
<th>#</th>
<th>Post</th>
<th>What it covers</th>
</tr>
</thead>
<tbody><tr>
<td>00</td>
<td><a href="/distributed-systems-what-happens-when-machines-disagree">Distributed Systems: What Happens When Machines Disagree</a></td>
<td>Twenty concepts covering network partitions, consensus, clocks, distributed transactions, CDC, erasure coding, and observability. The final pillar.</td>
</tr>
<tr>
<td>01</td>
<td><a href="/network-partitions-the-failure-mode-you-cant-design-away">Network Partitions: The Failure Mode You Can't Design Away</a></td>
<td>Network partitions are inevitable. Learn what happens when nodes can't communicate, how systems choose between availability and consistency, and what that means in practice.</td>
</tr>
<tr>
<td>02</td>
<td><a href="/split-brain-when-two-nodes-both-think-theyre-the-leader">Split-Brain: When Two Nodes Both Think They're the Leader</a></td>
<td>Split-brain occurs when two nodes both believe they're the primary. Learn how it happens, why it causes data corruption, and how STONITH and fencing prevent it.</td>
</tr>
<tr>
<td>03</td>
<td><a href="/heartbeats-how-nodes-know-their-peers-are-alive">Heartbeats: How Nodes Know Their Peers Are Alive</a></td>
<td>Heartbeats let nodes detect peer failures. Learn how timeouts, phi accrual failure detectors, and the tradeoff between false positives and detection speed work.</td>
</tr>
<tr>
<td>04</td>
<td><a href="/leader-election-agreeing-on-whos-in-charge">Leader Election: Agreeing on Who's in Charge</a></td>
<td>Leader election coordinates which node acts as primary. Learn the bully algorithm, Raft-based election, and why exactly-one-leader guarantees are hard to achieve.</td>
</tr>
<tr>
<td>05</td>
<td><a href="/consensus-algorithms-agreeing-on-a-value-across-failures">Consensus Algorithms: Agreeing on a Value Across Failures</a></td>
<td>Consensus lets distributed nodes agree on a value despite failures. Learn what FLP impossibility means, what Paxos and Raft provide, and where consensus is used.</td>
</tr>
<tr>
<td>06</td>
<td><a href="/quorum-how-many-nodes-must-agree">Quorum: How Many Nodes Must Agree?</a></td>
<td>Quorum determines how many nodes must agree for an operation to succeed. Learn how R + W &gt; N ensures consistency in distributed databases like Cassandra and DynamoDB.</td>
</tr>
<tr>
<td>07</td>
<td><a href="/paxos-the-algorithm-that-started-it-all">Paxos: The Algorithm That Started It All</a></td>
<td>Paxos is the foundational distributed consensus algorithm. Learn how its two phases work, why it's hard to implement, and what systems use it in production.</td>
</tr>
<tr>
<td>08</td>
<td><a href="/raft-consensus-made-understandable">Raft: Consensus Made Understandable</a></td>
<td>Raft makes distributed consensus understandable. Learn how leader election, log replication, and safety work in the algorithm that powers etcd, CockroachDB, and TiKV.</td>
</tr>
<tr>
<td>09</td>
<td><a href="/gossip-protocol-decentralised-cluster-communication">Gossip Protocol: Decentralised Cluster Communication</a></td>
<td>Gossip protocols propagate information across a cluster without a central coordinator. Learn how epidemic spreading works and where it's used in production.</td>
</tr>
<tr>
<td>10</td>
<td><a href="/logical-clocks-when-physical-time-isnt-enough">Logical Clocks: When Physical Time Isn't Enough</a></td>
<td>Physical clocks drift and can't establish event order in distributed systems. Logical clocks track causality instead. Learn why this matters and how it works.</td>
</tr>
<tr>
<td>11</td>
<td><a href="/lamport-timestamps-ordering-events-without-a-global-clock">Lamport Timestamps: Ordering Events Without a Global Clock</a></td>
<td>Lamport timestamps assign logical counters to events to establish causal order in distributed systems. Learn how they work and what they can and can't tell you.</td>
</tr>
<tr>
<td>12</td>
<td><a href="/vector-clocks-knowing-when-events-are-truly-concurrent">Vector Clocks: Knowing When Events Are Truly Concurrent</a></td>
<td>Vector clocks detect causality and concurrency in distributed systems. Learn how they work, how Dynamo uses them for conflict detection, and their limitations.</td>
</tr>
<tr>
<td>13</td>
<td><a href="/distributed-transactions-when-one-machine-isnt-enough">Distributed Transactions: When One Machine Isn't Enough</a></td>
<td>Distributed transactions are hard. Learn why cross-service atomicity is expensive, when to use it, and when eventual consistency is the right alternative.</td>
</tr>
<tr>
<td>14</td>
<td><a href="/two-phase-commit-coordinating-a-distributed-decision">Two-Phase Commit: Coordinating a Distributed Decision</a></td>
<td>2PC ensures distributed atomicity through prepare and commit phases. Learn how it works, the coordinator failure problem, and why it's rarely used in modern systems.</td>
</tr>
<tr>
<td>15</td>
<td><a href="/three-phase-commit-solving-2pcs-blocking-problem">Three-Phase Commit: Solving 2PC's Blocking Problem</a></td>
<td>3PC adds a pre-commit phase to eliminate 2PC's blocking problem. Learn how it works, what assumptions it requires, and why it's rarely used in production.</td>
</tr>
<tr>
<td>16</td>
<td><a href="/delivery-semantics-what-does-delivered-actually-mean">Delivery Semantics: What Does "Delivered" Actually Mean?</a></td>
<td>Message delivery guarantees define system reliability. Learn what at-most-once, at-least-once, and exactly-once mean, what they cost, and when each is appropriate.</td>
</tr>
<tr>
<td>17</td>
<td><strong>Change Data Capture: Streaming Your Database in Real Time</strong> ← you are here</td>
<td>CDC streams database changes in real time by reading the write-ahead log. Learn how Debezium works, what CDC enables, and when to use it.</td>
</tr>
<tr>
<td>18</td>
<td><a href="/erasure-coding-fault-tolerance-without-full-replication">Erasure Coding: Fault Tolerance Without Full Replication</a></td>
<td>Erasure coding stores data across nodes using math, not full replication. Learn how Reed-Solomon works, how S3 uses it, and when it beats 3x replication.</td>
</tr>
<tr>
<td>19</td>
<td><a href="/merkle-trees-efficiently-finding-whats-different">Merkle Trees: Efficiently Finding What's Different</a></td>
<td>Merkle trees efficiently detect which parts of a large dataset differ between nodes. Learn how Bitcoin, Cassandra, and Git use them for verification and anti-entropy.</td>
</tr>
<tr>
<td>20</td>
<td><a href="/observability-understanding-your-system-at-runtime">Observability: Understanding Your System at Runtime</a></td>
<td>Logs, metrics, and distributed traces are how you understand a system at runtime. Learn what each pillar provides, the tools involved, and how they work together.</td>
</tr>
<tr>
<td>21</td>
<td><a href="/distributed-systems-wrap-up">Distributed Systems: Wrap-Up</a></td>
<td>A recap of all 20 distributed systems concepts and the complete URL shortener architecture spanning all 8 pillars. The final post in the series.</td>
</tr>
</tbody></table>
<hr />
<h1>Change Data Capture: Streaming Your Database in Real Time</h1>
<h2>The problem</h2>
<div class="hn-embed-widget" id="cdc-vs-dual-write-widget"></div>

<p>Your URL shortener's links table in PostgreSQL is the source of truth. Multiple downstream systems need to stay current:</p>
<ul>
<li><p>Elasticsearch must index new and updated links for search</p>
</li>
<li><p>The analytics data warehouse must receive link metadata changes</p>
</li>
<li><p>The Outbox pattern relay must publish events from the outbox table</p>
</li>
<li><p>A Redis cache must be invalidated when link destinations change</p>
</li>
</ul>
<p>The naive approach: the application that writes to PostgreSQL also writes to each downstream system. This is dual-write — we've seen its problems (post 10, Outbox pattern). The write to PostgreSQL and the writes to downstream systems are not atomic; if any downstream write fails, systems diverge.</p>
<p>The better approach: instead of the application writing to multiple places, let the database itself be the single source of truth and stream every change to an event bus. Downstream systems consume from the event bus. This is Change Data Capture. </p>
<hr />
<h2>The core idea</h2>
<p>Change Data Capture (CDC) reads the database's internal change log (the Write-Ahead Log for PostgreSQL, the binary log for MySQL) and streams every INSERT, UPDATE, and DELETE as an event to downstream consumers. The application writes only to the database. The CDC pipeline handles the fan-out.</p>
<hr />
<h2>The analogy: a stenographer recording every decision</h2>
<p>A committee meeting makes decisions verbally. Rather than have the chairperson personally notify every stakeholder, a stenographer records every statement in real time. Stakeholders who need to know about decisions subscribe to the stenographer's transcript.</p>
<p>The committee (application) speaks once. The stenographer (CDC) captures it all. Stakeholders (downstream systems) get the full record without the committee knowing they exist.</p>
<hr />
<h2>How CDC works</h2>
<h3>The Write-Ahead Log (WAL)</h3>
<p>PostgreSQL (and most relational databases) maintain a WAL — a sequential, append-only log of every change committed to the database. The WAL's primary purpose is durability: if the database crashes, it replays the WAL on recovery.</p>
<p>CDC reads the WAL and converts its binary records into structured change events:</p>
<pre><code class="language-plaintext">WAL entry: INSERT into links (id='x7Kp2', dest='https://example.com', user_id=123)
CDC event:
  {
    "op": "c",              // c=create, u=update, d=delete
    "source": {"table": "links", "lsn": 291840},
    "before": null,         // no previous state on insert
    "after": {
      "id": "x7Kp2",
      "dest": "https://example.com",
      "user_id": 123,
      "created_at": "2025-06-01T14:00:00Z"
    }
  }
</code></pre>
<p>For an UPDATE, both <code>before</code> and <code>after</code> are populated. For a DELETE, <code>before</code> is the deleted row, <code>after</code> is null.</p>
<h3>Debezium</h3>
<p>Debezium is the dominant open-source CDC platform. It runs as a Kafka Connect connector: it reads the PostgreSQL WAL (or MySQL binlog, MongoDB oplog, etc.) and publishes change events to Kafka topics.</p>
<pre><code class="language-plaintext">PostgreSQL WAL
  → Debezium PostgreSQL connector (Kafka Connect)
  → Kafka topic: postgres.public.links
  → Consumers:
      Elasticsearch connector (indexes new/changed links)
      Analytics connector (writes to data warehouse)
      Outbox relay connector (publishes Outbox messages)
      Cache invalidation service (deletes Redis keys on change)
</code></pre>
<h3>Logical replication slots (PostgreSQL)</h3>
<p>For CDC to work, PostgreSQL must preserve WAL entries until the CDC consumer has read them. This is done via a <strong>logical replication slot</strong>: a named cursor in the WAL that tracks how far the CDC consumer has read. PostgreSQL retains WAL up to the oldest slot's position.</p>
<pre><code class="language-sql">-- Create a replication slot for Debezium
SELECT pg_create_logical_replication_slot('debezium_slot', 'pgoutput');
</code></pre>
<p><strong>Important:</strong> an unused replication slot causes WAL to accumulate indefinitely — PostgreSQL won't clean it up. A stalled CDC pipeline with a replication slot can fill the database's disk. Monitor replication slot lag.</p>
<hr />
<h2>What CDC enables</h2>
<p><strong>Real-time search index updates.</strong> Instead of a nightly Elasticsearch reindex, every link INSERT or UPDATE propagates to Elasticsearch within seconds. Search results reflect the latest data.</p>
<p><strong>Cache invalidation.</strong> When a link's destination is updated, a CDC consumer deletes the corresponding Redis cache entry. The next redirect hits the database for the fresh value — no TTL wait for stale data.</p>
<p><strong>Event sourcing without application changes.</strong> The database's change log becomes an event stream. Downstream systems can replay from any point in history.</p>
<p><strong>Data warehouse synchronisation.</strong> The ELT pipeline (Pillar 7, post 18) can use CDC for near-real-time data warehouse updates instead of nightly batch ETL jobs.</p>
<p><strong>Outbox pattern relay.</strong> The most reliable Outbox implementation uses CDC: Debezium watches the outbox table and publishes messages to Kafka as rows are inserted. No polling loop, no additional database queries.</p>
<hr />
<h2>Tradeoffs</h2>
<p><strong>WAL format coupling.</strong> Debezium reads the WAL directly. Major schema changes (dropping a column, changing a column type) can break the CDC pipeline if the connector's schema configuration isn't updated simultaneously.</p>
<p><strong>Replication slot lag.</strong> A slow or stalled CDC consumer causes WAL retention to grow. PostgreSQL must keep WAL segments for the stalled consumer, potentially filling disk. Monitor <code>pg_replication_slots</code> and alert on lag.</p>
<p><strong>Ordering and partitioning.</strong> Debezium publishes events in WAL order within a table, but across tables, ordering is not guaranteed. For consumers that depend on cross-table ordering (applying a parent row insert before a child row insert), careful partitioning of Kafka topics is required.</p>
<p><strong>Not for all databases.</strong> CDC via WAL requires the database to support logical replication (PostgreSQL 10+, MySQL 5.5+ binlog, MongoDB 3.6+ oplog). Older databases or some cloud-managed databases may not expose the WAL for CDC.</p>
<hr />
<h2>The one thing to remember</h2>
<blockquote>
<p><strong>CDC turns your database into an event source by reading its internal change log — the WAL — and streaming every commit as a structured event.</strong> The application writes only to the database; CDC handles fan-out to all downstream consumers (search, cache, analytics, other services). This solves the dual-write problem: the database write and the downstream event are guaranteed to be consistent because the event is derived from the already-committed WAL, not written separately. Debezium is the standard tool for this in PostgreSQL/MySQL/MongoDB environments.</p>
</blockquote>
<hr />
<p><em>← Previous:</em> <a href="/delivery-semantics-what-does-delivered-actually-mean"><em><strong>Delivery Semantics</strong></em></a> <em>— at-most-once, at-least-once, and exactly-once: what each guarantees and what it costs.</em></p>
<p><em>→ Next:</em> <a href="/erasure-coding-fault-tolerance-without-full-replication"><em><strong>Erasure Coding</strong></em></a> <em>— storing data redundantly using mathematics rather than full replication.</em></p>
]]></content:encoded></item><item><title><![CDATA[Delivery Semantics: What Does \"Delivered\" Actually Mean?]]></title><description><![CDATA[Series: System Design · Distributed Systems — Pillar 8 of 8

Systems Design



#
Post
What it covers



00
Distributed Systems: What Happens When Machines Disagree
Twenty concepts covering network par]]></description><link>https://cloudtuned.dev/delivery-semantics-what-does-delivered-actually-mean</link><guid isPermaLink="true">https://cloudtuned.dev/delivery-semantics-what-does-delivered-actually-mean</guid><category><![CDATA[systemdesign]]></category><category><![CDATA[distributedsystems]]></category><category><![CDATA[deliverysemantics]]></category><category><![CDATA[idempotency]]></category><category><![CDATA[kafka]]></category><category><![CDATA[backend]]></category><category><![CDATA[SoftwareDevelopment]]></category><category><![CDATA[softwarearchitecture]]></category><category><![CDATA[engineering]]></category><dc:creator><![CDATA[Cloud Tuned]]></dc:creator><pubDate>Sun, 09 Mar 2025 12:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/602bee9a4bb9c4083f02795d/00d865e9-8395-42f9-8c4d-3afa36138d05.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote>
<p><strong>Series:</strong> System Design · Distributed Systems — Pillar 8 of 8</p>
</blockquote>
<h2>Systems Design</h2>
<table>
<thead>
<tr>
<th>#</th>
<th>Post</th>
<th>What it covers</th>
</tr>
</thead>
<tbody><tr>
<td>00</td>
<td><a href="/distributed-systems-what-happens-when-machines-disagree">Distributed Systems: What Happens When Machines Disagree</a></td>
<td>Twenty concepts covering network partitions, consensus, clocks, distributed transactions, CDC, erasure coding, and observability. The final pillar.</td>
</tr>
<tr>
<td>01</td>
<td><a href="/network-partitions-the-failure-mode-you-cant-design-away">Network Partitions: The Failure Mode You Can't Design Away</a></td>
<td>Network partitions are inevitable. Learn what happens when nodes can't communicate, how systems choose between availability and consistency, and what that means in practice.</td>
</tr>
<tr>
<td>02</td>
<td><a href="/split-brain-when-two-nodes-both-think-theyre-the-leader">Split-Brain: When Two Nodes Both Think They're the Leader</a></td>
<td>Split-brain occurs when two nodes both believe they're the primary. Learn how it happens, why it causes data corruption, and how STONITH and fencing prevent it.</td>
</tr>
<tr>
<td>03</td>
<td><a href="/heartbeats-how-nodes-know-their-peers-are-alive">Heartbeats: How Nodes Know Their Peers Are Alive</a></td>
<td>Heartbeats let nodes detect peer failures. Learn how timeouts, phi accrual failure detectors, and the tradeoff between false positives and detection speed work.</td>
</tr>
<tr>
<td>04</td>
<td><a href="/leader-election-agreeing-on-whos-in-charge">Leader Election: Agreeing on Who's in Charge</a></td>
<td>Leader election coordinates which node acts as primary. Learn the bully algorithm, Raft-based election, and why exactly-one-leader guarantees are hard to achieve.</td>
</tr>
<tr>
<td>05</td>
<td><a href="/consensus-algorithms-agreeing-on-a-value-across-failures">Consensus Algorithms: Agreeing on a Value Across Failures</a></td>
<td>Consensus lets distributed nodes agree on a value despite failures. Learn what FLP impossibility means, what Paxos and Raft provide, and where consensus is used.</td>
</tr>
<tr>
<td>06</td>
<td><a href="/quorum-how-many-nodes-must-agree">Quorum: How Many Nodes Must Agree?</a></td>
<td>Quorum determines how many nodes must agree for an operation to succeed. Learn how R + W &gt; N ensures consistency in distributed databases like Cassandra and DynamoDB.</td>
</tr>
<tr>
<td>07</td>
<td><a href="/paxos-the-algorithm-that-started-it-all">Paxos: The Algorithm That Started It All</a></td>
<td>Paxos is the foundational distributed consensus algorithm. Learn how its two phases work, why it's hard to implement, and what systems use it in production.</td>
</tr>
<tr>
<td>08</td>
<td><a href="/raft-consensus-made-understandable">Raft: Consensus Made Understandable</a></td>
<td>Raft makes distributed consensus understandable. Learn how leader election, log replication, and safety work in the algorithm that powers etcd, CockroachDB, and TiKV.</td>
</tr>
<tr>
<td>09</td>
<td><a href="/gossip-protocol-decentralised-cluster-communication">Gossip Protocol: Decentralised Cluster Communication</a></td>
<td>Gossip protocols propagate information across a cluster without a central coordinator. Learn how epidemic spreading works and where it's used in production.</td>
</tr>
<tr>
<td>10</td>
<td><a href="/logical-clocks-when-physical-time-isnt-enough">Logical Clocks: When Physical Time Isn't Enough</a></td>
<td>Physical clocks drift and can't establish event order in distributed systems. Logical clocks track causality instead. Learn why this matters and how it works.</td>
</tr>
<tr>
<td>11</td>
<td><a href="/lamport-timestamps-ordering-events-without-a-global-clock">Lamport Timestamps: Ordering Events Without a Global Clock</a></td>
<td>Lamport timestamps assign logical counters to events to establish causal order in distributed systems. Learn how they work and what they can and can't tell you.</td>
</tr>
<tr>
<td>12</td>
<td><a href="/vector-clocks-knowing-when-events-are-truly-concurrent">Vector Clocks: Knowing When Events Are Truly Concurrent</a></td>
<td>Vector clocks detect causality and concurrency in distributed systems. Learn how they work, how Dynamo uses them for conflict detection, and their limitations.</td>
</tr>
<tr>
<td>13</td>
<td><a href="/distributed-transactions-when-one-machine-isnt-enough">Distributed Transactions: When One Machine Isn't Enough</a></td>
<td>Distributed transactions are hard. Learn why cross-service atomicity is expensive, when to use it, and when eventual consistency is the right alternative.</td>
</tr>
<tr>
<td>14</td>
<td><a href="/two-phase-commit-coordinating-a-distributed-decision">Two-Phase Commit: Coordinating a Distributed Decision</a></td>
<td>2PC ensures distributed atomicity through prepare and commit phases. Learn how it works, the coordinator failure problem, and why it's rarely used in modern systems.</td>
</tr>
<tr>
<td>15</td>
<td><a href="/three-phase-commit-solving-2pcs-blocking-problem">Three-Phase Commit: Solving 2PC's Blocking Problem</a></td>
<td>3PC adds a pre-commit phase to eliminate 2PC's blocking problem. Learn how it works, what assumptions it requires, and why it's rarely used in production.</td>
</tr>
<tr>
<td>16</td>
<td><strong>Delivery Semantics: What Does "Delivered" Actually Mean?</strong> ← you are here</td>
<td>Message delivery guarantees define system reliability. Learn what at-most-once, at-least-once, and exactly-once mean, what they cost, and when each is appropriate.</td>
</tr>
<tr>
<td>17</td>
<td><a href="/change-data-capture-streaming-your-database-in-real-time">Change Data Capture: Streaming Your Database in Real Time</a></td>
<td>CDC streams database changes in real time by reading the write-ahead log. Learn how Debezium works, what CDC enables, and when to use it.</td>
</tr>
<tr>
<td>18</td>
<td><a href="/erasure-coding-fault-tolerance-without-full-replication">Erasure Coding: Fault Tolerance Without Full Replication</a></td>
<td>Erasure coding stores data across nodes using math, not full replication. Learn how Reed-Solomon works, how S3 uses it, and when it beats 3x replication.</td>
</tr>
<tr>
<td>19</td>
<td><a href="/merkle-trees-efficiently-finding-whats-different">Merkle Trees: Efficiently Finding What's Different</a></td>
<td>Merkle trees efficiently detect which parts of a large dataset differ between nodes. Learn how Bitcoin, Cassandra, and Git use them for verification and anti-entropy.</td>
</tr>
<tr>
<td>20</td>
<td><a href="/observability-understanding-your-system-at-runtime">Observability: Understanding Your System at Runtime</a></td>
<td>Logs, metrics, and distributed traces are how you understand a system at runtime. Learn what each pillar provides, the tools involved, and how they work together.</td>
</tr>
<tr>
<td>21</td>
<td><a href="/distributed-systems-wrap-up">Distributed Systems: Wrap-Up</a></td>
<td>A recap of all 20 distributed systems concepts and the complete URL shortener architecture spanning all 8 pillars. The final post in the series.</td>
</tr>
</tbody></table>
<hr />
<h1>Delivery Semantics: What Does "Delivered" Actually Mean?</h1>
<h2>The problem</h2>
<p>Your URL shortener's click pipeline publishes events to Kafka. The analytics consumer processes each event and increments a counter. What guarantees does the system provide?</p>
<p>If the consumer crashes after processing an event but before committing its Kafka offset, Kafka will re-deliver the event on restart. The counter gets incremented twice for one click — double-counting.</p>
<p>If the consumer commits its offset before processing, and then crashes during processing, the event is marked consumed but was never processed — the counter was never incremented. The click is lost.</p>
<p>Both outcomes are wrong. The question is: which wrongness are you willing to accept, and what does it cost to avoid it?</p>
<hr />
<h2>The core idea</h2>
<p>Delivery semantics describe what a messaging system guarantees about how many times a message is delivered to a consumer: at most once (possibly zero), at least once (possibly more than once), or exactly once (exactly one). Each guarantee reflects a different tradeoff between performance, reliability, and implementation complexity.</p>
<hr />
<h2>The analogy: postal delivery policies</h2>
<p><strong>At-most-once:</strong> the postal service attempts delivery once. If no one is home, the letter is discarded — no second attempt. You might not get the letter (under-delivery), but you'll never get the same letter twice.</p>
<p><strong>At-least-once:</strong> the postal service attempts delivery and tries again if unconfirmed. You will eventually receive the letter — possibly multiple copies if the first delivery wasn't confirmed but was received.</p>
<p><strong>Exactly-once:</strong> the postal service guarantees you receive the letter exactly once. This requires tracking every delivery, detecting duplicates, and deduplicating before handing you the envelope. Much more work for the postal service.</p>
<hr />
<h2>At-Most-Once</h2>
<p>A message is delivered zero or one times. If something fails, the message may be lost — but will never be processed twice.</p>
<p><strong>How:</strong> the producer sends a message and doesn't retry on failure. The consumer acknowledges before processing — if it crashes after acknowledging but before processing, the message is gone.</p>
<pre><code>Producer → sends event → does not retry on failure
Consumer → acks message → processes event
         ↑
         Ack before processing: if crash here, message lost
</code></pre>
<p><strong>Use cases:</strong> metrics, telemetry, non-critical logs. Losing an occasional event is acceptable; duplicate processing would corrupt aggregates.</p>
<p><strong>Cost:</strong> possible message loss.</p>
<hr />
<h2>At-Least-Once</h2>
<p>A message is delivered one or more times. The consumer will process every message, but may process some more than once.</p>
<p><strong>How:</strong> the producer retries until the broker acknowledges. The consumer processes before acknowledging — if it crashes after processing but before acknowledging, the message is re-delivered and re-processed.</p>
<pre><code>Producer → sends event
  → timeout → retry (message sent again)
  → broker acks → stop retrying

Consumer → processes event
         → acks message
         ↑
         If crash here, message is re-delivered and re-processed
</code></pre>
<p><strong>The idempotency requirement:</strong> if a consumer might process the same message twice, it must be <strong>idempotent</strong> — processing the same message twice produces the same result as processing it once.</p>
<pre><code class="language-python"># Non-idempotent (wrong for at-least-once):
def process_click(event):
    db.execute("UPDATE links SET click_count = click_count + 1 WHERE id = ?", event.link_id)
    # If this runs twice: click_count is incremented twice

# Idempotent (correct):
def process_click(event):
    db.execute("INSERT INTO click_events (id, link_id, ...) VALUES (?, ?, ...)",
               event.id, event.link_id, ...)
    # If event.id already exists (UNIQUE constraint): ignore duplicate silently
</code></pre>
<p><strong>Use cases:</strong> most event-driven workloads. The most common production choice.</p>
<p><strong>Cost:</strong> consumers must be idempotent; some events are processed more than once (but with idempotency, the end result is correct).</p>
<hr />
<h2>Exactly-Once</h2>
<p>A message is delivered exactly once — no loss, no duplicates. The hardest guarantee.</p>
<p><strong>The problem:</strong> "exactly once" in the context of distributed systems requires coordinating the producer, broker, and consumer atomically. The consumer must atomically: process the event AND mark it as consumed — such that if either step fails, both are retried or rolled back together.</p>
<p><strong>Kafka's exactly-once implementation:</strong></p>
<p>Kafka 0.11+ provides exactly-once semantics within a Kafka-to-Kafka workflow:</p>
<ol>
<li><p><strong>Idempotent producer:</strong> each producer has a unique ID and sequence number per partition. Kafka deduplicates retried produces — the same sequence number from the same producer is committed only once.</p>
</li>
<li><p><strong>Transactional API:</strong> a consumer reads from topic A, processes the event, and writes results to topic B — atomically, within a Kafka transaction. Either all three steps succeed (consume + process + produce) or none do.</p>
</li>
</ol>
<pre><code class="language-python">producer.init_transactions()
try:
    producer.begin_transaction()
    for record in consumer.poll():
        result = process(record)
        producer.send("output-topic", result)
    producer.send_offsets_to_transaction(consumer.offsets, group_id)
    producer.commit_transaction()
except Exception:
    producer.abort_transaction()
</code></pre>
<p><strong>Kafka exactly-once is only within Kafka.</strong> If the consumer writes to a database (not another Kafka topic), exactly-once requires the database write and Kafka offset commit to be in the same transaction — which requires 2PC across Kafka and the database. This is either unsupported or impractical.</p>
<p><strong>The practical approach for Kafka → Database:</strong> use at-least-once delivery with idempotent writes to the database (deduplication by event ID). The result is semantically exactly-once at the application level, without Kafka's transactional complexity.</p>
<hr />
<h2>Choosing delivery semantics</h2>
<pre><code>Can you tolerate message loss?
  Yes → At-most-once (fastest, simplest)

Can your consumers be idempotent?
  Yes → At-least-once with idempotent consumers (most common, practical)
  No → Must work toward exactly-once or idempotent redesign

Are all your writes Kafka-to-Kafka?
  Yes → Kafka exactly-once transactions
  No → At-least-once + idempotent writes to database
</code></pre>
<hr />
<h2>Tradeoffs</h2>
<p><strong>At-most-once:</strong> lowest latency and overhead. Wrong for any workload where losing events matters.</p>
<p><strong>At-least-once:</strong> the practical default. Requires idempotent consumers — which is a good design principle regardless. Doubles some processing; correctly designed systems are unaffected.</p>
<p><strong>Exactly-once:</strong> the highest overhead and complexity. Truly necessary only when the consumer cannot be made idempotent and duplicate processing has visible effects. Often "exactly-once at the application level through idempotency" is a better approach.</p>
<hr />
<h2>The one thing to remember</h2>
<blockquote>
<p><strong>At-least-once delivery with idempotent consumers is the practical choice for almost all event-driven systems.</strong> Accept that messages will occasionally be delivered more than once; design consumers to handle duplicates gracefully (by event ID deduplication, INSERT OR IGNORE, or natural idempotency). Exactly-once is achievable within Kafka-to-Kafka pipelines but not across systems — for cross-system exactly-once semantics, idempotency at the application level is almost always the simpler and more robust approach.</p>
</blockquote>
<hr />
<p><em>← Previous: <strong><a href="/three-phase-commit-solving-2pcs-blocking-problem">Three-Phase Commit</a></strong> — the protocol designed to eliminate 2PC's blocking problem, and why it's rarely used in practice despite solving it.</em></p>
<p><em>→ Next: <strong><a href="/change-data-capture-streaming-your-database-in-real-time">Change Data Capture</a></strong> — streaming database changes in real time by reading the write-ahead log.</em></p>
]]></content:encoded></item><item><title><![CDATA[Three-Phase Commit: Solving 2PC's Blocking Problem]]></title><description><![CDATA[Series: System Design · Distributed Systems — Pillar 8 of 8

Systems Design



#
Post
What it covers



00
Distributed Systems: What Happens When Machines Disagree
Twenty concepts covering network par]]></description><link>https://cloudtuned.dev/three-phase-commit-solving-2pcs-blocking-problem</link><guid isPermaLink="true">https://cloudtuned.dev/three-phase-commit-solving-2pcs-blocking-problem</guid><category><![CDATA[systemdesign]]></category><category><![CDATA[distributedsystems]]></category><category><![CDATA[threephasecommit]]></category><category><![CDATA[3PC ]]></category><category><![CDATA[transactions]]></category><category><![CDATA[backend]]></category><category><![CDATA[SoftwareDevelopment]]></category><category><![CDATA[softwarearchitecture]]></category><category><![CDATA[engineering]]></category><dc:creator><![CDATA[Cloud Tuned]]></dc:creator><pubDate>Sat, 08 Mar 2025 12:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/602bee9a4bb9c4083f02795d/5796ea5a-7aa1-4b41-abd8-32876302f60b.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote>
<p><strong>Series:</strong> System Design · Distributed Systems — Pillar 8 of 8</p>
</blockquote>
<h2>Systems Design</h2>
<table>
<thead>
<tr>
<th>#</th>
<th>Post</th>
<th>What it covers</th>
</tr>
</thead>
<tbody><tr>
<td>00</td>
<td><a href="/distributed-systems-what-happens-when-machines-disagree">Distributed Systems: What Happens When Machines Disagree</a></td>
<td>Twenty concepts covering network partitions, consensus, clocks, distributed transactions, CDC, erasure coding, and observability. The final pillar.</td>
</tr>
<tr>
<td>01</td>
<td><a href="/network-partitions-the-failure-mode-you-cant-design-away">Network Partitions: The Failure Mode You Can't Design Away</a></td>
<td>Network partitions are inevitable. Learn what happens when nodes can't communicate, how systems choose between availability and consistency, and what that means in practice.</td>
</tr>
<tr>
<td>02</td>
<td><a href="/split-brain-when-two-nodes-both-think-theyre-the-leader">Split-Brain: When Two Nodes Both Think They're the Leader</a></td>
<td>Split-brain occurs when two nodes both believe they're the primary. Learn how it happens, why it causes data corruption, and how STONITH and fencing prevent it.</td>
</tr>
<tr>
<td>03</td>
<td><a href="/heartbeats-how-nodes-know-their-peers-are-alive">Heartbeats: How Nodes Know Their Peers Are Alive</a></td>
<td>Heartbeats let nodes detect peer failures. Learn how timeouts, phi accrual failure detectors, and the tradeoff between false positives and detection speed work.</td>
</tr>
<tr>
<td>04</td>
<td><a href="/leader-election-agreeing-on-whos-in-charge">Leader Election: Agreeing on Who's in Charge</a></td>
<td>Leader election coordinates which node acts as primary. Learn the bully algorithm, Raft-based election, and why exactly-one-leader guarantees are hard to achieve.</td>
</tr>
<tr>
<td>05</td>
<td><a href="/consensus-algorithms-agreeing-on-a-value-across-failures">Consensus Algorithms: Agreeing on a Value Across Failures</a></td>
<td>Consensus lets distributed nodes agree on a value despite failures. Learn what FLP impossibility means, what Paxos and Raft provide, and where consensus is used.</td>
</tr>
<tr>
<td>06</td>
<td><a href="/quorum-how-many-nodes-must-agree">Quorum: How Many Nodes Must Agree?</a></td>
<td>Quorum determines how many nodes must agree for an operation to succeed. Learn how R + W &gt; N ensures consistency in distributed databases like Cassandra and DynamoDB.</td>
</tr>
<tr>
<td>07</td>
<td><a href="/paxos-the-algorithm-that-started-it-all">Paxos: The Algorithm That Started It All</a></td>
<td>Paxos is the foundational distributed consensus algorithm. Learn how its two phases work, why it's hard to implement, and what systems use it in production.</td>
</tr>
<tr>
<td>08</td>
<td><a href="/raft-consensus-made-understandable">Raft: Consensus Made Understandable</a></td>
<td>Raft makes distributed consensus understandable. Learn how leader election, log replication, and safety work in the algorithm that powers etcd, CockroachDB, and TiKV.</td>
</tr>
<tr>
<td>09</td>
<td><a href="/gossip-protocol-decentralised-cluster-communication">Gossip Protocol: Decentralised Cluster Communication</a></td>
<td>Gossip protocols propagate information across a cluster without a central coordinator. Learn how epidemic spreading works and where it's used in production.</td>
</tr>
<tr>
<td>10</td>
<td><a href="/logical-clocks-when-physical-time-isnt-enough">Logical Clocks: When Physical Time Isn't Enough</a></td>
<td>Physical clocks drift and can't establish event order in distributed systems. Logical clocks track causality instead. Learn why this matters and how it works.</td>
</tr>
<tr>
<td>11</td>
<td><a href="/lamport-timestamps-ordering-events-without-a-global-clock">Lamport Timestamps: Ordering Events Without a Global Clock</a></td>
<td>Lamport timestamps assign logical counters to events to establish causal order in distributed systems. Learn how they work and what they can and can't tell you.</td>
</tr>
<tr>
<td>12</td>
<td><a href="/vector-clocks-knowing-when-events-are-truly-concurrent">Vector Clocks: Knowing When Events Are Truly Concurrent</a></td>
<td>Vector clocks detect causality and concurrency in distributed systems. Learn how they work, how Dynamo uses them for conflict detection, and their limitations.</td>
</tr>
<tr>
<td>13</td>
<td><a href="/distributed-transactions-when-one-machine-isnt-enough">Distributed Transactions: When One Machine Isn't Enough</a></td>
<td>Distributed transactions are hard. Learn why cross-service atomicity is expensive, when to use it, and when eventual consistency is the right alternative.</td>
</tr>
<tr>
<td>14</td>
<td><a href="/two-phase-commit-coordinating-a-distributed-decision">Two-Phase Commit: Coordinating a Distributed Decision</a></td>
<td>2PC ensures distributed atomicity through prepare and commit phases. Learn how it works, the coordinator failure problem, and why it's rarely used in modern systems.</td>
</tr>
<tr>
<td>15</td>
<td><strong>Three-Phase Commit: Solving 2PC's Blocking Problem</strong> ← you are here</td>
<td>3PC adds a pre-commit phase to eliminate 2PC's blocking problem. Learn how it works, what assumptions it requires, and why it's rarely used in production.</td>
</tr>
<tr>
<td>16</td>
<td><a href="/delivery-semantics-what-does-delivered-actually-mean">Delivery Semantics: What Does "Delivered" Actually Mean?</a></td>
<td>Message delivery guarantees define system reliability. Learn what at-most-once, at-least-once, and exactly-once mean, what they cost, and when each is appropriate.</td>
</tr>
<tr>
<td>17</td>
<td><a href="/change-data-capture-streaming-your-database-in-real-time">Change Data Capture: Streaming Your Database in Real Time</a></td>
<td>CDC streams database changes in real time by reading the write-ahead log. Learn how Debezium works, what CDC enables, and when to use it.</td>
</tr>
<tr>
<td>18</td>
<td><a href="/erasure-coding-fault-tolerance-without-full-replication">Erasure Coding: Fault Tolerance Without Full Replication</a></td>
<td>Erasure coding stores data across nodes using math, not full replication. Learn how Reed-Solomon works, how S3 uses it, and when it beats 3x replication.</td>
</tr>
<tr>
<td>19</td>
<td><a href="/merkle-trees-efficiently-finding-whats-different">Merkle Trees: Efficiently Finding What's Different</a></td>
<td>Merkle trees efficiently detect which parts of a large dataset differ between nodes. Learn how Bitcoin, Cassandra, and Git use them for verification and anti-entropy.</td>
</tr>
<tr>
<td>20</td>
<td><a href="/observability-understanding-your-system-at-runtime">Observability: Understanding Your System at Runtime</a></td>
<td>Logs, metrics, and distributed traces are how you understand a system at runtime. Learn what each pillar provides, the tools involved, and how they work together.</td>
</tr>
<tr>
<td>21</td>
<td><a href="/distributed-systems-wrap-up">Distributed Systems: Wrap-Up</a></td>
<td>A recap of all 20 distributed systems concepts and the complete URL shortener architecture spanning all 8 pillars. The final post in the series.</td>
</tr>
</tbody></table>
<hr />
<h1>Three-Phase Commit: Solving 2PC's Blocking Problem</h1>
<h2>The problem</h2>
<p>Two-Phase Commit blocks when the coordinator crashes after participants vote Yes but before sending the commit message. Participants hold locks indefinitely, waiting for a coordinator that might take minutes to restart.</p>
<p>The root cause: in 2PC, once a participant votes Yes, it has no way to make a safe independent decision. It doesn't know whether the coordinator committed or aborted — and different independent decisions by different participants would violate atomicity.</p>
<p>Three-Phase Commit (3PC) adds an intermediate phase that gives participants enough information to make a safe independent decision if the coordinator fails — eliminating the blocking problem.</p>
<hr />
<h2>The core idea</h2>
<p>3PC adds a <strong>pre-commit</strong> phase between prepare and commit. After collecting all Yes votes, the coordinator sends a Pre-Commit message before the final Commit. This gives participants two crucial properties: (1) they know all other participants have voted Yes, and (2) if the coordinator fails, they can safely complete the commit independently without risking disagreement.</p>
<hr />
<h2>The analogy: the wedding with a dress rehearsal</h2>
<p>2PC: the officiant asks "do you?" privately, collects answers, then announces the result. Problem: if the officiant collapses mid-announcement, parties don't know if they're married.</p>
<p>3PC: adds a rehearsal. Before the public ceremony, the officiant gathers both parties and says "I've confirmed you both said yes, and we're about to proceed — are you both still ready?" Only if both confirm does the final ceremony happen. Now if the officiant collapses mid-ceremony, either party knows: (1) we both confirmed readiness, (2) we can safely complete the ceremony ourselves.</p>
<p>The pre-commit is the rehearsal confirmation.</p>
<hr />
<h2>How 3PC works</h2>
<h3>Phase 1: Prepare (same as 2PC)</h3>
<p>Coordinator sends Prepare to all participants. Each votes Yes or No.</p>
<p>If any votes No → Coordinator sends Abort to all (same as 2PC).</p>
<h3>Phase 2: Pre-Commit (new phase)</h3>
<p>If all voted Yes → Coordinator sends <strong>Pre-Commit</strong> to all participants.</p>
<p>Each participant that receives Pre-Commit:</p>
<ul>
<li>Records it durably (survives crash)</li>
<li>Acknowledges to coordinator</li>
<li>Now knows: <strong>all participants voted Yes</strong></li>
</ul>
<p>The key property: a participant in Pre-Commit state knows it's safe to commit if the coordinator fails — because it knows every other participant also voted Yes.</p>
<h3>Phase 3: Commit</h3>
<p>Coordinator receives acknowledgements from all participants → sends <strong>Commit</strong>.</p>
<p>Each participant commits and releases locks.</p>
<h3>Handling coordinator failure</h3>
<p><strong>Coordinator fails in Phase 1 (before Pre-Commit):</strong> participants that haven't received Pre-Commit can safely abort — no Pre-Commit means not all votes were Yes, so aborting is safe.</p>
<p><strong>Coordinator fails in Phase 2 (after Pre-Commit to some, before all):</strong></p>
<ul>
<li>Participants that received Pre-Commit know all voted Yes → they elect a new coordinator from among themselves and complete the commit</li>
<li>Participants that didn't receive Pre-Commit abort</li>
<li>Wait — these decisions must agree! They don't, if the network partitioned the Pre-Commit messages inconsistently</li>
</ul>
<p>This is where 3PC's limitation emerges.</p>
<hr />
<h2>The key limitation: network partitions</h2>
<p>3PC assumes fail-stop failures (nodes crash cleanly) and no network partitions. In reality, network partitions are common (post 01). A partition can cause 3PC to violate atomicity:</p>
<pre><code>Coordinator sends Pre-Commit to A and B, but not C (partition)
Coordinator then crashes

A and B elect a new coordinator among themselves
Both are in Pre-Commit state → they commit
C times out in Prepared state → aborts

Result: A and B committed; C aborted → INCONSISTENT
</code></pre>
<p>Under a network partition, 3PC is unsafe: participants that received Pre-Commit commit, while participants that didn't abort — and they're making these independent decisions without knowing about each other's state.</p>
<p>This is why 3PC is almost never used in practice. The real world has network partitions. Under partitions, 3PC provides atomicity guarantees that are weaker than 2PC's (which at least blocks rather than making inconsistent decisions).</p>
<hr />
<h2>Why 3PC is rarely used</h2>
<p><strong>Network partitions make it unsafe.</strong> As described above — partition during Phase 2 can cause inconsistent commit/abort decisions.</p>
<p><strong>Paxos-based commit is better.</strong> A coordinator that uses consensus (Paxos/Raft) to durably record its decision before sending it to participants solves the blocking problem correctly, even under partitions. This is what CockroachDB and Spanner do — they don't implement 3PC.</p>
<p><strong>Saga patterns avoid the problem entirely.</strong> Most microservices don't need distributed atomicity at all if the system is designed with Sagas.</p>
<hr />
<h2>The one thing to remember</h2>
<blockquote>
<p><strong>3PC eliminates 2PC's blocking problem by adding a pre-commit phase that tells participants "all have voted yes" before the final commit — allowing them to complete the commit independently if the coordinator fails.</strong> The protocol works under crash failures, but breaks under network partitions (the more realistic failure mode), making inconsistent commit/abort decisions when Pre-Commit is delivered to some participants but not others. This is why 3PC is a useful theoretical concept but is almost never implemented in production systems, which use consensus-based commit (CockroachDB, Spanner) or Saga patterns instead.</p>
</blockquote>
<hr />
<p><em>← Previous: <strong><a href="/two-phase-commit-coordinating-a-distributed-decision">Two-Phase Commit</a></strong> — the classical distributed transaction protocol in detail.</em></p>
<p><em>→ Next: <strong><a href="/delivery-semantics-what-does-delivered-actually-mean">Delivery Semantics</a></strong> — at-most-once, at-least-once, and exactly-once: what each guarantees and what it costs.</em></p>
]]></content:encoded></item><item><title><![CDATA[Two-Phase Commit: Coordinating a Distributed Decision]]></title><description><![CDATA[Series: System Design · Distributed Systems — Pillar 8 of 8

Systems Design



#
Post
What it covers



00
Distributed Systems: What Happens When Machines Disagree
Twenty concepts covering network par]]></description><link>https://cloudtuned.dev/two-phase-commit-coordinating-a-distributed-decision</link><guid isPermaLink="true">https://cloudtuned.dev/two-phase-commit-coordinating-a-distributed-decision</guid><category><![CDATA[systemdesign]]></category><category><![CDATA[distributedsystems]]></category><category><![CDATA[twophasecommit]]></category><category><![CDATA[2PC]]></category><category><![CDATA[transactions]]></category><category><![CDATA[backend]]></category><category><![CDATA[SoftwareDevelopment]]></category><category><![CDATA[softwarearchitecture]]></category><category><![CDATA[engineering]]></category><dc:creator><![CDATA[Cloud Tuned]]></dc:creator><pubDate>Fri, 07 Mar 2025 12:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/602bee9a4bb9c4083f02795d/d0ea334e-388b-4fc4-b273-f7c32efeb96d.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote>
<p><strong>Series:</strong> System Design · Distributed Systems — Pillar 8 of 8</p>
</blockquote>
<h2>Systems Design</h2>
<table>
<thead>
<tr>
<th>#</th>
<th>Post</th>
<th>What it covers</th>
</tr>
</thead>
<tbody><tr>
<td>00</td>
<td><a href="/distributed-systems-what-happens-when-machines-disagree">Distributed Systems: What Happens When Machines Disagree</a></td>
<td>Twenty concepts covering network partitions, consensus, clocks, distributed transactions, CDC, erasure coding, and observability. The final pillar.</td>
</tr>
<tr>
<td>01</td>
<td><a href="/network-partitions-the-failure-mode-you-cant-design-away">Network Partitions: The Failure Mode You Can't Design Away</a></td>
<td>Network partitions are inevitable. Learn what happens when nodes can't communicate, how systems choose between availability and consistency, and what that means in practice.</td>
</tr>
<tr>
<td>02</td>
<td><a href="/split-brain-when-two-nodes-both-think-theyre-the-leader">Split-Brain: When Two Nodes Both Think They're the Leader</a></td>
<td>Split-brain occurs when two nodes both believe they're the primary. Learn how it happens, why it causes data corruption, and how STONITH and fencing prevent it.</td>
</tr>
<tr>
<td>03</td>
<td><a href="/heartbeats-how-nodes-know-their-peers-are-alive">Heartbeats: How Nodes Know Their Peers Are Alive</a></td>
<td>Heartbeats let nodes detect peer failures. Learn how timeouts, phi accrual failure detectors, and the tradeoff between false positives and detection speed work.</td>
</tr>
<tr>
<td>04</td>
<td><a href="/leader-election-agreeing-on-whos-in-charge">Leader Election: Agreeing on Who's in Charge</a></td>
<td>Leader election coordinates which node acts as primary. Learn the bully algorithm, Raft-based election, and why exactly-one-leader guarantees are hard to achieve.</td>
</tr>
<tr>
<td>05</td>
<td><a href="/consensus-algorithms-agreeing-on-a-value-across-failures">Consensus Algorithms: Agreeing on a Value Across Failures</a></td>
<td>Consensus lets distributed nodes agree on a value despite failures. Learn what FLP impossibility means, what Paxos and Raft provide, and where consensus is used.</td>
</tr>
<tr>
<td>06</td>
<td><a href="/quorum-how-many-nodes-must-agree">Quorum: How Many Nodes Must Agree?</a></td>
<td>Quorum determines how many nodes must agree for an operation to succeed. Learn how R + W &gt; N ensures consistency in distributed databases like Cassandra and DynamoDB.</td>
</tr>
<tr>
<td>07</td>
<td><a href="/paxos-the-algorithm-that-started-it-all">Paxos: The Algorithm That Started It All</a></td>
<td>Paxos is the foundational distributed consensus algorithm. Learn how its two phases work, why it's hard to implement, and what systems use it in production.</td>
</tr>
<tr>
<td>08</td>
<td><a href="/raft-consensus-made-understandable">Raft: Consensus Made Understandable</a></td>
<td>Raft makes distributed consensus understandable. Learn how leader election, log replication, and safety work in the algorithm that powers etcd, CockroachDB, and TiKV.</td>
</tr>
<tr>
<td>09</td>
<td><a href="/gossip-protocol-decentralised-cluster-communication">Gossip Protocol: Decentralised Cluster Communication</a></td>
<td>Gossip protocols propagate information across a cluster without a central coordinator. Learn how epidemic spreading works and where it's used in production.</td>
</tr>
<tr>
<td>10</td>
<td><a href="/logical-clocks-when-physical-time-isnt-enough">Logical Clocks: When Physical Time Isn't Enough</a></td>
<td>Physical clocks drift and can't establish event order in distributed systems. Logical clocks track causality instead. Learn why this matters and how it works.</td>
</tr>
<tr>
<td>11</td>
<td><a href="/lamport-timestamps-ordering-events-without-a-global-clock">Lamport Timestamps: Ordering Events Without a Global Clock</a></td>
<td>Lamport timestamps assign logical counters to events to establish causal order in distributed systems. Learn how they work and what they can and can't tell you.</td>
</tr>
<tr>
<td>12</td>
<td><a href="/vector-clocks-knowing-when-events-are-truly-concurrent">Vector Clocks: Knowing When Events Are Truly Concurrent</a></td>
<td>Vector clocks detect causality and concurrency in distributed systems. Learn how they work, how Dynamo uses them for conflict detection, and their limitations.</td>
</tr>
<tr>
<td>13</td>
<td><a href="/distributed-transactions-when-one-machine-isnt-enough">Distributed Transactions: When One Machine Isn't Enough</a></td>
<td>Distributed transactions are hard. Learn why cross-service atomicity is expensive, when to use it, and when eventual consistency is the right alternative.</td>
</tr>
<tr>
<td>14</td>
<td><strong>Two-Phase Commit: Coordinating a Distributed Decision</strong> ← you are here</td>
<td>2PC ensures distributed atomicity through prepare and commit phases. Learn how it works, the coordinator failure problem, and why it's rarely used in modern systems.</td>
</tr>
<tr>
<td>15</td>
<td><a href="/three-phase-commit-solving-2pcs-blocking-problem">Three-Phase Commit: Solving 2PC's Blocking Problem</a></td>
<td>3PC adds a pre-commit phase to eliminate 2PC's blocking problem. Learn how it works, what assumptions it requires, and why it's rarely used in production.</td>
</tr>
<tr>
<td>16</td>
<td><a href="/delivery-semantics-what-does-delivered-actually-mean">Delivery Semantics: What Does "Delivered" Actually Mean?</a></td>
<td>Message delivery guarantees define system reliability. Learn what at-most-once, at-least-once, and exactly-once mean, what they cost, and when each is appropriate.</td>
</tr>
<tr>
<td>17</td>
<td><a href="/change-data-capture-streaming-your-database-in-real-time">Change Data Capture: Streaming Your Database in Real Time</a></td>
<td>CDC streams database changes in real time by reading the write-ahead log. Learn how Debezium works, what CDC enables, and when to use it.</td>
</tr>
<tr>
<td>18</td>
<td><a href="/erasure-coding-fault-tolerance-without-full-replication">Erasure Coding: Fault Tolerance Without Full Replication</a></td>
<td>Erasure coding stores data across nodes using math, not full replication. Learn how Reed-Solomon works, how S3 uses it, and when it beats 3x replication.</td>
</tr>
<tr>
<td>19</td>
<td><a href="/merkle-trees-efficiently-finding-whats-different">Merkle Trees: Efficiently Finding What's Different</a></td>
<td>Merkle trees efficiently detect which parts of a large dataset differ between nodes. Learn how Bitcoin, Cassandra, and Git use them for verification and anti-entropy.</td>
</tr>
<tr>
<td>20</td>
<td><a href="/observability-understanding-your-system-at-runtime">Observability: Understanding Your System at Runtime</a></td>
<td>Logs, metrics, and distributed traces are how you understand a system at runtime. Learn what each pillar provides, the tools involved, and how they work together.</td>
</tr>
<tr>
<td>21</td>
<td><a href="/distributed-systems-wrap-up">Distributed Systems: Wrap-Up</a></td>
<td>A recap of all 20 distributed systems concepts and the complete URL shortener architecture spanning all 8 pillars. The final post in the series.</td>
</tr>
</tbody></table>
<hr />
<h1>Two-Phase Commit: Coordinating a Distributed Decision</h1>
<h2>The problem</h2>
<p>Three database nodes must atomically commit a transaction: either all three commit or all three abort. The coordinator must make this decision and ensure all participants do the same, even if some messages are delayed and any node can fail at any moment.</p>
<p>Sending "commit" to all three simultaneously doesn't work — if the message reaches two nodes but is lost to the third (network failure), two commit and one doesn't. The transaction is inconsistent.</p>
<p>You need a protocol that guarantees: if even one participant cannot commit (for any reason), none commit.</p>
<hr />
<h2>The core idea</h2>
<p>Two-Phase Commit (2PC) coordinates a distributed transaction in two phases: <strong>prepare</strong> (each participant votes yes or no), then <strong>commit or abort</strong> (the coordinator sends the unanimous decision). Only after receiving a "yes" from every participant does the coordinator send "commit." Any "no" triggers an "abort" to all.</p>
<hr />
<h2>The analogy: a wedding ceremony with a final question</h2>
<p>A wedding officiant (coordinator) asks each party: "Do you take this person to be your lawfully wedded spouse?" Each must say "yes" before the officiant declares them married.</p>
<p>Phase 1: The officiant asks each party privately whether they're sure. Each commits (in their heart) to saying yes, but says nothing final yet — they're in a "prepared" state.</p>
<p>Phase 2: If both said yes, the officiant declares them married (commit). If either hesitates or says no, the ceremony is called off (abort).</p>
<p>If the officiant collapses mid-ceremony after both parties have said "yes" but before the declaration — both parties are stuck in "prepared" state, unsure whether the marriage is legal. This is the 2PC blocking problem.</p>
<hr />
<h2>How 2PC works</h2>
<h3>Phase 1: Prepare</h3>
<pre><code>Coordinator → Prepare → Participant A
Coordinator → Prepare → Participant B
Coordinator → Prepare → Participant C

Each participant:
  - Evaluates whether it can commit (checks constraints, acquires row locks)
  - Writes a "prepared" record to its WAL (durable — will survive crash)
  - Sends Vote-Yes or Vote-No to coordinator

If Vote-Yes: participant is committed to committing if coordinator says so
             It will not abort unilaterally
If Vote-No:  participant cannot commit (constraint violation, lock conflict)
</code></pre>
<h3>Phase 2: Commit or Abort</h3>
<pre><code>If all votes are Yes:
  Coordinator writes "commit" to its log (durable)
  Coordinator → Commit → all participants
  Each participant commits and releases locks

If any vote is No:
  Coordinator → Abort → all participants
  Each participant rolls back and releases locks
</code></pre>
<h3>Why it's safe</h3>
<p>Once a participant votes Yes, it is obligated to commit if the coordinator says commit — it cannot independently decide to abort. This obligation is what makes atomicity possible: the coordinator makes exactly one decision, and all prepared participants follow it.</p>
<h3>The blocking problem</h3>
<p>2PC has one critical flaw: <strong>it blocks if the coordinator fails after participants vote Yes but before the commit message is sent.</strong></p>
<pre><code>Participants A, B, C all vote Yes
Coordinator writes "commit" to log
Coordinator CRASHES before sending commit to anyone

Status:
  A, B, C: each holds locks, waiting for coordinator
  None knows whether to commit or abort
  They cannot make a safe independent decision:
    - Committing unilaterally might contradict a decision the coordinator
      will make to abort when it recovers
    - Aborting unilaterally might contradict a commit decision
  
  They must wait for coordinator to recover.
  Locks held. Blocking.
</code></pre>
<p>In practice, the coordinator typically recovers in seconds to minutes. But during that window, all locked rows are unavailable. For a busy OLTP database, this is a serious availability problem.</p>
<p><strong>Mitigation:</strong> the coordinator writes its decision to durable storage before sending messages. On recovery, it can resume from its log and send the correct message to all participants. This reduces the blocking window to the coordinator's recovery time — but doesn't eliminate blocking entirely.</p>
<h3>Coordinator failure edge cases</h3>
<p><strong>Coordinator fails before writing prepare:</strong> coordinator can abort the transaction on recovery — nothing was committed.</p>
<p><strong>Coordinator fails after prepare but before commit:</strong> participants are stuck in "prepared" state holding locks until coordinator recovers. This is the blocking case.</p>
<p><strong>Coordinator fails after sending some commits:</strong> some participants committed. On recovery, coordinator resends commit to the participants that hadn't acknowledged. All eventually commit — consistency is restored.</p>
<hr />
<h2>Where 2PC is used</h2>
<p><strong>XA transactions (PostgreSQL, MySQL, Oracle):</strong> the database's native support for distributed transactions. Used in some enterprise systems where cross-database atomicity is required.</p>
<p><strong>JTA (Java Transaction API):</strong> enterprise Java applications managing transactions across databases and message brokers.</p>
<p><strong>CockroachDB / Spanner internals:</strong> these use a variant of 2PC, but with Raft providing the coordinator's durability guarantee, eliminating the blocking problem.</p>
<p><strong>Avoided in microservices:</strong> the lock contention, blocking on coordinator failure, and latency make 2PC unsuitable for most microservices designs. The Saga pattern (Pillar 7, post 09) is almost always preferred.</p>
<hr />
<h2>The one thing to remember</h2>
<blockquote>
<p><strong>2PC guarantees atomicity across distributed participants through a prepare-then-commit protocol: all must vote yes before any commit.</strong> The fundamental weakness is blocking: if the coordinator crashes after participants vote yes but before the commit message is sent, all participants hold locks and wait. This blocking behaviour — not correctness — is what makes 2PC impractical for most microservices designs, and why Saga patterns and distributed databases with native consensus (CockroachDB, Spanner) are preferred.</p>
</blockquote>
<hr />
<p><em>← Previous: <strong><a href="/distributed-transactions-when-one-machine-isnt-enough">Distributed Transactions</a></strong> — ensuring atomicity across multiple nodes or services when a single ACID transaction isn't possible.</em></p>
<p><em>→ Next: <strong><a href="/three-phase-commit-solving-2pcs-blocking-problem">Three-Phase Commit</a></strong> — the protocol designed to eliminate 2PC's blocking problem, and why it's rarely used in practice despite solving it.</em></p>
]]></content:encoded></item><item><title><![CDATA[Distributed Transactions: When One Machine Isn't Enough]]></title><description><![CDATA[Series: System Design · Distributed Systems — Pillar 8 of 8

Systems Design



#
Post
What it covers



00
Distributed Systems: What Happens When Machines Disagree
Twenty concepts covering network par]]></description><link>https://cloudtuned.dev/distributed-transactions-when-one-machine-isnt-enough</link><guid isPermaLink="true">https://cloudtuned.dev/distributed-transactions-when-one-machine-isnt-enough</guid><category><![CDATA[systemdesign]]></category><category><![CDATA[distributedsystems]]></category><category><![CDATA[DistributedTransactions]]></category><category><![CDATA[atomicity]]></category><category><![CDATA[backend]]></category><category><![CDATA[SoftwareDevelopment]]></category><category><![CDATA[softwarearchitecture]]></category><category><![CDATA[engineering]]></category><dc:creator><![CDATA[Cloud Tuned]]></dc:creator><pubDate>Thu, 06 Mar 2025 12:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/602bee9a4bb9c4083f02795d/e14ac696-4e57-44c9-b798-d4f130467bab.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote>
<p><strong>Series:</strong> System Design · Distributed Systems — Pillar 8 of 8</p>
</blockquote>
<h2>Systems Design</h2>
<table>
<thead>
<tr>
<th>#</th>
<th>Post</th>
<th>What it covers</th>
</tr>
</thead>
<tbody><tr>
<td>00</td>
<td><a href="/distributed-systems-what-happens-when-machines-disagree">Distributed Systems: What Happens When Machines Disagree</a></td>
<td>Twenty concepts covering network partitions, consensus, clocks, distributed transactions, CDC, erasure coding, and observability. The final pillar.</td>
</tr>
<tr>
<td>01</td>
<td><a href="/network-partitions-the-failure-mode-you-cant-design-away">Network Partitions: The Failure Mode You Can't Design Away</a></td>
<td>Network partitions are inevitable. Learn what happens when nodes can't communicate, how systems choose between availability and consistency, and what that means in practice.</td>
</tr>
<tr>
<td>02</td>
<td><a href="/split-brain-when-two-nodes-both-think-theyre-the-leader">Split-Brain: When Two Nodes Both Think They're the Leader</a></td>
<td>Split-brain occurs when two nodes both believe they're the primary. Learn how it happens, why it causes data corruption, and how STONITH and fencing prevent it.</td>
</tr>
<tr>
<td>03</td>
<td><a href="/heartbeats-how-nodes-know-their-peers-are-alive">Heartbeats: How Nodes Know Their Peers Are Alive</a></td>
<td>Heartbeats let nodes detect peer failures. Learn how timeouts, phi accrual failure detectors, and the tradeoff between false positives and detection speed work.</td>
</tr>
<tr>
<td>04</td>
<td><a href="/leader-election-agreeing-on-whos-in-charge">Leader Election: Agreeing on Who's in Charge</a></td>
<td>Leader election coordinates which node acts as primary. Learn the bully algorithm, Raft-based election, and why exactly-one-leader guarantees are hard to achieve.</td>
</tr>
<tr>
<td>05</td>
<td><a href="/consensus-algorithms-agreeing-on-a-value-across-failures">Consensus Algorithms: Agreeing on a Value Across Failures</a></td>
<td>Consensus lets distributed nodes agree on a value despite failures. Learn what FLP impossibility means, what Paxos and Raft provide, and where consensus is used.</td>
</tr>
<tr>
<td>06</td>
<td><a href="/quorum-how-many-nodes-must-agree">Quorum: How Many Nodes Must Agree?</a></td>
<td>Quorum determines how many nodes must agree for an operation to succeed. Learn how R + W &gt; N ensures consistency in distributed databases like Cassandra and DynamoDB.</td>
</tr>
<tr>
<td>07</td>
<td><a href="/paxos-the-algorithm-that-started-it-all">Paxos: The Algorithm That Started It All</a></td>
<td>Paxos is the foundational distributed consensus algorithm. Learn how its two phases work, why it's hard to implement, and what systems use it in production.</td>
</tr>
<tr>
<td>08</td>
<td><a href="/raft-consensus-made-understandable">Raft: Consensus Made Understandable</a></td>
<td>Raft makes distributed consensus understandable. Learn how leader election, log replication, and safety work in the algorithm that powers etcd, CockroachDB, and TiKV.</td>
</tr>
<tr>
<td>09</td>
<td><a href="/gossip-protocol-decentralised-cluster-communication">Gossip Protocol: Decentralised Cluster Communication</a></td>
<td>Gossip protocols propagate information across a cluster without a central coordinator. Learn how epidemic spreading works and where it's used in production.</td>
</tr>
<tr>
<td>10</td>
<td><a href="/logical-clocks-when-physical-time-isnt-enough">Logical Clocks: When Physical Time Isn't Enough</a></td>
<td>Physical clocks drift and can't establish event order in distributed systems. Logical clocks track causality instead. Learn why this matters and how it works.</td>
</tr>
<tr>
<td>11</td>
<td><a href="/lamport-timestamps-ordering-events-without-a-global-clock">Lamport Timestamps: Ordering Events Without a Global Clock</a></td>
<td>Lamport timestamps assign logical counters to events to establish causal order in distributed systems. Learn how they work and what they can and can't tell you.</td>
</tr>
<tr>
<td>12</td>
<td><a href="/vector-clocks-knowing-when-events-are-truly-concurrent">Vector Clocks: Knowing When Events Are Truly Concurrent</a></td>
<td>Vector clocks detect causality and concurrency in distributed systems. Learn how they work, how Dynamo uses them for conflict detection, and their limitations.</td>
</tr>
<tr>
<td>13</td>
<td><strong>Distributed Transactions: When One Machine Isn't Enough</strong> ← you are here</td>
<td>Distributed transactions are hard. Learn why cross-service atomicity is expensive, when to use it, and when eventual consistency is the right alternative.</td>
</tr>
<tr>
<td>14</td>
<td><a href="/two-phase-commit-coordinating-a-distributed-decision">Two-Phase Commit: Coordinating a Distributed Decision</a></td>
<td>2PC ensures distributed atomicity through prepare and commit phases. Learn how it works, the coordinator failure problem, and why it's rarely used in modern systems.</td>
</tr>
<tr>
<td>15</td>
<td><a href="/three-phase-commit-solving-2pcs-blocking-problem">Three-Phase Commit: Solving 2PC's Blocking Problem</a></td>
<td>3PC adds a pre-commit phase to eliminate 2PC's blocking problem. Learn how it works, what assumptions it requires, and why it's rarely used in production.</td>
</tr>
<tr>
<td>16</td>
<td><a href="/delivery-semantics-what-does-delivered-actually-mean">Delivery Semantics: What Does "Delivered" Actually Mean?</a></td>
<td>Message delivery guarantees define system reliability. Learn what at-most-once, at-least-once, and exactly-once mean, what they cost, and when each is appropriate.</td>
</tr>
<tr>
<td>17</td>
<td><a href="/change-data-capture-streaming-your-database-in-real-time">Change Data Capture: Streaming Your Database in Real Time</a></td>
<td>CDC streams database changes in real time by reading the write-ahead log. Learn how Debezium works, what CDC enables, and when to use it.</td>
</tr>
<tr>
<td>18</td>
<td><a href="/erasure-coding-fault-tolerance-without-full-replication">Erasure Coding: Fault Tolerance Without Full Replication</a></td>
<td>Erasure coding stores data across nodes using math, not full replication. Learn how Reed-Solomon works, how S3 uses it, and when it beats 3x replication.</td>
</tr>
<tr>
<td>19</td>
<td><a href="/merkle-trees-efficiently-finding-whats-different">Merkle Trees: Efficiently Finding What's Different</a></td>
<td>Merkle trees efficiently detect which parts of a large dataset differ between nodes. Learn how Bitcoin, Cassandra, and Git use them for verification and anti-entropy.</td>
</tr>
<tr>
<td>20</td>
<td><a href="/observability-understanding-your-system-at-runtime">Observability: Understanding Your System at Runtime</a></td>
<td>Logs, metrics, and distributed traces are how you understand a system at runtime. Learn what each pillar provides, the tools involved, and how they work together.</td>
</tr>
<tr>
<td>21</td>
<td><a href="/distributed-systems-wrap-up">Distributed Systems: Wrap-Up</a></td>
<td>A recap of all 20 distributed systems concepts and the complete URL shortener architecture spanning all 8 pillars. The final post in the series.</td>
</tr>
</tbody></table>
<hr />
<h1>Distributed Transactions: When One Machine Isn't Enough</h1>
<h2>The problem</h2>
<p>A user upgrades their URL shortener plan from Free to Pro. This must atomically:</p>
<ol>
<li>Charge their credit card (Stripe API)</li>
<li>Update their plan in the User Service database</li>
<li>Increase their link quota in the Link Service database</li>
</ol>
<p>In a single-database monolith, this is one transaction — either all three succeed or all three roll back. The database guarantees atomicity.</p>
<p>In a microservices architecture with three separate systems (Stripe, User DB, Link DB), there is no single transaction manager. If step 2 succeeds and step 3 fails, the user has paid for Pro but their quota wasn't increased. If step 1 succeeds and step 2 fails, the user was charged but their account shows Free tier. Both are bad.</p>
<p>This is the distributed transaction problem: ensuring atomicity (all-or-nothing) across multiple independent data stores or services.</p>
<hr />
<h2>The core idea</h2>
<p>A distributed transaction provides ACID guarantees across multiple nodes or services. It's much harder than a local transaction because it requires coordinating the commit or abort decision across participants that can each independently fail or become unreachable. The fundamental difficulty: how do you commit atomically when the network might drop your commit message?</p>
<hr />
<h2>The analogy: signing a contract with multiple parties</h2>
<p>A business deal requires signatures from Company A, Company B, and a lawyer as witness. The rule: the deal is finalised only when all three sign; if any refuses or is unreachable, the deal is null and void.</p>
<p>In person, this is easy — everyone signs in the same room simultaneously. Over distance, it's hard: Company A signs and sends to Company B, which signs and sends to the lawyer. What if Company B's courier is delayed? Company A has signed; Company B hasn't. The deal is in limbo. Who decides whether to proceed?</p>
<p>A distributed transaction coordinator is the resolution: it collects "ready to sign" confirmations from all parties before telling anyone to finalise.</p>
<hr />
<h2>When distributed transactions are needed vs avoidable</h2>
<p><strong>Genuinely needed:</strong></p>
<ul>
<li>Financial operations that must be consistent across multiple stores (charge + grant access must be atomic)</li>
<li>Cross-service invariants that must be maintained (inventory count in one service and order record in another)</li>
<li>Database migrations that span shards (moving a record from shard A to shard B must not leave it in both or neither)</li>
</ul>
<p><strong>Avoidable with eventual consistency:</strong></p>
<ul>
<li>Most microservices communication (Saga pattern + Outbox — Pillar 7, posts 09–10)</li>
<li>Analytics, notifications, search index updates</li>
<li>Any operation where "we'll fix inconsistency later" is acceptable</li>
</ul>
<p><strong>The key insight:</strong> most operations that seem to require distributed transactions actually don't, if you're willing to accept brief eventual inconsistency and design idempotent recovery. The Saga pattern (Pillar 7, post 09) handles most cross-service coordination without distributed transactions.</p>
<hr />
<h2>The approaches</h2>
<h3>2PC (Two-Phase Commit)</h3>
<p>The classical protocol. A coordinator node:</p>
<ol>
<li><strong>Prepare phase:</strong> asks all participants "can you commit?" Each votes yes or no and locks its resources</li>
<li><strong>Commit phase:</strong> if all vote yes, coordinator sends commit to all; if any votes no, sends abort to all</li>
</ol>
<p>Guarantees atomicity. Problems: blocking on coordinator failure (covered in post 14), lock contention (participants hold locks during the prepare phase, waiting for the coordinator's decision).</p>
<h3>Saga pattern (Pillar 7, post 09)</h3>
<p>Not a true distributed transaction — uses local transactions with compensating actions. Eventual consistency: the system may be inconsistent for a brief period. The right choice for most microservices cross-service operations.</p>
<h3>Distributed databases with native support (CockroachDB, Spanner)</h3>
<p>CockroachDB and Google Spanner provide distributed ACID transactions natively. They use consensus (Raft/Paxos) to ensure all shards agree on the transaction outcome. This is the correct tool when you need true distributed atomicity without implementing it yourself.</p>
<p>CockroachDB executes transactions across multiple shards using a protocol similar to 2PC, but with Raft providing the durability guarantee at each shard — eliminating the "coordinator crashes, transaction is stuck" problem of classic 2PC.</p>
<h3>XA transactions (distributed database standard)</h3>
<p>XA is a standard for distributed transactions used by traditional enterprise databases. Supported by MySQL, PostgreSQL, Oracle. Allows transactions that span multiple database servers with a two-phase commit.</p>
<p>In practice, XA is rarely used in modern microservices — the coordination overhead is high and it requires all participants to be XA-aware. Saga patterns are almost universally preferred.</p>
<hr />
<h2>The real cost of distributed transactions</h2>
<p><strong>Lock contention.</strong> In 2PC, all participants hold locks on affected rows from the prepare phase until the commit message arrives. If the coordinator is slow or crashes, locks are held indefinitely — blocking all other reads and writes to those rows.</p>
<p><strong>Coordinator availability.</strong> The transaction coordinator is a single point of failure. If it crashes after participants voted "yes" but before sending commit, the transaction is stuck in "prepared" state until the coordinator recovers. This is the 2PC blocking problem (covered in post 14).</p>
<p><strong>Latency.</strong> At minimum, a distributed transaction requires two round trips (prepare + commit) between the coordinator and all participants. For cross-region transactions (London, Singapore, São Paulo), this is 3 × cross-continent RTT = 300–600ms per transaction.</p>
<p><strong>Operational complexity.</strong> Stuck transactions ("in-doubt" transactions) require manual intervention or automated recovery. Every DBA who has worked with distributed databases has encountered stuck 2PC transactions that had to be manually resolved.</p>
<hr />
<h2>The one thing to remember</h2>
<blockquote>
<p><strong>Distributed transactions are expensive and fragile: they require coordination across multiple independent systems, hold locks during the coordination period, and block if the coordinator fails.</strong> Most cross-service operations that appear to need distributed transactions can be handled with the Saga pattern (eventual consistency with compensating actions) at lower cost and higher availability. Reserve distributed transactions for cases where eventual consistency genuinely isn't acceptable — and prefer databases (CockroachDB, Spanner) that implement them natively over rolling your own 2PC coordinator.</p>
</blockquote>
<hr />
<p><em>← Previous: <strong><a href="/vector-clocks-knowing-when-events-are-truly-concurrent">Vector Clocks</a></strong> — extending Lamport timestamps to detect concurrency: when two events are causally independent, vector clocks make that explicit.</em></p>
<p><em>→ Next: <strong><a href="/two-phase-commit-coordinating-a-distributed-decision">Two-Phase Commit</a></strong> — the classical distributed transaction protocol in detail.</em></p>
]]></content:encoded></item><item><title><![CDATA[Vector Clocks: Knowing When Events Are Truly Concurrent]]></title><description><![CDATA[Series: System Design · Distributed Systems — Pillar 8 of 8

Systems Design



#
Post
What it covers



00
Distributed Systems: What Happens When Machines Disagree
Twenty concepts covering network par]]></description><link>https://cloudtuned.dev/vector-clocks-knowing-when-events-are-truly-concurrent</link><guid isPermaLink="true">https://cloudtuned.dev/vector-clocks-knowing-when-events-are-truly-concurrent</guid><category><![CDATA[systemdesign]]></category><category><![CDATA[distributedsystems]]></category><category><![CDATA[vectorclocks]]></category><category><![CDATA[causality]]></category><category><![CDATA[dynamo]]></category><category><![CDATA[backend]]></category><category><![CDATA[SoftwareDevelopment]]></category><category><![CDATA[softwarearchitecture]]></category><category><![CDATA[engineering]]></category><dc:creator><![CDATA[Cloud Tuned]]></dc:creator><pubDate>Wed, 05 Mar 2025 12:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/602bee9a4bb9c4083f02795d/336e9c8d-1f67-4949-9dc9-86e427bbbf48.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote>
<p><strong>Series:</strong> System Design · Distributed Systems — Pillar 8 of 8</p>
</blockquote>
<h2>Systems Design</h2>
<table>
<thead>
<tr>
<th>#</th>
<th>Post</th>
<th>What it covers</th>
</tr>
</thead>
<tbody><tr>
<td>00</td>
<td><a href="/distributed-systems-what-happens-when-machines-disagree">Distributed Systems: What Happens When Machines Disagree</a></td>
<td>Twenty concepts covering network partitions, consensus, clocks, distributed transactions, CDC, erasure coding, and observability. The final pillar.</td>
</tr>
<tr>
<td>01</td>
<td><a href="/network-partitions-the-failure-mode-you-cant-design-away">Network Partitions: The Failure Mode You Can't Design Away</a></td>
<td>Network partitions are inevitable. Learn what happens when nodes can't communicate, how systems choose between availability and consistency, and what that means in practice.</td>
</tr>
<tr>
<td>02</td>
<td><a href="/split-brain-when-two-nodes-both-think-theyre-the-leader">Split-Brain: When Two Nodes Both Think They're the Leader</a></td>
<td>Split-brain occurs when two nodes both believe they're the primary. Learn how it happens, why it causes data corruption, and how STONITH and fencing prevent it.</td>
</tr>
<tr>
<td>03</td>
<td><a href="/heartbeats-how-nodes-know-their-peers-are-alive">Heartbeats: How Nodes Know Their Peers Are Alive</a></td>
<td>Heartbeats let nodes detect peer failures. Learn how timeouts, phi accrual failure detectors, and the tradeoff between false positives and detection speed work.</td>
</tr>
<tr>
<td>04</td>
<td><a href="/leader-election-agreeing-on-whos-in-charge">Leader Election: Agreeing on Who's in Charge</a></td>
<td>Leader election coordinates which node acts as primary. Learn the bully algorithm, Raft-based election, and why exactly-one-leader guarantees are hard to achieve.</td>
</tr>
<tr>
<td>05</td>
<td><a href="/consensus-algorithms-agreeing-on-a-value-across-failures">Consensus Algorithms: Agreeing on a Value Across Failures</a></td>
<td>Consensus lets distributed nodes agree on a value despite failures. Learn what FLP impossibility means, what Paxos and Raft provide, and where consensus is used.</td>
</tr>
<tr>
<td>06</td>
<td><a href="/quorum-how-many-nodes-must-agree">Quorum: How Many Nodes Must Agree?</a></td>
<td>Quorum determines how many nodes must agree for an operation to succeed. Learn how R + W &gt; N ensures consistency in distributed databases like Cassandra and DynamoDB.</td>
</tr>
<tr>
<td>07</td>
<td><a href="/paxos-the-algorithm-that-started-it-all">Paxos: The Algorithm That Started It All</a></td>
<td>Paxos is the foundational distributed consensus algorithm. Learn how its two phases work, why it's hard to implement, and what systems use it in production.</td>
</tr>
<tr>
<td>08</td>
<td><a href="/raft-consensus-made-understandable">Raft: Consensus Made Understandable</a></td>
<td>Raft makes distributed consensus understandable. Learn how leader election, log replication, and safety work in the algorithm that powers etcd, CockroachDB, and TiKV.</td>
</tr>
<tr>
<td>09</td>
<td><a href="/gossip-protocol-decentralised-cluster-communication">Gossip Protocol: Decentralised Cluster Communication</a></td>
<td>Gossip protocols propagate information across a cluster without a central coordinator. Learn how epidemic spreading works and where it's used in production.</td>
</tr>
<tr>
<td>10</td>
<td><a href="/logical-clocks-when-physical-time-isnt-enough">Logical Clocks: When Physical Time Isn't Enough</a></td>
<td>Physical clocks drift and can't establish event order in distributed systems. Logical clocks track causality instead. Learn why this matters and how it works.</td>
</tr>
<tr>
<td>11</td>
<td><a href="/lamport-timestamps-ordering-events-without-a-global-clock">Lamport Timestamps: Ordering Events Without a Global Clock</a></td>
<td>Lamport timestamps assign logical counters to events to establish causal order in distributed systems. Learn how they work and what they can and can't tell you.</td>
</tr>
<tr>
<td>12</td>
<td><strong>Vector Clocks: Knowing When Events Are Truly Concurrent</strong> ← you are here</td>
<td>Vector clocks detect causality and concurrency in distributed systems. Learn how they work, how Dynamo uses them for conflict detection, and their limitations.</td>
</tr>
<tr>
<td>13</td>
<td><a href="/distributed-transactions-when-one-machine-isnt-enough">Distributed Transactions: When One Machine Isn't Enough</a></td>
<td>Distributed transactions are hard. Learn why cross-service atomicity is expensive, when to use it, and when eventual consistency is the right alternative.</td>
</tr>
<tr>
<td>14</td>
<td><a href="/two-phase-commit-coordinating-a-distributed-decision">Two-Phase Commit: Coordinating a Distributed Decision</a></td>
<td>2PC ensures distributed atomicity through prepare and commit phases. Learn how it works, the coordinator failure problem, and why it's rarely used in modern systems.</td>
</tr>
<tr>
<td>15</td>
<td><a href="/three-phase-commit-solving-2pcs-blocking-problem">Three-Phase Commit: Solving 2PC's Blocking Problem</a></td>
<td>3PC adds a pre-commit phase to eliminate 2PC's blocking problem. Learn how it works, what assumptions it requires, and why it's rarely used in production.</td>
</tr>
<tr>
<td>16</td>
<td><a href="/delivery-semantics-what-does-delivered-actually-mean">Delivery Semantics: What Does "Delivered" Actually Mean?</a></td>
<td>Message delivery guarantees define system reliability. Learn what at-most-once, at-least-once, and exactly-once mean, what they cost, and when each is appropriate.</td>
</tr>
<tr>
<td>17</td>
<td><a href="/change-data-capture-streaming-your-database-in-real-time">Change Data Capture: Streaming Your Database in Real Time</a></td>
<td>CDC streams database changes in real time by reading the write-ahead log. Learn how Debezium works, what CDC enables, and when to use it.</td>
</tr>
<tr>
<td>18</td>
<td><a href="/erasure-coding-fault-tolerance-without-full-replication">Erasure Coding: Fault Tolerance Without Full Replication</a></td>
<td>Erasure coding stores data across nodes using math, not full replication. Learn how Reed-Solomon works, how S3 uses it, and when it beats 3x replication.</td>
</tr>
<tr>
<td>19</td>
<td><a href="/merkle-trees-efficiently-finding-whats-different">Merkle Trees: Efficiently Finding What's Different</a></td>
<td>Merkle trees efficiently detect which parts of a large dataset differ between nodes. Learn how Bitcoin, Cassandra, and Git use them for verification and anti-entropy.</td>
</tr>
<tr>
<td>20</td>
<td><a href="/observability-understanding-your-system-at-runtime">Observability: Understanding Your System at Runtime</a></td>
<td>Logs, metrics, and distributed traces are how you understand a system at runtime. Learn what each pillar provides, the tools involved, and how they work together.</td>
</tr>
<tr>
<td>21</td>
<td><a href="/distributed-systems-wrap-up">Distributed Systems: Wrap-Up</a></td>
<td>A recap of all 20 distributed systems concepts and the complete URL shortener architecture spanning all 8 pillars. The final post in the series.</td>
</tr>
</tbody></table>
<hr />
<h1>Vector Clocks: Knowing When Events Are Truly Concurrent</h1>
<h2>The problem</h2>
<p>Lamport timestamps tell you: if A → B, then ts(A) &lt; ts(B). What they don't tell you: if ts(A) &lt; ts(B), does that mean A caused B, or were they concurrent?</p>
<p>Consider two users simultaneously editing the same link's destination URL on different servers. Lamport timestamps will order them (one will have a lower timestamp than the other), but this ordering is arbitrary — neither write caused the other. They're concurrent. Silently picking the "higher timestamp" write and discarding the other loses data without the application knowing a conflict occurred.</p>
<p>Vector clocks solve this: they can distinguish between "A happened-before B" and "A and B are concurrent and both happened independently." This distinction is the basis of conflict detection in distributed databases.</p>
<hr />
<h2>The core idea</h2>
<p>A vector clock is a list of counters, one per process, that tracks each process's knowledge of every other process's logical time. Comparing two vector clocks tells you definitively: A happened-before B, B happened-before A, or A and B are concurrent.</p>
<hr />
<h2>The analogy: tracking who heard what from whom</h2>
<p>Three gossips — Alice, Bob, and Carol — each keep a tally of how many things each person has told them:</p>
<ul>
<li>Alice's tally: [Alice: 3, Bob: 2, Carol: 1] — "I've made 3 statements, heard 2 from Bob, 1 from Carol"</li>
<li>Bob's tally: [Alice: 2, Bob: 4, Carol: 2]</li>
</ul>
<p>When Alice shares her tally with Bob, Bob updates each entry to the maximum of their two tallies. Bob now knows everything Alice knows.</p>
<p>If Bob's tally for a dimension is higher than Alice's for the same dimension, Bob has information Alice doesn't. If both are lower in some dimensions, their states are incomparable — they've heard different things and both have newer information in some respects. That's concurrency.</p>
<hr />
<h2>How vector clocks work</h2>
<p>Each process <code>i</code> maintains a vector <code>V</code> of length N (one entry per process). <code>V[j]</code> = the number of events process <code>i</code> knows about from process <code>j</code>.</p>
<p><strong>On a local event at process i:</strong> <code>V[i] += 1</code></p>
<p><strong>On sending a message from process i:</strong> <code>V[i] += 1</code>, send message with current <code>V</code></p>
<p><strong>On receiving a message at process i with vector <code>W</code>:</strong> <code>V[j] = max(V[j], W[j])</code> for all j, then <code>V[i] += 1</code></p>
<h3>Comparing vector clocks</h3>
<p>Vector clock A <strong>happened-before</strong> B (A → B) iff: <code>A[i] ≤ B[i]</code> for all i, and <code>A[j] &lt; B[j]</code> for at least one j.</p>
<p>Vectors A and B are <strong>concurrent</strong> (A ‖ B) iff: neither A → B nor B → A. This means A has a higher counter in some dimension and B has a higher counter in another.</p>
<pre><code>Process A    Process B    Process C
V_A=[0,0,0]  V_B=[0,0,0]  V_C=[0,0,0]

A has event: V_A=[1,0,0]
A sends to B with V=[1,0,0]

B receives:  V_B = max([0,0,0],[1,0,0]) + B++ = [1,1,0]
B has event: V_B=[1,2,0]

A has event (concurrent, no communication): V_A=[2,0,0]

Now compare V_A=[2,0,0] and V_B=[1,2,0]:
  V_A[0]=2 &gt; V_B[0]=1 → A has something B doesn't
  V_A[1]=0 &lt; V_B[1]=2 → B has something A doesn't
→ CONCURRENT: neither happened-before the other ✓
</code></pre>
<h3>Application: Dynamo and conflict detection</h3>
<p>Amazon Dynamo (and Riak, which is an open-source Dynamo implementation) uses version vectors (a variant of vector clocks) for conflict detection on writes.</p>
<p>When a client reads a key, Dynamo returns the value along with its version vector (a "context"). When the client writes back, it includes this context. Dynamo uses the context to determine if the write is a successor to the current value (no conflict) or concurrent with it (conflict).</p>
<pre><code>Initial: key="x7Kp2", value="https://old.com", VC=[A:1, B:0]

Client 1 reads (gets VC=[A:1, B:0]), updates to "https://v2.com"
Writes with context VC=[A:1, B:0] → stored on Server A
  Server A: value="https://v2.com", VC=[A:2, B:0]

Client 2 (concurrently, read the old value) updates to "https://v3.com"
Writes with context VC=[A:1, B:0] → stored on Server B
  Server B: value="https://v3.com", VC=[A:1, B:1]

Reconciliation:
  [A:2, B:0] vs [A:1, B:1]: concurrent (A has A:2 &gt; B:0, B has B:1 &gt; A:0)
  → CONFLICT: surface both values to the application for resolution
</code></pre>
<p>In Dynamo, conflicting versions are returned to the next reader as a list ("siblings"). The application (or the client library) resolves the conflict and writes back a merged version.</p>
<h3>The vector clock size problem</h3>
<p>A vector clock has one entry per process. With 100 processes, each vector clock is 100 entries. At scale, this becomes expensive to store and transmit.</p>
<p>Dynamo addresses this with <strong>dotted version vectors</strong> (a more compact representation) or <strong>version vectors</strong> (track client IDs rather than server IDs). Riak and newer Dynamo implementations use these to avoid unbounded clock growth.</p>
<hr />
<h2>Vector clocks vs Lamport timestamps</h2>
<table>
<thead>
<tr>
<th></th>
<th>Lamport Timestamps</th>
<th>Vector Clocks</th>
</tr>
</thead>
<tbody><tr>
<td><strong>Detects A → B</strong></td>
<td>Yes</td>
<td>Yes</td>
</tr>
<tr>
<td><strong>Detects concurrency</strong></td>
<td>No</td>
<td>Yes</td>
</tr>
<tr>
<td><strong>Size</strong></td>
<td>1 integer</td>
<td>N integers (one per process)</td>
</tr>
<tr>
<td><strong>Use case</strong></td>
<td>Total order, simple causality tracking</td>
<td>Conflict detection, concurrent write detection</td>
</tr>
</tbody></table>
<hr />
<h2>The one thing to remember</h2>
<blockquote>
<p><strong>Vector clocks track per-process knowledge so that comparing two events tells you definitively whether one happened-before the other or they're concurrent.</strong> A happened-before B means A's every counter ≤ B's corresponding counter (and at least one is strictly less). Concurrent means each has a higher counter in at least one dimension — neither subsumes the other. This is the mechanism behind conflict detection in Dynamo and Riak: concurrent writes are surfaced to the application for resolution, not silently discarded.</p>
</blockquote>
<hr />
<p><em>← Previous: <strong><a href="/lamport-timestamps-ordering-events-without-a-global-clock">Lamport Timestamps</a></strong> — the simplest logical clock: assigning monotonic integers to events to capture causal order.</em></p>
<p><em>→ Next: <strong><a href="/distributed-transactions-when-one-machine-isnt-enough">Distributed Transactions</a></strong> — ensuring atomicity across multiple nodes or services when a single ACID transaction isn't possible.</em></p>
]]></content:encoded></item><item><title><![CDATA[Lamport Timestamps: Ordering Events Without a Global Clock]]></title><description><![CDATA[Series: System Design · Distributed Systems — Pillar 8 of 8

Systems Design



#
Post
What it covers



00
Distributed Systems: What Happens When Machines Disagree
Twenty concepts covering network par]]></description><link>https://cloudtuned.dev/lamport-timestamps-ordering-events-without-a-global-clock</link><guid isPermaLink="true">https://cloudtuned.dev/lamport-timestamps-ordering-events-without-a-global-clock</guid><category><![CDATA[systemdesign]]></category><category><![CDATA[distributedsystems]]></category><category><![CDATA[lamporttimestamps]]></category><category><![CDATA[logicalclocks]]></category><category><![CDATA[backend]]></category><category><![CDATA[SoftwareDevelopment]]></category><category><![CDATA[softwarearchitecture]]></category><category><![CDATA[engineering]]></category><dc:creator><![CDATA[Cloud Tuned]]></dc:creator><pubDate>Tue, 04 Mar 2025 12:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/602bee9a4bb9c4083f02795d/b87368bb-d4b7-4c30-8dd8-15bc322bd955.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote>
<p><strong>Series:</strong> System Design · Distributed Systems — Pillar 8 of 8</p>
</blockquote>
<h2>Systems Design</h2>
<table>
<thead>
<tr>
<th>#</th>
<th>Post</th>
<th>What it covers</th>
</tr>
</thead>
<tbody><tr>
<td>00</td>
<td><a href="/distributed-systems-what-happens-when-machines-disagree">Distributed Systems: What Happens When Machines Disagree</a></td>
<td>Twenty concepts covering network partitions, consensus, clocks, distributed transactions, CDC, erasure coding, and observability. The final pillar.</td>
</tr>
<tr>
<td>01</td>
<td><a href="/network-partitions-the-failure-mode-you-cant-design-away">Network Partitions: The Failure Mode You Can't Design Away</a></td>
<td>Network partitions are inevitable. Learn what happens when nodes can't communicate, how systems choose between availability and consistency, and what that means in practice.</td>
</tr>
<tr>
<td>02</td>
<td><a href="/split-brain-when-two-nodes-both-think-theyre-the-leader">Split-Brain: When Two Nodes Both Think They're the Leader</a></td>
<td>Split-brain occurs when two nodes both believe they're the primary. Learn how it happens, why it causes data corruption, and how STONITH and fencing prevent it.</td>
</tr>
<tr>
<td>03</td>
<td><a href="/heartbeats-how-nodes-know-their-peers-are-alive">Heartbeats: How Nodes Know Their Peers Are Alive</a></td>
<td>Heartbeats let nodes detect peer failures. Learn how timeouts, phi accrual failure detectors, and the tradeoff between false positives and detection speed work.</td>
</tr>
<tr>
<td>04</td>
<td><a href="/leader-election-agreeing-on-whos-in-charge">Leader Election: Agreeing on Who's in Charge</a></td>
<td>Leader election coordinates which node acts as primary. Learn the bully algorithm, Raft-based election, and why exactly-one-leader guarantees are hard to achieve.</td>
</tr>
<tr>
<td>05</td>
<td><a href="/consensus-algorithms-agreeing-on-a-value-across-failures">Consensus Algorithms: Agreeing on a Value Across Failures</a></td>
<td>Consensus lets distributed nodes agree on a value despite failures. Learn what FLP impossibility means, what Paxos and Raft provide, and where consensus is used.</td>
</tr>
<tr>
<td>06</td>
<td><a href="/quorum-how-many-nodes-must-agree">Quorum: How Many Nodes Must Agree?</a></td>
<td>Quorum determines how many nodes must agree for an operation to succeed. Learn how R + W &gt; N ensures consistency in distributed databases like Cassandra and DynamoDB.</td>
</tr>
<tr>
<td>07</td>
<td><a href="/paxos-the-algorithm-that-started-it-all">Paxos: The Algorithm That Started It All</a></td>
<td>Paxos is the foundational distributed consensus algorithm. Learn how its two phases work, why it's hard to implement, and what systems use it in production.</td>
</tr>
<tr>
<td>08</td>
<td><a href="/raft-consensus-made-understandable">Raft: Consensus Made Understandable</a></td>
<td>Raft makes distributed consensus understandable. Learn how leader election, log replication, and safety work in the algorithm that powers etcd, CockroachDB, and TiKV.</td>
</tr>
<tr>
<td>09</td>
<td><a href="/gossip-protocol-decentralised-cluster-communication">Gossip Protocol: Decentralised Cluster Communication</a></td>
<td>Gossip protocols propagate information across a cluster without a central coordinator. Learn how epidemic spreading works and where it's used in production.</td>
</tr>
<tr>
<td>10</td>
<td><a href="/logical-clocks-when-physical-time-isnt-enough">Logical Clocks: When Physical Time Isn't Enough</a></td>
<td>Physical clocks drift and can't establish event order in distributed systems. Logical clocks track causality instead. Learn why this matters and how it works.</td>
</tr>
<tr>
<td>11</td>
<td><strong>Lamport Timestamps: Ordering Events Without a Global Clock</strong> ← you are here</td>
<td>Lamport timestamps assign logical counters to events to establish causal order in distributed systems. Learn how they work and what they can and can't tell you.</td>
</tr>
<tr>
<td>12</td>
<td><a href="/vector-clocks-knowing-when-events-are-truly-concurrent">Vector Clocks: Knowing When Events Are Truly Concurrent</a></td>
<td>Vector clocks detect causality and concurrency in distributed systems. Learn how they work, how Dynamo uses them for conflict detection, and their limitations.</td>
</tr>
<tr>
<td>13</td>
<td><a href="/distributed-transactions-when-one-machine-isnt-enough">Distributed Transactions: When One Machine Isn't Enough</a></td>
<td>Distributed transactions are hard. Learn why cross-service atomicity is expensive, when to use it, and when eventual consistency is the right alternative.</td>
</tr>
<tr>
<td>14</td>
<td><a href="/two-phase-commit-coordinating-a-distributed-decision">Two-Phase Commit: Coordinating a Distributed Decision</a></td>
<td>2PC ensures distributed atomicity through prepare and commit phases. Learn how it works, the coordinator failure problem, and why it's rarely used in modern systems.</td>
</tr>
<tr>
<td>15</td>
<td><a href="/three-phase-commit-solving-2pcs-blocking-problem">Three-Phase Commit: Solving 2PC's Blocking Problem</a></td>
<td>3PC adds a pre-commit phase to eliminate 2PC's blocking problem. Learn how it works, what assumptions it requires, and why it's rarely used in production.</td>
</tr>
<tr>
<td>16</td>
<td><a href="/delivery-semantics-what-does-delivered-actually-mean">Delivery Semantics: What Does "Delivered" Actually Mean?</a></td>
<td>Message delivery guarantees define system reliability. Learn what at-most-once, at-least-once, and exactly-once mean, what they cost, and when each is appropriate.</td>
</tr>
<tr>
<td>17</td>
<td><a href="/change-data-capture-streaming-your-database-in-real-time">Change Data Capture: Streaming Your Database in Real Time</a></td>
<td>CDC streams database changes in real time by reading the write-ahead log. Learn how Debezium works, what CDC enables, and when to use it.</td>
</tr>
<tr>
<td>18</td>
<td><a href="/erasure-coding-fault-tolerance-without-full-replication">Erasure Coding: Fault Tolerance Without Full Replication</a></td>
<td>Erasure coding stores data across nodes using math, not full replication. Learn how Reed-Solomon works, how S3 uses it, and when it beats 3x replication.</td>
</tr>
<tr>
<td>19</td>
<td><a href="/merkle-trees-efficiently-finding-whats-different">Merkle Trees: Efficiently Finding What's Different</a></td>
<td>Merkle trees efficiently detect which parts of a large dataset differ between nodes. Learn how Bitcoin, Cassandra, and Git use them for verification and anti-entropy.</td>
</tr>
<tr>
<td>20</td>
<td><a href="/observability-understanding-your-system-at-runtime">Observability: Understanding Your System at Runtime</a></td>
<td>Logs, metrics, and distributed traces are how you understand a system at runtime. Learn what each pillar provides, the tools involved, and how they work together.</td>
</tr>
<tr>
<td>21</td>
<td><a href="/distributed-systems-wrap-up">Distributed Systems: Wrap-Up</a></td>
<td>A recap of all 20 distributed systems concepts and the complete URL shortener architecture spanning all 8 pillars. The final post in the series.</td>
</tr>
</tbody></table>
<hr />
<h1>Lamport Timestamps: Ordering Events Without a Global Clock</h1>
<h2>The problem</h2>
<p>Three services — Link Service, Analytics Service, and Billing Service — exchange messages. We need to determine the order in which events occurred to reconstruct causality during an incident.</p>
<p>Physical timestamps are unreliable (clocks drift). We need a logical clock: a mechanism that assigns order numbers to events such that if event A caused event B, A's number is less than B's.</p>
<hr />
<h2>The core idea</h2>
<p>A Lamport timestamp is a monotonically increasing integer counter maintained per process. The rule: before any event, increment the counter. When sending a message, include the current counter. When receiving a message, take the max of the local counter and the received counter, then increment.</p>
<p>This ensures: if A happened-before B (A → B), then timestamp(A) &lt; timestamp(B). The converse is not guaranteed: timestamp(A) &lt; timestamp(B) does not imply A → B — it might just mean A happened on a process with a lower counter.</p>
<hr />
<h2>The analogy: version numbers in a document history</h2>
<p>A shared document has a version counter. Every edit increments the version. When two users collaborate, the server takes the higher version and increments it — ensuring every merged version is higher than either contributor's version.</p>
<p>If version 47 preceded version 48, version 47's changes are causally "before" version 48. If two separate branches both produced version 47 independently, they're concurrent — the counter alone can't tell you this.</p>
<hr />
<h2>The algorithm</h2>
<p>Each process maintains a local counter <code>C</code>.</p>
<p><strong>On any local event:</strong> <code>C = C + 1</code></p>
<p><strong>On sending a message:</strong> <code>C = C + 1</code>, send message with timestamp <code>C</code></p>
<p><strong>On receiving a message with timestamp <code>T</code>:</strong> <code>C = max(C, T) + 1</code></p>
<pre><code>Process A (C_A):       Process B (C_B):       Process C (C_C):
C_A = 0                C_B = 0                C_C = 0

Event a1: C_A = 1
Send msg to B (ts=1) →
                       Receive msg (ts=1):
                       C_B = max(0,1)+1 = 2
                       Event b1: C_B = 3
                       Send msg to C (ts=3) →
                                              Receive msg (ts=3):
                                              C_C = max(0,3)+1 = 4
                                              Event c1: C_C = 5

Event a2: C_A = 2
(no message, concurrent with b1)
</code></pre>
<p>From this, we can order: a1(1) &lt; b1(3) &lt; c1(5). And a2(2) is ordered between a1 and b1 in total order, even though a2 is causally independent of b1.</p>
<h3>What Lamport timestamps guarantee</h3>
<p><strong>If A → B, then ts(A) &lt; ts(B).</strong> Always true. This is the useful property: causal ordering is preserved.</p>
<p><strong>If ts(A) &lt; ts(B), we can't conclude A → B.</strong> Not true. Low timestamp might just mean a different process. Two concurrent events on different processes could have any relationship between their timestamps.</p>
<h3>Total order from Lamport timestamps</h3>
<p>Lamport timestamps create a <strong>total order</strong>: any two events can be compared (ts(A) &lt; ts(B) or ts(A) &gt; ts(B) or ts(A) = ts(B) → break ties by process ID). This total order is consistent with the causal partial order (no causal predecessor has a higher timestamp), but it adds arbitrary ordering for concurrent events.</p>
<p>This total order is used by:</p>
<ul>
<li><strong>Distributed mutex algorithms:</strong> agree on the order in which processes acquire a lock using Lamport timestamps</li>
<li><strong>Event log ordering in debugging:</strong> total-order all events across services for incident reconstruction</li>
<li><strong>Serialisable transaction ordering:</strong> CockroachDB uses Hybrid Logical Clocks (HLC) — a Lamport-like structure that combines logical and physical time — for transaction ordering</li>
</ul>
<hr />
<h2>Limitations</h2>
<p><strong>Can't detect concurrency.</strong> The most significant limitation: ts(A) &lt; ts(B) doesn't tell you whether A happened-before B or they were concurrent. To detect concurrency, you need vector clocks (post 12).</p>
<p><strong>Not useful for conflict detection.</strong> If two writes to the same key have different Lamport timestamps, you can order them — but you can't tell if they were concurrent (which would indicate a conflict). Last-write-wins based on Lamport timestamps silently discards one concurrent write without flagging it as a conflict.</p>
<hr />
<h2>The one thing to remember</h2>
<blockquote>
<p><strong>Lamport timestamps give a simple rule: if event A causally preceded event B, A's timestamp is strictly less than B's.</strong> They create a total order consistent with causality, useful for ordering events across services without a global clock. The limitation: they can't detect whether two events with different timestamps are causally related or merely concurrent. For conflict detection, you need vector clocks.</p>
</blockquote>
<hr />
<p><em>← Previous: <strong><a href="/logical-clocks-when-physical-time-isnt-enough">Logical Clocks</a></strong> — in distributed systems, physical clocks can't be trusted; logical clocks capture causal relationships between events instead.</em></p>
<p><em>→ Next: <strong><a href="/vector-clocks-knowing-when-events-are-truly-concurrent">Vector Clocks</a></strong> — extending Lamport timestamps to detect concurrency: when two events are causally independent, vector clocks make that explicit.</em></p>
]]></content:encoded></item><item><title><![CDATA[Logical Clocks: When Physical Time Isn't Enough]]></title><description><![CDATA[Series: System Design · Distributed Systems — Pillar 8 of 8

Systems Design



#
Post
What it covers



00
Distributed Systems: What Happens When Machines Disagree
Twenty concepts covering network par]]></description><link>https://cloudtuned.dev/logical-clocks-when-physical-time-isnt-enough</link><guid isPermaLink="true">https://cloudtuned.dev/logical-clocks-when-physical-time-isnt-enough</guid><category><![CDATA[systemdesign]]></category><category><![CDATA[distributedsystems]]></category><category><![CDATA[logicalclocks]]></category><category><![CDATA[causality]]></category><category><![CDATA[backend]]></category><category><![CDATA[SoftwareDevelopment]]></category><category><![CDATA[softwarearchitecture]]></category><category><![CDATA[engineering]]></category><dc:creator><![CDATA[Cloud Tuned]]></dc:creator><pubDate>Mon, 03 Mar 2025 12:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/602bee9a4bb9c4083f02795d/e7b937ee-cb1f-42cd-ba77-4379d584b151.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote>
<p><strong>Series:</strong> System Design · Distributed Systems — Pillar 8 of 8</p>
</blockquote>
<h2>Systems Design</h2>
<table>
<thead>
<tr>
<th>#</th>
<th>Post</th>
<th>What it covers</th>
</tr>
</thead>
<tbody><tr>
<td>00</td>
<td><a href="/distributed-systems-what-happens-when-machines-disagree">Distributed Systems: What Happens When Machines Disagree</a></td>
<td>Twenty concepts covering network partitions, consensus, clocks, distributed transactions, CDC, erasure coding, and observability. The final pillar.</td>
</tr>
<tr>
<td>01</td>
<td><a href="/network-partitions-the-failure-mode-you-cant-design-away">Network Partitions: The Failure Mode You Can't Design Away</a></td>
<td>Network partitions are inevitable. Learn what happens when nodes can't communicate, how systems choose between availability and consistency, and what that means in practice.</td>
</tr>
<tr>
<td>02</td>
<td><a href="/split-brain-when-two-nodes-both-think-theyre-the-leader">Split-Brain: When Two Nodes Both Think They're the Leader</a></td>
<td>Split-brain occurs when two nodes both believe they're the primary. Learn how it happens, why it causes data corruption, and how STONITH and fencing prevent it.</td>
</tr>
<tr>
<td>03</td>
<td><a href="/heartbeats-how-nodes-know-their-peers-are-alive">Heartbeats: How Nodes Know Their Peers Are Alive</a></td>
<td>Heartbeats let nodes detect peer failures. Learn how timeouts, phi accrual failure detectors, and the tradeoff between false positives and detection speed work.</td>
</tr>
<tr>
<td>04</td>
<td><a href="/leader-election-agreeing-on-whos-in-charge">Leader Election: Agreeing on Who's in Charge</a></td>
<td>Leader election coordinates which node acts as primary. Learn the bully algorithm, Raft-based election, and why exactly-one-leader guarantees are hard to achieve.</td>
</tr>
<tr>
<td>05</td>
<td><a href="/consensus-algorithms-agreeing-on-a-value-across-failures">Consensus Algorithms: Agreeing on a Value Across Failures</a></td>
<td>Consensus lets distributed nodes agree on a value despite failures. Learn what FLP impossibility means, what Paxos and Raft provide, and where consensus is used.</td>
</tr>
<tr>
<td>06</td>
<td><a href="/quorum-how-many-nodes-must-agree">Quorum: How Many Nodes Must Agree?</a></td>
<td>Quorum determines how many nodes must agree for an operation to succeed. Learn how R + W &gt; N ensures consistency in distributed databases like Cassandra and DynamoDB.</td>
</tr>
<tr>
<td>07</td>
<td><a href="/paxos-the-algorithm-that-started-it-all">Paxos: The Algorithm That Started It All</a></td>
<td>Paxos is the foundational distributed consensus algorithm. Learn how its two phases work, why it's hard to implement, and what systems use it in production.</td>
</tr>
<tr>
<td>08</td>
<td><a href="/raft-consensus-made-understandable">Raft: Consensus Made Understandable</a></td>
<td>Raft makes distributed consensus understandable. Learn how leader election, log replication, and safety work in the algorithm that powers etcd, CockroachDB, and TiKV.</td>
</tr>
<tr>
<td>09</td>
<td><a href="/gossip-protocol-decentralised-cluster-communication">Gossip Protocol: Decentralised Cluster Communication</a></td>
<td>Gossip protocols propagate information across a cluster without a central coordinator. Learn how epidemic spreading works and where it's used in production.</td>
</tr>
<tr>
<td>10</td>
<td><strong>Logical Clocks: When Physical Time Isn't Enough</strong> ← you are here</td>
<td>Physical clocks drift and can't establish event order in distributed systems. Logical clocks track causality instead. Learn why this matters and how it works.</td>
</tr>
<tr>
<td>11</td>
<td><a href="/lamport-timestamps-ordering-events-without-a-global-clock">Lamport Timestamps: Ordering Events Without a Global Clock</a></td>
<td>Lamport timestamps assign logical counters to events to establish causal order in distributed systems. Learn how they work and what they can and can't tell you.</td>
</tr>
<tr>
<td>12</td>
<td><a href="/vector-clocks-knowing-when-events-are-truly-concurrent">Vector Clocks: Knowing When Events Are Truly Concurrent</a></td>
<td>Vector clocks detect causality and concurrency in distributed systems. Learn how they work, how Dynamo uses them for conflict detection, and their limitations.</td>
</tr>
<tr>
<td>13</td>
<td><a href="/distributed-transactions-when-one-machine-isnt-enough">Distributed Transactions: When One Machine Isn't Enough</a></td>
<td>Distributed transactions are hard. Learn why cross-service atomicity is expensive, when to use it, and when eventual consistency is the right alternative.</td>
</tr>
<tr>
<td>14</td>
<td><a href="/two-phase-commit-coordinating-a-distributed-decision">Two-Phase Commit: Coordinating a Distributed Decision</a></td>
<td>2PC ensures distributed atomicity through prepare and commit phases. Learn how it works, the coordinator failure problem, and why it's rarely used in modern systems.</td>
</tr>
<tr>
<td>15</td>
<td><a href="/three-phase-commit-solving-2pcs-blocking-problem">Three-Phase Commit: Solving 2PC's Blocking Problem</a></td>
<td>3PC adds a pre-commit phase to eliminate 2PC's blocking problem. Learn how it works, what assumptions it requires, and why it's rarely used in production.</td>
</tr>
<tr>
<td>16</td>
<td><a href="/delivery-semantics-what-does-delivered-actually-mean">Delivery Semantics: What Does "Delivered" Actually Mean?</a></td>
<td>Message delivery guarantees define system reliability. Learn what at-most-once, at-least-once, and exactly-once mean, what they cost, and when each is appropriate.</td>
</tr>
<tr>
<td>17</td>
<td><a href="/change-data-capture-streaming-your-database-in-real-time">Change Data Capture: Streaming Your Database in Real Time</a></td>
<td>CDC streams database changes in real time by reading the write-ahead log. Learn how Debezium works, what CDC enables, and when to use it.</td>
</tr>
<tr>
<td>18</td>
<td><a href="/erasure-coding-fault-tolerance-without-full-replication">Erasure Coding: Fault Tolerance Without Full Replication</a></td>
<td>Erasure coding stores data across nodes using math, not full replication. Learn how Reed-Solomon works, how S3 uses it, and when it beats 3x replication.</td>
</tr>
<tr>
<td>19</td>
<td><a href="/merkle-trees-efficiently-finding-whats-different">Merkle Trees: Efficiently Finding What's Different</a></td>
<td>Merkle trees efficiently detect which parts of a large dataset differ between nodes. Learn how Bitcoin, Cassandra, and Git use them for verification and anti-entropy.</td>
</tr>
<tr>
<td>20</td>
<td><a href="/observability-understanding-your-system-at-runtime">Observability: Understanding Your System at Runtime</a></td>
<td>Logs, metrics, and distributed traces are how you understand a system at runtime. Learn what each pillar provides, the tools involved, and how they work together.</td>
</tr>
<tr>
<td>21</td>
<td><a href="/distributed-systems-wrap-up">Distributed Systems: Wrap-Up</a></td>
<td>A recap of all 20 distributed systems concepts and the complete URL shortener architecture spanning all 8 pillars. The final post in the series.</td>
</tr>
</tbody></table>
<hr />
<h1>Logical Clocks: When Physical Time Isn't Enough</h1>
<h2>The problem</h2>
<p>Your URL shortener's Analytics Service runs on three servers. Each server has a real-time clock. Server A says it's 14:00:00.000. Server B says it's 14:00:00.003. Server C says it's 13:59:59.997.</p>
<p>These three clocks disagree by a few milliseconds. That seems fine — until you need to order events:</p>
<ul>
<li>Server A records a click at 14:00:00.001</li>
<li>Server C records the same link's metadata update at 13:59:59.998</li>
</ul>
<p>Based on physical timestamps, the metadata update (C, 13:59:59.998) happened <em>before</em> the click (A, 14:00:00.001). But in reality, the metadata update was <em>triggered by</em> a notification that included information from the click — the click caused the update, not the other way around.</p>
<p>Physical clocks in distributed systems drift. NTP can synchronise them to within a few milliseconds, but "a few milliseconds" matters when events happen microseconds apart on different machines. You cannot rely on physical timestamps to establish causal order between events on different machines.</p>
<p>This is the problem logical clocks solve.</p>
<hr />
<h2>The core idea</h2>
<p>A logical clock doesn't measure real time — it measures <strong>causal order</strong>: whether one event happened-before another. The fundamental insight from Leslie Lamport's 1978 paper: if event A caused event B (A's message was received by the process that executed B), then A happened-before B. If A and B are on different machines with no causal connection, they are <strong>concurrent</strong> — neither happened before the other, regardless of their physical timestamps.</p>
<hr />
<h2>The analogy: chapter numbers in a book exchange</h2>
<p>Two authors are collaborating on a book, each writing different chapters and emailing drafts to each other. The emails take random amounts of time to arrive.</p>
<p>Author A writes Chapter 3, then emails it to Author B. Author B reads it and responds with Chapter 4, which incorporates Chapter 3's ideas. A simple fact: Chapter 4 happened-after Chapter 3 — not because the clock says so, but because Chapter 4 causally depends on Chapter 3.</p>
<p>If Author C (who wasn't in the exchange) writes Chapter 5 independently at the same time, Chapter 5 is concurrent with Chapter 3 and Chapter 4 — neither happened-before the other in the causal sense.</p>
<p>Logical clocks are chapter numbers: they track the causal chain of revisions, not wall-clock time.</p>
<hr />
<h2>The happened-before relation</h2>
<p>Lamport defined the happened-before relation (→) with three rules:</p>
<ol>
<li><strong>Within one process:</strong> if event A occurs before event B in the same process, then A → B</li>
<li><strong>Message passing:</strong> if A is the sending of a message and B is the receipt of that message, then A → B</li>
<li><strong>Transitivity:</strong> if A → B and B → C, then A → C</li>
</ol>
<p>Events that are neither A → B nor B → A are <strong>concurrent</strong> (written A ‖ B).</p>
<p>This relation is a partial order — not every pair of events is ordered. Concurrent events have no meaningful "before/after" relationship.</p>
<h3>Why this matters</h3>
<p><strong>Conflict resolution:</strong> in Cassandra, if two writes to the same key are concurrent (neither happened-before the other), it's a conflict. Last-write-wins (using timestamps) may silently discard one. Vector clocks can detect this and surface the conflict for application-level resolution.</p>
<p><strong>Debugging distributed systems:</strong> reconstructing the causal chain of events in a distributed incident requires happened-before order, not just physical timestamps. "This cache miss happened before that database query" is a causal statement, not a temporal one.</p>
<p><strong>Consistency in replicated systems:</strong> when a client reads its own writes, the system must guarantee it sees events that happened-after its writes — not just events that have a later physical timestamp.</p>
<hr />
<h2>Partial vs total order</h2>
<p>Physical clocks give a <strong>total order</strong>: every event has a wall-clock time, and times can always be compared. The problem: the comparison is unreliable (clocks drift) and doesn't reflect causality.</p>
<p>Happened-before gives a <strong>partial order</strong>: some events are ordered (causally related), others are concurrent (no causal relationship). More accurate but doesn't order everything.</p>
<p>Logical clock implementations (Lamport timestamps, vector clocks) bridge the gap:</p>
<ul>
<li><strong>Lamport timestamps:</strong> extend partial order to total order by breaking ties arbitrarily. Simple, but can't detect concurrency.</li>
<li><strong>Vector clocks:</strong> preserve partial order, detect concurrency explicitly. More complex, but more informative.</li>
</ul>
<hr />
<h2>The one thing to remember</h2>
<blockquote>
<p><strong>Physical clocks can't reliably establish causal order in distributed systems — they drift, and milliseconds of disagreement matter.</strong> Logical clocks track causal relationships instead: if A caused B (via message passing or within a process), A happened-before B. This partial order is what distributed systems actually need for correctness: detecting conflicts, establishing read-your-writes guarantees, and reconstructing event causality in debugging. Lamport timestamps and vector clocks (the next two posts) are the concrete implementations of this idea.</p>
</blockquote>
<hr />
<p><em>← Previous: <strong><a href="/gossip-protocol-decentralised-cluster-communication">Gossip Protocol</a></strong> — decentralised cluster membership and state propagation without a leader or consensus.</em></p>
<p><em>→ Next: <strong><a href="/lamport-timestamps-ordering-events-without-a-global-clock">Lamport Timestamps</a></strong> — the simplest logical clock: assigning monotonic integers to events to capture causal order.</em></p>
]]></content:encoded></item><item><title><![CDATA[Gossip Protocol: Decentralised Cluster Communication]]></title><description><![CDATA[Series: System Design · Distributed Systems — Pillar 8 of 8

Systems Design



#
Post
What it covers



00
Distributed Systems: What Happens When Machines Disagree
Twenty concepts covering network par]]></description><link>https://cloudtuned.dev/gossip-protocol-decentralised-cluster-communication</link><guid isPermaLink="true">https://cloudtuned.dev/gossip-protocol-decentralised-cluster-communication</guid><category><![CDATA[systemdesign]]></category><category><![CDATA[distributedsystems]]></category><category><![CDATA[gossip]]></category><category><![CDATA[Cassandra]]></category><category><![CDATA[consul]]></category><category><![CDATA[backend]]></category><category><![CDATA[SoftwareDevelopment]]></category><category><![CDATA[softwarearchitecture]]></category><category><![CDATA[engineering]]></category><dc:creator><![CDATA[Cloud Tuned]]></dc:creator><pubDate>Sun, 02 Mar 2025 12:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/602bee9a4bb9c4083f02795d/fac34161-38be-4459-a684-1afd9259231d.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote>
<p><strong>Series:</strong> System Design · Distributed Systems — Pillar 8 of 8</p>
</blockquote>
<h2>Systems Design</h2>
<table>
<thead>
<tr>
<th>#</th>
<th>Post</th>
<th>What it covers</th>
</tr>
</thead>
<tbody><tr>
<td>00</td>
<td><a href="/distributed-systems-what-happens-when-machines-disagree">Distributed Systems: What Happens When Machines Disagree</a></td>
<td>Twenty concepts covering network partitions, consensus, clocks, distributed transactions, CDC, erasure coding, and observability. The final pillar.</td>
</tr>
<tr>
<td>01</td>
<td><a href="/network-partitions-the-failure-mode-you-cant-design-away">Network Partitions: The Failure Mode You Can't Design Away</a></td>
<td>Network partitions are inevitable. Learn what happens when nodes can't communicate, how systems choose between availability and consistency, and what that means in practice.</td>
</tr>
<tr>
<td>02</td>
<td><a href="/split-brain-when-two-nodes-both-think-theyre-the-leader">Split-Brain: When Two Nodes Both Think They're the Leader</a></td>
<td>Split-brain occurs when two nodes both believe they're the primary. Learn how it happens, why it causes data corruption, and how STONITH and fencing prevent it.</td>
</tr>
<tr>
<td>03</td>
<td><a href="/heartbeats-how-nodes-know-their-peers-are-alive">Heartbeats: How Nodes Know Their Peers Are Alive</a></td>
<td>Heartbeats let nodes detect peer failures. Learn how timeouts, phi accrual failure detectors, and the tradeoff between false positives and detection speed work.</td>
</tr>
<tr>
<td>04</td>
<td><a href="/leader-election-agreeing-on-whos-in-charge">Leader Election: Agreeing on Who's in Charge</a></td>
<td>Leader election coordinates which node acts as primary. Learn the bully algorithm, Raft-based election, and why exactly-one-leader guarantees are hard to achieve.</td>
</tr>
<tr>
<td>05</td>
<td><a href="/consensus-algorithms-agreeing-on-a-value-across-failures">Consensus Algorithms: Agreeing on a Value Across Failures</a></td>
<td>Consensus lets distributed nodes agree on a value despite failures. Learn what FLP impossibility means, what Paxos and Raft provide, and where consensus is used.</td>
</tr>
<tr>
<td>06</td>
<td><a href="/quorum-how-many-nodes-must-agree">Quorum: How Many Nodes Must Agree?</a></td>
<td>Quorum determines how many nodes must agree for an operation to succeed. Learn how R + W &gt; N ensures consistency in distributed databases like Cassandra and DynamoDB.</td>
</tr>
<tr>
<td>07</td>
<td><a href="/paxos-the-algorithm-that-started-it-all">Paxos: The Algorithm That Started It All</a></td>
<td>Paxos is the foundational distributed consensus algorithm. Learn how its two phases work, why it's hard to implement, and what systems use it in production.</td>
</tr>
<tr>
<td>08</td>
<td><a href="/raft-consensus-made-understandable">Raft: Consensus Made Understandable</a></td>
<td>Raft makes distributed consensus understandable. Learn how leader election, log replication, and safety work in the algorithm that powers etcd, CockroachDB, and TiKV.</td>
</tr>
<tr>
<td>09</td>
<td><strong>Gossip Protocol: Decentralised Cluster Communication</strong> ← you are here</td>
<td>Gossip protocols propagate information across a cluster without a central coordinator. Learn how epidemic spreading works and where it's used in production.</td>
</tr>
<tr>
<td>10</td>
<td><a href="/logical-clocks-when-physical-time-isnt-enough">Logical Clocks: When Physical Time Isn't Enough</a></td>
<td>Physical clocks drift and can't establish event order in distributed systems. Logical clocks track causality instead. Learn why this matters and how it works.</td>
</tr>
<tr>
<td>11</td>
<td><a href="/lamport-timestamps-ordering-events-without-a-global-clock">Lamport Timestamps: Ordering Events Without a Global Clock</a></td>
<td>Lamport timestamps assign logical counters to events to establish causal order in distributed systems. Learn how they work and what they can and can't tell you.</td>
</tr>
<tr>
<td>12</td>
<td><a href="/vector-clocks-knowing-when-events-are-truly-concurrent">Vector Clocks: Knowing When Events Are Truly Concurrent</a></td>
<td>Vector clocks detect causality and concurrency in distributed systems. Learn how they work, how Dynamo uses them for conflict detection, and their limitations.</td>
</tr>
<tr>
<td>13</td>
<td><a href="/distributed-transactions-when-one-machine-isnt-enough">Distributed Transactions: When One Machine Isn't Enough</a></td>
<td>Distributed transactions are hard. Learn why cross-service atomicity is expensive, when to use it, and when eventual consistency is the right alternative.</td>
</tr>
<tr>
<td>14</td>
<td><a href="/two-phase-commit-coordinating-a-distributed-decision">Two-Phase Commit: Coordinating a Distributed Decision</a></td>
<td>2PC ensures distributed atomicity through prepare and commit phases. Learn how it works, the coordinator failure problem, and why it's rarely used in modern systems.</td>
</tr>
<tr>
<td>15</td>
<td><a href="/three-phase-commit-solving-2pcs-blocking-problem">Three-Phase Commit: Solving 2PC's Blocking Problem</a></td>
<td>3PC adds a pre-commit phase to eliminate 2PC's blocking problem. Learn how it works, what assumptions it requires, and why it's rarely used in production.</td>
</tr>
<tr>
<td>16</td>
<td><a href="/delivery-semantics-what-does-delivered-actually-mean">Delivery Semantics: What Does "Delivered" Actually Mean?</a></td>
<td>Message delivery guarantees define system reliability. Learn what at-most-once, at-least-once, and exactly-once mean, what they cost, and when each is appropriate.</td>
</tr>
<tr>
<td>17</td>
<td><a href="/change-data-capture-streaming-your-database-in-real-time">Change Data Capture: Streaming Your Database in Real Time</a></td>
<td>CDC streams database changes in real time by reading the write-ahead log. Learn how Debezium works, what CDC enables, and when to use it.</td>
</tr>
<tr>
<td>18</td>
<td><a href="/erasure-coding-fault-tolerance-without-full-replication">Erasure Coding: Fault Tolerance Without Full Replication</a></td>
<td>Erasure coding stores data across nodes using math, not full replication. Learn how Reed-Solomon works, how S3 uses it, and when it beats 3x replication.</td>
</tr>
<tr>
<td>19</td>
<td><a href="/merkle-trees-efficiently-finding-whats-different">Merkle Trees: Efficiently Finding What's Different</a></td>
<td>Merkle trees efficiently detect which parts of a large dataset differ between nodes. Learn how Bitcoin, Cassandra, and Git use them for verification and anti-entropy.</td>
</tr>
<tr>
<td>20</td>
<td><a href="/observability-understanding-your-system-at-runtime">Observability: Understanding Your System at Runtime</a></td>
<td>Logs, metrics, and distributed traces are how you understand a system at runtime. Learn what each pillar provides, the tools involved, and how they work together.</td>
</tr>
<tr>
<td>21</td>
<td><a href="/distributed-systems-wrap-up">Distributed Systems: Wrap-Up</a></td>
<td>A recap of all 20 distributed systems concepts and the complete URL shortener architecture spanning all 8 pillars. The final post in the series.</td>
</tr>
</tbody></table>
<hr />
<h1>Gossip Protocol: Decentralised Cluster Communication</h1>
<h2>The problem</h2>
<p>Your Cassandra cluster has 100 nodes. Each node needs to know the health status of every other node — which are alive, which are dead, which are handling which token ranges. With 100 nodes, that's each node needing updates from 99 others.</p>
<p>A centralised approach: one coordinator node receives status from all nodes and broadcasts updates. The coordinator is a single point of failure and a bottleneck for a 100-node cluster.</p>
<p>A direct broadcast: each node broadcasts its status to all 99 others. With 100 nodes sending 99 messages each per second, that's 9,900 messages per second — fine at 100 nodes, but quadratically worse as the cluster grows. A 1,000-node cluster would generate nearly a million messages per second just for status updates.</p>
<p>Gossip protocols solve this with a different model: each node only talks to a few random peers, but information spreads exponentially fast across the cluster through the chain of random communications.</p>
<hr />
<h2>The core idea</h2>
<p>A gossip protocol (also called epidemic protocol) propagates information through a cluster by having each node periodically select a small number of random peers and exchange information with them. Like a rumour spreading through a social network, information reaches every node in O(log N) rounds — logarithmically fast — without any central coordinator and without each node communicating with all others directly.</p>
<hr />
<h2>The analogy: rumour spreading through a school</h2>
<p>A rumour starts with one student. Every few minutes, each student who knows the rumour tells a randomly selected other student. After one round, 2 students know. After two rounds, ~4 know. After three rounds, ~8. After about 7 rounds (log₂(100)), essentially everyone knows.</p>
<p>No one is in charge. No one coordinates who tells whom. The rumour spreads naturally through random pairwise contact. This is gossip: decentralised, scalable, resilient. If a few students are absent, the rumour still spreads — it just takes one extra round to route around them. Check our interactive diagram below:</p>
<hr />
<h2>How gossip works</h2>
<h3>The basic mechanism</h3>
<p>Every T seconds (typically 1 second), each node:</p>
<ol>
<li><p>Selects 1–3 random peers from its known cluster membership</p>
</li>
<li><p>Sends its current state vector to those peers</p>
</li>
<li><p>Receives their state in return</p>
</li>
<li><p>Updates its local view of cluster state with anything newer than what it already has</p>
</li>
</ol>
<pre><code class="language-plaintext">Node A gossips with Node B:
  A sends: {A: (alive, generation=5, version=42), C: (alive, gen=3, ver=19)}
  B sends: {B: (alive, gen=4, ver=31), C: (alive, gen=3, ver=20), D: (suspected, gen=2)}

After exchange:
  A now knows: B is at version 31, C is at version 20 (newer than 19), D is suspected
  B now knows: A is at version 42
</code></pre>
<p>The <strong>version number</strong> (or generation+version pair) identifies the currency of each node's information about every other node. Higher version = more recent.</p>
<h3>Convergence rate</h3>
<p>In a cluster of N nodes with each node gossiping with k peers per round, new information reaches all nodes within O(log_k(N)) rounds. For k=3 and N=100: log₃(100) ≈ 4.2 rounds. With 1-second gossip intervals, the entire cluster learns new state within ~5 seconds.</p>
<p>This is remarkably efficient: 100 nodes, each sending 3 messages per second = 300 total messages per second for cluster-wide state propagation — constant, regardless of cluster size growth to moderate scales.</p>
<h3>Failure detection via gossip</h3>
<p>Cassandra uses gossip for failure detection in combination with heartbeats:</p>
<ul>
<li><p>Each node gossips its own heartbeat counter (incrementing every second) to its peers</p>
</li>
<li><p>If a peer's heartbeat counter hasn't increased in the expected time, its "phi" suspicion level rises (the phi accrual detector from post 03)</p>
</li>
<li><p>When φ exceeds a threshold, the node is marked as suspected, then down</p>
</li>
</ul>
<p>Marking a node down propagates through gossip: node A marks B as down, gossips to C and D, who update their views and gossip to E and F. Within seconds, the whole cluster considers B down.</p>
<h3>What gossip is used for</h3>
<p><strong>Cluster membership:</strong> which nodes are in the cluster, which are healthy, which are joining or leaving. Cassandra, Redis Cluster, Consul.</p>
<p><strong>Ring topology in consistent hashing:</strong> when a node joins or leaves the Cassandra cluster, its token assignments propagate via gossip. Within seconds, all nodes know the updated ring.</p>
<p><strong>Data anti-entropy (Cassandra):</strong> Cassandra periodically gossips about Merkle tree hashes of its data to identify and repair inconsistencies between replicas (covered in post 19).</p>
<p><strong>Service health in Consul:</strong> Consul agents gossip health check results. A failing service's unhealthiness propagates to all agents within seconds without any central coordinator.</p>
<hr />
<h2>Tradeoffs</h2>
<p><strong>Eventual consistency of the cluster view.</strong> Gossip doesn't provide strong consistency — there's always a brief window where different nodes have different views of cluster state. A node that was just marked down may still be in some nodes' "alive" view for a few seconds. This is acceptable for membership and health propagation; it's not suitable for consensus or coordination decisions (use Raft/Paxos for those).</p>
<p><strong>Bandwidth scales with state size, not cluster size.</strong> Each gossip message carries the state of the sender's view of the cluster. If each node stores metadata about N other nodes, gossip messages grow with N. For very large clusters (thousands of nodes), this can become expensive. Solutions: cap the amount of state included per gossip round, or use hierarchical gossip (gossip within a zone, then between zones).</p>
<p><strong>No total ordering.</strong> Gossip delivers information eventually but not in any guaranteed order. If two events happen simultaneously on different nodes, different nodes may learn about them in different orders. This is fine for membership changes; it's not acceptable for ordered log replication.</p>
<hr />
<h2>The one thing to remember</h2>
<blockquote>
<p><strong>Gossip protocols spread information across a cluster in O(log N) rounds by having each node exchange state with a few random peers — no central coordinator, no single point of failure.</strong> Each individual exchange is cheap; the collective effect is rapid, resilient propagation. Cassandra, Redis Cluster, and Consul all use gossip for cluster membership because it scales naturally, tolerates node failures, and requires no dedicated coordination infrastructure. The cost: eventual consistency of the cluster view, not instantaneous agreement.</p>
</blockquote>
<hr />
<p><em>← Previous:</em> <a href="/raft-consensus-made-understandable"><em><strong>Raft</strong></em></a> <em>— the consensus algorithm designed for understandability; the most important one to know in practice.</em></p>
<p><em>→ Next:</em> <a href="/logical-clocks-when-physical-time-isnt-enough"><em><strong>Logical Clocks</strong></em></a> <em>— in distributed systems, physical clocks can't be trusted; logical clocks capture causal relationships between events instead.</em></p>
]]></content:encoded></item><item><title><![CDATA[Raft: Consensus Made Understandable]]></title><description><![CDATA[Series: System Design · Distributed Systems — Pillar 8 of 8

Systems Design



#
Post
What it covers



00
Distributed Systems: What Happens When Machines Disagree
Twenty concepts covering network par]]></description><link>https://cloudtuned.dev/raft-consensus-made-understandable</link><guid isPermaLink="true">https://cloudtuned.dev/raft-consensus-made-understandable</guid><category><![CDATA[systemdesign]]></category><category><![CDATA[distributedsystems]]></category><category><![CDATA[raft]]></category><category><![CDATA[Consensus]]></category><category><![CDATA[etcd]]></category><category><![CDATA[backend]]></category><category><![CDATA[SoftwareDevelopment]]></category><category><![CDATA[softwarearchitecture]]></category><category><![CDATA[engineering]]></category><dc:creator><![CDATA[Cloud Tuned]]></dc:creator><pubDate>Sat, 01 Mar 2025 12:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/602bee9a4bb9c4083f02795d/8049af9f-2ef1-434a-8612-5478d6d6ac48.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote>
<p><strong>Series:</strong> System Design · Distributed Systems — Pillar 8 of 8</p>
</blockquote>
<h2>Systems Design</h2>
<table>
<thead>
<tr>
<th>#</th>
<th>Post</th>
<th>What it covers</th>
</tr>
</thead>
<tbody><tr>
<td>00</td>
<td><a href="/distributed-systems-what-happens-when-machines-disagree">Distributed Systems: What Happens When Machines Disagree</a></td>
<td>Twenty concepts covering network partitions, consensus, clocks, distributed transactions, CDC, erasure coding, and observability. The final pillar.</td>
</tr>
<tr>
<td>01</td>
<td><a href="/network-partitions-the-failure-mode-you-cant-design-away">Network Partitions: The Failure Mode You Can't Design Away</a></td>
<td>Network partitions are inevitable. Learn what happens when nodes can't communicate, how systems choose between availability and consistency, and what that means in practice.</td>
</tr>
<tr>
<td>02</td>
<td><a href="/split-brain-when-two-nodes-both-think-theyre-the-leader">Split-Brain: When Two Nodes Both Think They're the Leader</a></td>
<td>Split-brain occurs when two nodes both believe they're the primary. Learn how it happens, why it causes data corruption, and how STONITH and fencing prevent it.</td>
</tr>
<tr>
<td>03</td>
<td><a href="/heartbeats-how-nodes-know-their-peers-are-alive">Heartbeats: How Nodes Know Their Peers Are Alive</a></td>
<td>Heartbeats let nodes detect peer failures. Learn how timeouts, phi accrual failure detectors, and the tradeoff between false positives and detection speed work.</td>
</tr>
<tr>
<td>04</td>
<td><a href="/leader-election-agreeing-on-whos-in-charge">Leader Election: Agreeing on Who's in Charge</a></td>
<td>Leader election coordinates which node acts as primary. Learn the bully algorithm, Raft-based election, and why exactly-one-leader guarantees are hard to achieve.</td>
</tr>
<tr>
<td>05</td>
<td><a href="/consensus-algorithms-agreeing-on-a-value-across-failures">Consensus Algorithms: Agreeing on a Value Across Failures</a></td>
<td>Consensus lets distributed nodes agree on a value despite failures. Learn what FLP impossibility means, what Paxos and Raft provide, and where consensus is used.</td>
</tr>
<tr>
<td>06</td>
<td><a href="/quorum-how-many-nodes-must-agree">Quorum: How Many Nodes Must Agree?</a></td>
<td>Quorum determines how many nodes must agree for an operation to succeed. Learn how R + W &gt; N ensures consistency in distributed databases like Cassandra and DynamoDB.</td>
</tr>
<tr>
<td>07</td>
<td><a href="/paxos-the-algorithm-that-started-it-all">Paxos: The Algorithm That Started It All</a></td>
<td>Paxos is the foundational distributed consensus algorithm. Learn how its two phases work, why it's hard to implement, and what systems use it in production.</td>
</tr>
<tr>
<td>08</td>
<td><strong>Raft: Consensus Made Understandable</strong> ← you are here</td>
<td>Raft makes distributed consensus understandable. Learn how leader election, log replication, and safety work in the algorithm that powers etcd, CockroachDB, and TiKV.</td>
</tr>
<tr>
<td>09</td>
<td><a href="/gossip-protocol-decentralised-cluster-communication">Gossip Protocol: Decentralised Cluster Communication</a></td>
<td>Gossip protocols propagate information across a cluster without a central coordinator. Learn how epidemic spreading works and where it's used in production.</td>
</tr>
<tr>
<td>10</td>
<td><a href="/logical-clocks-when-physical-time-isnt-enough">Logical Clocks: When Physical Time Isn't Enough</a></td>
<td>Physical clocks drift and can't establish event order in distributed systems. Logical clocks track causality instead. Learn why this matters and how it works.</td>
</tr>
<tr>
<td>11</td>
<td><a href="/lamport-timestamps-ordering-events-without-a-global-clock">Lamport Timestamps: Ordering Events Without a Global Clock</a></td>
<td>Lamport timestamps assign logical counters to events to establish causal order in distributed systems. Learn how they work and what they can and can't tell you.</td>
</tr>
<tr>
<td>12</td>
<td><a href="/vector-clocks-knowing-when-events-are-truly-concurrent">Vector Clocks: Knowing When Events Are Truly Concurrent</a></td>
<td>Vector clocks detect causality and concurrency in distributed systems. Learn how they work, how Dynamo uses them for conflict detection, and their limitations.</td>
</tr>
<tr>
<td>13</td>
<td><a href="/distributed-transactions-when-one-machine-isnt-enough">Distributed Transactions: When One Machine Isn't Enough</a></td>
<td>Distributed transactions are hard. Learn why cross-service atomicity is expensive, when to use it, and when eventual consistency is the right alternative.</td>
</tr>
<tr>
<td>14</td>
<td><a href="/two-phase-commit-coordinating-a-distributed-decision">Two-Phase Commit: Coordinating a Distributed Decision</a></td>
<td>2PC ensures distributed atomicity through prepare and commit phases. Learn how it works, the coordinator failure problem, and why it's rarely used in modern systems.</td>
</tr>
<tr>
<td>15</td>
<td><a href="/three-phase-commit-solving-2pcs-blocking-problem">Three-Phase Commit: Solving 2PC's Blocking Problem</a></td>
<td>3PC adds a pre-commit phase to eliminate 2PC's blocking problem. Learn how it works, what assumptions it requires, and why it's rarely used in production.</td>
</tr>
<tr>
<td>16</td>
<td><a href="/delivery-semantics-what-does-delivered-actually-mean">Delivery Semantics: What Does "Delivered" Actually Mean?</a></td>
<td>Message delivery guarantees define system reliability. Learn what at-most-once, at-least-once, and exactly-once mean, what they cost, and when each is appropriate.</td>
</tr>
<tr>
<td>17</td>
<td><a href="/change-data-capture-streaming-your-database-in-real-time">Change Data Capture: Streaming Your Database in Real Time</a></td>
<td>CDC streams database changes in real time by reading the write-ahead log. Learn how Debezium works, what CDC enables, and when to use it.</td>
</tr>
<tr>
<td>18</td>
<td><a href="/erasure-coding-fault-tolerance-without-full-replication">Erasure Coding: Fault Tolerance Without Full Replication</a></td>
<td>Erasure coding stores data across nodes using math, not full replication. Learn how Reed-Solomon works, how S3 uses it, and when it beats 3x replication.</td>
</tr>
<tr>
<td>19</td>
<td><a href="/merkle-trees-efficiently-finding-whats-different">Merkle Trees: Efficiently Finding What's Different</a></td>
<td>Merkle trees efficiently detect which parts of a large dataset differ between nodes. Learn how Bitcoin, Cassandra, and Git use them for verification and anti-entropy.</td>
</tr>
<tr>
<td>20</td>
<td><a href="/observability-understanding-your-system-at-runtime">Observability: Understanding Your System at Runtime</a></td>
<td>Logs, metrics, and distributed traces are how you understand a system at runtime. Learn what each pillar provides, the tools involved, and how they work together.</td>
</tr>
<tr>
<td>21</td>
<td><a href="/distributed-systems-wrap-up">Distributed Systems: Wrap-Up</a></td>
<td>A recap of all 20 distributed systems concepts and the complete URL shortener architecture spanning all 8 pillars. The final post in the series.</td>
</tr>
</tbody></table>
<hr />
<h1>Raft: Consensus Made Understandable</h1>
<h2>The problem</h2>
<p>Paxos is correct. It is also notoriously difficult to understand, implement correctly, and explain to engineers who need to reason about the systems built on it. In a 2014 research paper, Diego Ongaro and John Ousterhout described this plainly: they surveyed graduate students and found Paxos was widely considered "opaque and difficult." They designed Raft with one primary goal: understandability.</p>
<p>The result is an algorithm that provides the same safety guarantees as Paxos with a structure that engineers can explain, implement, and debug. Raft is now the most widely used consensus algorithm in production systems: etcd, CockroachDB, TiKV, Consul, and CockroachDB all use Raft. Kubernetes depends on etcd. Half the distributed databases shipped in the last decade depend on Raft.</p>
<div class="hn-embed-widget" id="raft-properties-widget"></div>

<hr />
<h2>The core idea</h2>
<p>Raft decomposes consensus into three relatively independent subproblems: <strong>leader election</strong> (choosing one node to coordinate), <strong>log replication</strong> (the leader accepts entries and replicates them to followers), and <strong>safety</strong> (ensuring no two nodes ever commit different values at the same log index). Each subproblem is tractable independently; together they provide a complete consensus protocol.</p>
<hr />
<h2>The analogy: a parliamentary legislature with a speaker</h2>
<p>A parliament has a Speaker (the leader) who controls the floor. Only the Speaker can introduce legislation (log entries). When the Speaker proposes a bill, members vote to pass it or not. If the majority pass it, it becomes law (committed). If the Speaker is absent, parliament elects a new Speaker before proceeding.</p>
<p>The legislature's rule: all laws are passed in the order the Speaker introduced them. No law is rescinded once passed. If the Speaker changes, the new Speaker inherits all previously passed laws and introduces new ones from where the old Speaker left off.</p>
<p>This is Raft's model, exactly.</p>
<hr />
<h2>How Raft works</h2>
<h3>Terms</h3>
<p>Raft uses <strong>terms</strong> — monotonically increasing logical time units — to distinguish legitimate leaders from stale ones. Each election starts a new term. A node that receives a message with a higher term immediately updates its term and reverts to follower. This prevents an old leader from reasserting authority after recovering from a partition.</p>
<h3>Leader election</h3>
<p>All nodes start as <strong>followers</strong>. A follower that doesn't receive a heartbeat from the leader within <code>electionTimeout</code> becomes a <strong>candidate</strong> and starts an election:</p>
<ol>
<li><p>Increments its term</p>
</li>
<li><p>Votes for itself</p>
</li>
<li><p>Sends <code>RequestVote</code> RPCs to all other nodes</p>
</li>
</ol>
<p>A node grants its vote if: it hasn't voted in this term yet, AND the candidate's log is at least as up-to-date as its own (more recent last entry term, or same term and longer log).</p>
<p>The candidate wins if it receives votes from a majority (⌊N/2⌋ + 1 of N nodes, including itself). It immediately begins sending heartbeats to prevent new elections.</p>
<p>If no candidate wins (split vote), the election times out and a new election starts with a higher term. Randomised election timeouts (each node picks a random delay before starting a candidacy) break ties and ensure elections converge quickly.</p>
<h3>Log replication</h3>
<p>The leader accepts client commands and appends them to its log as new entries. Each entry has an index, term number, and the command.</p>
<p>The leader sends <code>AppendEntries</code> RPCs to all followers with the new entry. Followers append the entry if it's consistent with their log (the entry before it matches). The leader waits for a majority of nodes to acknowledge the entry.</p>
<p>Once a majority acknowledge, the entry is <strong>committed</strong> — it will survive any future leader changes. The leader applies the entry to its state machine and returns the result to the client.</p>
<pre><code class="language-plaintext">Log:
Index: 1    2    3    4    5
Term:  1    1    2    2    2
Cmd:   w1   w2   w3   w4   w5 (uncommitted)
                  ↑
           commit index (majority acknowledged through here)
</code></pre>
<p>Followers learn the commit index via subsequent <code>AppendEntries</code> RPCs and apply committed entries to their state machines.</p>
<h3>Log consistency guarantee</h3>
<p>Raft maintains a critical invariant: <strong>if two logs have the same term and index for an entry, all preceding entries are identical.</strong> This is enforced by the consistency check in <code>AppendEntries</code>: before accepting a new entry, the follower verifies that the entry immediately before it matches (same term, same index). If not, it rejects the append — the leader re-sends earlier entries until consistency is established.</p>
<h3>Safety: the log matching property</h3>
<p>A key safety property: <strong>Raft never allows two different committed entries at the same log index.</strong> This follows from:</p>
<ol>
<li><p>Only one leader per term (from the election guarantee)</p>
</li>
<li><p>A leader never overwrites committed entries — it only appends</p>
</li>
<li><p>The vote restriction: a candidate can only win if its log is at least as up-to-date as any voter's — ensuring the winner has all committed entries</p>
</li>
</ol>
<p>These three properties together guarantee no two nodes ever commit different values at the same index.</p>
<h3>Leader changes and log reconciliation</h3>
<p>When a new leader is elected, its log may be behind followers' logs (it wasn't the most recent leader). Raft's approach: the new leader's log is authoritative. Followers that have entries beyond the leader's log have those entries overwritten (they were never committed — committed entries survive leader changes; uncommitted ones may not).</p>
<p>The leader sends its log to each follower, which the follower matches against its own and overwrites any divergent tail.</p>
<hr />
<h2>Raft in etcd: the Kubernetes brain</h2>
<p>Kubernetes stores all cluster state in etcd — pod specs, service definitions, configuration, secrets. etcd uses Raft for its replicated log. Every etcd write goes through Raft's commit process: proposed to the leader, replicated to followers, committed when a majority acknowledge.</p>
<p>An etcd cluster of 3 nodes tolerates 1 failure. 5 nodes tolerates 2 failures. The API server, scheduler, and controller manager all read from etcd. If etcd loses quorum (more than half its nodes fail), Kubernetes cannot make decisions — scheduling stops, deployments freeze.</p>
<p>This is the price of strong consistency: etcd will never return incorrect data, but it may be unavailable if enough nodes fail.</p>
<hr />
<h2>Tradeoffs</h2>
<p><strong>Leader is the bottleneck.</strong> All writes route through the leader. For high-write systems, a single Raft group's throughput is limited by one node's capacity. Systems like CockroachDB and TiKV shard data across many independent Raft groups (one per key range) to parallelise write throughput.</p>
<p><strong>Quorum requirement limits availability.</strong> A Raft group of 3 requires 2 to be reachable. If one node is in a slow availability zone and another crashes, the cluster loses quorum and stops accepting writes. Operating in 3 availability zones with 3 nodes is the typical pattern for tolerable availability with strong consistency.</p>
<p><strong>Read linearity requires care.</strong> A stale read from a follower is possible — the follower may not have applied the latest committed entries. Linearisable reads route through the leader or use a read lease mechanism.</p>
<hr />
<h2>The one thing to remember</h2>
<blockquote>
<p><strong>Raft achieves consensus through an elected leader that replicates log entries to a majority of followers before committing.</strong> Safety comes from three rules: only one leader per term, leaders never overwrite committed entries, and candidates must have an up-to-date log to be elected. Raft is the most important consensus algorithm to understand in practice — it directly powers Kubernetes (via etcd), CockroachDB, TiKV, and Consul. When you interact with any of these systems, you're interacting with Raft's guarantees.</p>
</blockquote>
<hr />
<p><em>← Previous:</em> <a href="/paxos-the-algorithm-that-started-it-all"><em><strong>Paxos</strong></em></a> <em>— the foundational consensus algorithm, notoriously difficult to understand but the basis of many production systems.</em></p>
<p><em>→ Next:</em> <a href="/gossip-protocol-decentralised-cluster-communication"><em><strong>Gossip Protocol</strong></em></a> <em>— decentralised cluster membership and state propagation without a leader or consensus.</em></p>
]]></content:encoded></item><item><title><![CDATA[Paxos: The Algorithm That Started It All]]></title><description><![CDATA[Series: System Design · Distributed Systems — Pillar 8 of 8

Systems Design



#
Post
What it covers



00
Distributed Systems: What Happens When Machines Disagree
Twenty concepts covering network par]]></description><link>https://cloudtuned.dev/paxos-the-algorithm-that-started-it-all</link><guid isPermaLink="true">https://cloudtuned.dev/paxos-the-algorithm-that-started-it-all</guid><category><![CDATA[systemdesign]]></category><category><![CDATA[distributedsystems]]></category><category><![CDATA[paxos]]></category><category><![CDATA[Consensus]]></category><category><![CDATA[backend]]></category><category><![CDATA[SoftwareDevelopment]]></category><category><![CDATA[softwarearchitecture]]></category><category><![CDATA[engineering]]></category><dc:creator><![CDATA[Cloud Tuned]]></dc:creator><pubDate>Fri, 28 Feb 2025 12:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/602bee9a4bb9c4083f02795d/94750a6c-a8dc-4ae2-8151-df4ddeabb125.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote>
<p><strong>Series:</strong> System Design · Distributed Systems — Pillar 8 of 8</p>
</blockquote>
<h2>Systems Design</h2>
<table>
<thead>
<tr>
<th>#</th>
<th>Post</th>
<th>What it covers</th>
</tr>
</thead>
<tbody><tr>
<td>00</td>
<td><a href="/distributed-systems-what-happens-when-machines-disagree">Distributed Systems: What Happens When Machines Disagree</a></td>
<td>Twenty concepts covering network partitions, consensus, clocks, distributed transactions, CDC, erasure coding, and observability. The final pillar.</td>
</tr>
<tr>
<td>01</td>
<td><a href="/network-partitions-the-failure-mode-you-cant-design-away">Network Partitions: The Failure Mode You Can't Design Away</a></td>
<td>Network partitions are inevitable. Learn what happens when nodes can't communicate, how systems choose between availability and consistency, and what that means in practice.</td>
</tr>
<tr>
<td>02</td>
<td><a href="/split-brain-when-two-nodes-both-think-theyre-the-leader">Split-Brain: When Two Nodes Both Think They're the Leader</a></td>
<td>Split-brain occurs when two nodes both believe they're the primary. Learn how it happens, why it causes data corruption, and how STONITH and fencing prevent it.</td>
</tr>
<tr>
<td>03</td>
<td><a href="/heartbeats-how-nodes-know-their-peers-are-alive">Heartbeats: How Nodes Know Their Peers Are Alive</a></td>
<td>Heartbeats let nodes detect peer failures. Learn how timeouts, phi accrual failure detectors, and the tradeoff between false positives and detection speed work.</td>
</tr>
<tr>
<td>04</td>
<td><a href="/leader-election-agreeing-on-whos-in-charge">Leader Election: Agreeing on Who's in Charge</a></td>
<td>Leader election coordinates which node acts as primary. Learn the bully algorithm, Raft-based election, and why exactly-one-leader guarantees are hard to achieve.</td>
</tr>
<tr>
<td>05</td>
<td><a href="/consensus-algorithms-agreeing-on-a-value-across-failures">Consensus Algorithms: Agreeing on a Value Across Failures</a></td>
<td>Consensus lets distributed nodes agree on a value despite failures. Learn what FLP impossibility means, what Paxos and Raft provide, and where consensus is used.</td>
</tr>
<tr>
<td>06</td>
<td><a href="/quorum-how-many-nodes-must-agree">Quorum: How Many Nodes Must Agree?</a></td>
<td>Quorum determines how many nodes must agree for an operation to succeed. Learn how R + W &gt; N ensures consistency in distributed databases like Cassandra and DynamoDB.</td>
</tr>
<tr>
<td>07</td>
<td><strong>Paxos: The Algorithm That Started It All</strong> ← you are here</td>
<td>Paxos is the foundational distributed consensus algorithm. Learn how its two phases work, why it's hard to implement, and what systems use it in production.</td>
</tr>
<tr>
<td>08</td>
<td><a href="/raft-consensus-made-understandable">Raft: Consensus Made Understandable</a></td>
<td>Raft makes distributed consensus understandable. Learn how leader election, log replication, and safety work in the algorithm that powers etcd, CockroachDB, and TiKV.</td>
</tr>
<tr>
<td>09</td>
<td><a href="/gossip-protocol-decentralised-cluster-communication">Gossip Protocol: Decentralised Cluster Communication</a></td>
<td>Gossip protocols propagate information across a cluster without a central coordinator. Learn how epidemic spreading works and where it's used in production.</td>
</tr>
<tr>
<td>10</td>
<td><a href="/logical-clocks-when-physical-time-isnt-enough">Logical Clocks: When Physical Time Isn't Enough</a></td>
<td>Physical clocks drift and can't establish event order in distributed systems. Logical clocks track causality instead. Learn why this matters and how it works.</td>
</tr>
<tr>
<td>11</td>
<td><a href="/lamport-timestamps-ordering-events-without-a-global-clock">Lamport Timestamps: Ordering Events Without a Global Clock</a></td>
<td>Lamport timestamps assign logical counters to events to establish causal order in distributed systems. Learn how they work and what they can and can't tell you.</td>
</tr>
<tr>
<td>12</td>
<td><a href="/vector-clocks-knowing-when-events-are-truly-concurrent">Vector Clocks: Knowing When Events Are Truly Concurrent</a></td>
<td>Vector clocks detect causality and concurrency in distributed systems. Learn how they work, how Dynamo uses them for conflict detection, and their limitations.</td>
</tr>
<tr>
<td>13</td>
<td><a href="/distributed-transactions-when-one-machine-isnt-enough">Distributed Transactions: When One Machine Isn't Enough</a></td>
<td>Distributed transactions are hard. Learn why cross-service atomicity is expensive, when to use it, and when eventual consistency is the right alternative.</td>
</tr>
<tr>
<td>14</td>
<td><a href="/two-phase-commit-coordinating-a-distributed-decision">Two-Phase Commit: Coordinating a Distributed Decision</a></td>
<td>2PC ensures distributed atomicity through prepare and commit phases. Learn how it works, the coordinator failure problem, and why it's rarely used in modern systems.</td>
</tr>
<tr>
<td>15</td>
<td><a href="/three-phase-commit-solving-2pcs-blocking-problem">Three-Phase Commit: Solving 2PC's Blocking Problem</a></td>
<td>3PC adds a pre-commit phase to eliminate 2PC's blocking problem. Learn how it works, what assumptions it requires, and why it's rarely used in production.</td>
</tr>
<tr>
<td>16</td>
<td><a href="/delivery-semantics-what-does-delivered-actually-mean">Delivery Semantics: What Does "Delivered" Actually Mean?</a></td>
<td>Message delivery guarantees define system reliability. Learn what at-most-once, at-least-once, and exactly-once mean, what they cost, and when each is appropriate.</td>
</tr>
<tr>
<td>17</td>
<td><a href="/change-data-capture-streaming-your-database-in-real-time">Change Data Capture: Streaming Your Database in Real Time</a></td>
<td>CDC streams database changes in real time by reading the write-ahead log. Learn how Debezium works, what CDC enables, and when to use it.</td>
</tr>
<tr>
<td>18</td>
<td><a href="/erasure-coding-fault-tolerance-without-full-replication">Erasure Coding: Fault Tolerance Without Full Replication</a></td>
<td>Erasure coding stores data across nodes using math, not full replication. Learn how Reed-Solomon works, how S3 uses it, and when it beats 3x replication.</td>
</tr>
<tr>
<td>19</td>
<td><a href="/merkle-trees-efficiently-finding-whats-different">Merkle Trees: Efficiently Finding What's Different</a></td>
<td>Merkle trees efficiently detect which parts of a large dataset differ between nodes. Learn how Bitcoin, Cassandra, and Git use them for verification and anti-entropy.</td>
</tr>
<tr>
<td>20</td>
<td><a href="/observability-understanding-your-system-at-runtime">Observability: Understanding Your System at Runtime</a></td>
<td>Logs, metrics, and distributed traces are how you understand a system at runtime. Learn what each pillar provides, the tools involved, and how they work together.</td>
</tr>
<tr>
<td>21</td>
<td><a href="/distributed-systems-wrap-up">Distributed Systems: Wrap-Up</a></td>
<td>A recap of all 20 distributed systems concepts and the complete URL shortener architecture spanning all 8 pillars. The final post in the series.</td>
</tr>
</tbody></table>
<hr />
<h1>Paxos: The Algorithm That Started It All</h1>
<h2>The problem</h2>
<p>You need five distributed nodes to agree on a single value — which server should be the leader, what the value of a configuration key should be, or whether a transaction should commit. Any node can propose a value. Any node can fail. Messages can be delayed, lost, or reordered. No node can know for certain what other nodes have decided.</p>
<p>This is the consensus problem. Paxos, proposed by Leslie Lamport in 1989 (published 1998), was the first algorithm to prove this problem solvable in an asynchronous network with crash failures. Everything that followed — Multi-Paxos, Raft, Zab — is built on its foundation.</p>
<hr />
<h2>The core idea</h2>
<p>Paxos runs in two phases. In Phase 1 (<strong>Prepare</strong>), a proposer asks a majority of acceptors to promise not to accept older proposals. In Phase 2 (<strong>Accept</strong>), the proposer sends its chosen value; acceptors accept it if they haven't made a newer promise. Once a majority of acceptors accept the same value, it is chosen — irrevocably.</p>
<hr />
<h2>The analogy: reserving a meeting room</h2>
<p>You want to book a conference room. The booking system has three administrators (acceptors). To book, you:</p>
<p><strong>Phase 1 (Prepare/Promise):</strong> Call all three admins: "I'm proposing booking ID #42. Will you promise not to accept any booking with an ID lower than 42?"</p>
<ul>
<li>If they've already promised a higher number, they say "No (and by the way, the highest I've seen is #48)"</li>
<li>If #42 is the highest they've seen, they say "Yes, I promise"</li>
</ul>
<p>If a majority promise: proceed to Phase 2. If not: your booking ID is too low — try again with a higher ID.</p>
<p><strong>Phase 2 (Accept/Commit):</strong> Tell the same admins: "Please record this booking for ID #42: Meeting room B, 3pm Tuesday"</p>
<ul>
<li>If they haven't promised anything higher than #42 since Phase 1: they accept</li>
<li>If they have (another proposer snuck in): they reject</li>
</ul>
<p>If a majority accept: the booking is made. It can never be unmade. If not: start over with a higher proposal number.</p>
<hr />
<h2>How Paxos works in detail</h2>
<h3>Roles</h3>
<p><strong>Proposer:</strong> a node that initiates a consensus round by proposing a value.</p>
<p><strong>Acceptor:</strong> a node that receives proposals and accepts or rejects them. Maintains the highest proposal number it has seen and the last value it accepted.</p>
<p><strong>Learner:</strong> a node that learns the decided value (the chosen value) to act on it.</p>
<p>In practice, nodes often play all three roles.</p>
<h3>Phase 1: Prepare</h3>
<p>The proposer selects a globally unique, monotonically increasing proposal number <code>n</code>. It sends <code>Prepare(n)</code> to a majority of acceptors.</p>
<p>Each acceptor responds with a <strong>promise</strong>: it will not accept any proposal numbered less than <code>n</code>. If the acceptor has previously accepted a value, it includes that value in its response (so the proposer knows about any previously accepted values it must preserve).</p>
<pre><code>Proposer → Prepare(n=5) → Acceptors A, B, C
A: hasn't accepted anything → Promise(n=5, accepted=null)
B: previously accepted (n=3, v="foo") → Promise(n=5, accepted=(3, "foo"))
C: doesn't respond (failed or delayed)
</code></pre>
<p>Proposer receives promises from A and B (majority of 3) → can proceed.</p>
<h3>Phase 2: Accept</h3>
<p>The proposer picks a value:</p>
<ul>
<li>If any acceptor reported a previously accepted value, the proposer <strong>must</strong> use the value from the highest-numbered accepted proposal (v="foo" from n=3 in the example above)</li>
<li>If no acceptor reported a prior accepted value, the proposer uses its own proposed value</li>
</ul>
<p>The proposer sends <code>Accept(n, v)</code> to a majority.</p>
<p>Each acceptor accepts if it hasn't promised a higher proposal number since Phase 1.</p>
<pre><code>Proposer → Accept(n=5, v="foo") → Acceptors A, B, C
A: promised n=5, no higher → Accept(5, "foo") ✓
B: promised n=5, no higher → Accept(5, "foo") ✓
</code></pre>
<p>When a majority accept the same <code>(n, v)</code>, the value <code>v</code> is <strong>chosen</strong> (committed). It will be the decision regardless of future rounds.</p>
<h3>Why Paxos is safe</h3>
<p><strong>No two values can be chosen:</strong> only one proposal can achieve majority acceptance at any given proposal number (acceptors only accept one proposal per number). Any subsequent majority must include at least one node that accepted the current value, forcing the proposer to propagate it.</p>
<p><strong>The value of a chosen value is preserved:</strong> if value <code>v</code> was chosen in round <code>n</code>, any higher-numbered round's Phase 1 will discover the previously accepted <code>v</code> and must propose it — never a different value.</p>
<h3>Why Paxos is hard to implement correctly</h3>
<p><strong>Liveness is not guaranteed.</strong> If two proposers compete with increasing proposal numbers, they can livelock indefinitely: proposer A interrupts proposer B's Phase 1 with a higher number, B does the same to A, neither completes. Randomised backoff or a distinguished proposer (Multi-Paxos) solves this.</p>
<p><strong>The algorithm doesn't specify how to handle leader crashes.</strong> What happens to an in-progress proposal when the proposer fails? Paxos proves the value is safe — no conflicting decision will be made — but recovering the current state requires a new proposal round.</p>
<p><strong>Multi-Paxos for log replication.</strong> Single-Decree Paxos agrees on one value. For a replicated log, you need Multi-Paxos: a stable leader that skips Phase 1 for log entries (the leader's authority was established once during its election), running only Phase 2 for each entry. This is how Google Chubby, Spanner, and Zookeeper work.</p>
<p><strong>Implementation requires careful handling of:</strong> network message deduplication, acceptor state persistence (must survive crashes), leader leases, read linearizability, and cluster membership changes. Chubby's implementation note (Burrows, 2006) lists dozens of non-obvious correctness considerations.</p>
<hr />
<h2>Where Paxos is used in production</h2>
<p><strong>Google Chubby:</strong> distributed lock service. Uses Multi-Paxos for its replicated log. Chubby powers leader election across most of Google's infrastructure.</p>
<p><strong>Google Spanner:</strong> uses Paxos groups (one Paxos instance per data shard) for globally-consistent distributed transactions.</p>
<p><strong>Apache Zookeeper:</strong> uses Zab (ZooKeeper Atomic Broadcast), a Paxos variant, for its replicated log. Zookeeper coordinates Kafka, HBase, and many other distributed systems.</p>
<p><strong>CockroachDB:</strong> uses Multi-Raft (Raft, which is a more understandable reformulation of Multi-Paxos) for its replicated key-value store.</p>
<hr />
<h2>The one thing to remember</h2>
<blockquote>
<p><strong>Paxos guarantees that a distributed system agrees on exactly one value by ensuring that any majority of acceptors that accepts a value has already promised not to accept conflicting values.</strong> The two-phase structure — prepare (gather promises) and accept (commit the value) — is the foundation of all practical consensus algorithms. Paxos is correct but notoriously difficult to implement; this is why Raft was created to express the same guarantees more clearly.</p>
</blockquote>
<hr />
<p><em>← Previous: <strong><a href="/quorum-how-many-nodes-must-agree">Quorum</a></strong> — the minimum vote count that makes consensus safe, and how choosing the right quorum size balances consistency against availability.</em></p>
<p><em>→ Next: <strong><a href="/raft-consensus-made-understandable">Raft</a></strong> — the consensus algorithm designed for understandability; the most important one to know in practice.</em></p>
]]></content:encoded></item><item><title><![CDATA[Quorum: How Many Nodes Must Agree?]]></title><description><![CDATA[Series: System Design · Distributed Systems — Pillar 8 of 8

Systems Design



#
Post
What it covers



00
Distributed Systems: What Happens When Machines Disagree
Twenty concepts covering network par]]></description><link>https://cloudtuned.dev/quorum-how-many-nodes-must-agree</link><guid isPermaLink="true">https://cloudtuned.dev/quorum-how-many-nodes-must-agree</guid><category><![CDATA[systemdesign]]></category><category><![CDATA[distributedsystems]]></category><category><![CDATA[quorum]]></category><category><![CDATA[Cassandra]]></category><category><![CDATA[consistency]]></category><category><![CDATA[backend]]></category><category><![CDATA[SoftwareDevelopment]]></category><category><![CDATA[softwarearchitecture]]></category><category><![CDATA[engineering]]></category><dc:creator><![CDATA[Cloud Tuned]]></dc:creator><pubDate>Thu, 27 Feb 2025 12:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/602bee9a4bb9c4083f02795d/9fafb3e7-3f7e-4fe3-948d-6b0bef09fd6d.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote>
<p><strong>Series:</strong> System Design · Distributed Systems — Pillar 8 of 8</p>
</blockquote>
<h2>Systems Design</h2>
<table>
<thead>
<tr>
<th>#</th>
<th>Post</th>
<th>What it covers</th>
</tr>
</thead>
<tbody><tr>
<td>00</td>
<td><a href="/distributed-systems-what-happens-when-machines-disagree">Distributed Systems: What Happens When Machines Disagree</a></td>
<td>Twenty concepts covering network partitions, consensus, clocks, distributed transactions, CDC, erasure coding, and observability. The final pillar.</td>
</tr>
<tr>
<td>01</td>
<td><a href="/network-partitions-the-failure-mode-you-cant-design-away">Network Partitions: The Failure Mode You Can't Design Away</a></td>
<td>Network partitions are inevitable. Learn what happens when nodes can't communicate, how systems choose between availability and consistency, and what that means in practice.</td>
</tr>
<tr>
<td>02</td>
<td><a href="/split-brain-when-two-nodes-both-think-theyre-the-leader">Split-Brain: When Two Nodes Both Think They're the Leader</a></td>
<td>Split-brain occurs when two nodes both believe they're the primary. Learn how it happens, why it causes data corruption, and how STONITH and fencing prevent it.</td>
</tr>
<tr>
<td>03</td>
<td><a href="/heartbeats-how-nodes-know-their-peers-are-alive">Heartbeats: How Nodes Know Their Peers Are Alive</a></td>
<td>Heartbeats let nodes detect peer failures. Learn how timeouts, phi accrual failure detectors, and the tradeoff between false positives and detection speed work.</td>
</tr>
<tr>
<td>04</td>
<td><a href="/leader-election-agreeing-on-whos-in-charge">Leader Election: Agreeing on Who's in Charge</a></td>
<td>Leader election coordinates which node acts as primary. Learn the bully algorithm, Raft-based election, and why exactly-one-leader guarantees are hard to achieve.</td>
</tr>
<tr>
<td>05</td>
<td><a href="/consensus-algorithms-agreeing-on-a-value-across-failures">Consensus Algorithms: Agreeing on a Value Across Failures</a></td>
<td>Consensus lets distributed nodes agree on a value despite failures. Learn what FLP impossibility means, what Paxos and Raft provide, and where consensus is used.</td>
</tr>
<tr>
<td>06</td>
<td><strong>Quorum: How Many Nodes Must Agree?</strong> ← you are here</td>
<td>Quorum determines how many nodes must agree for an operation to succeed. Learn how R + W &gt; N ensures consistency in distributed databases like Cassandra and DynamoDB.</td>
</tr>
<tr>
<td>07</td>
<td><a href="/paxos-the-algorithm-that-started-it-all">Paxos: The Algorithm That Started It All</a></td>
<td>Paxos is the foundational distributed consensus algorithm. Learn how its two phases work, why it's hard to implement, and what systems use it in production.</td>
</tr>
<tr>
<td>08</td>
<td><a href="/raft-consensus-made-understandable">Raft: Consensus Made Understandable</a></td>
<td>Raft makes distributed consensus understandable. Learn how leader election, log replication, and safety work in the algorithm that powers etcd, CockroachDB, and TiKV.</td>
</tr>
<tr>
<td>09</td>
<td><a href="/gossip-protocol-decentralised-cluster-communication">Gossip Protocol: Decentralised Cluster Communication</a></td>
<td>Gossip protocols propagate information across a cluster without a central coordinator. Learn how epidemic spreading works and where it's used in production.</td>
</tr>
<tr>
<td>10</td>
<td><a href="/logical-clocks-when-physical-time-isnt-enough">Logical Clocks: When Physical Time Isn't Enough</a></td>
<td>Physical clocks drift and can't establish event order in distributed systems. Logical clocks track causality instead. Learn why this matters and how it works.</td>
</tr>
<tr>
<td>11</td>
<td><a href="/lamport-timestamps-ordering-events-without-a-global-clock">Lamport Timestamps: Ordering Events Without a Global Clock</a></td>
<td>Lamport timestamps assign logical counters to events to establish causal order in distributed systems. Learn how they work and what they can and can't tell you.</td>
</tr>
<tr>
<td>12</td>
<td><a href="/vector-clocks-knowing-when-events-are-truly-concurrent">Vector Clocks: Knowing When Events Are Truly Concurrent</a></td>
<td>Vector clocks detect causality and concurrency in distributed systems. Learn how they work, how Dynamo uses them for conflict detection, and their limitations.</td>
</tr>
<tr>
<td>13</td>
<td><a href="/distributed-transactions-when-one-machine-isnt-enough">Distributed Transactions: When One Machine Isn't Enough</a></td>
<td>Distributed transactions are hard. Learn why cross-service atomicity is expensive, when to use it, and when eventual consistency is the right alternative.</td>
</tr>
<tr>
<td>14</td>
<td><a href="/two-phase-commit-coordinating-a-distributed-decision">Two-Phase Commit: Coordinating a Distributed Decision</a></td>
<td>2PC ensures distributed atomicity through prepare and commit phases. Learn how it works, the coordinator failure problem, and why it's rarely used in modern systems.</td>
</tr>
<tr>
<td>15</td>
<td><a href="/three-phase-commit-solving-2pcs-blocking-problem">Three-Phase Commit: Solving 2PC's Blocking Problem</a></td>
<td>3PC adds a pre-commit phase to eliminate 2PC's blocking problem. Learn how it works, what assumptions it requires, and why it's rarely used in production.</td>
</tr>
<tr>
<td>16</td>
<td><a href="/delivery-semantics-what-does-delivered-actually-mean">Delivery Semantics: What Does "Delivered" Actually Mean?</a></td>
<td>Message delivery guarantees define system reliability. Learn what at-most-once, at-least-once, and exactly-once mean, what they cost, and when each is appropriate.</td>
</tr>
<tr>
<td>17</td>
<td><a href="/change-data-capture-streaming-your-database-in-real-time">Change Data Capture: Streaming Your Database in Real Time</a></td>
<td>CDC streams database changes in real time by reading the write-ahead log. Learn how Debezium works, what CDC enables, and when to use it.</td>
</tr>
<tr>
<td>18</td>
<td><a href="/erasure-coding-fault-tolerance-without-full-replication">Erasure Coding: Fault Tolerance Without Full Replication</a></td>
<td>Erasure coding stores data across nodes using math, not full replication. Learn how Reed-Solomon works, how S3 uses it, and when it beats 3x replication.</td>
</tr>
<tr>
<td>19</td>
<td><a href="/merkle-trees-efficiently-finding-whats-different">Merkle Trees: Efficiently Finding What's Different</a></td>
<td>Merkle trees efficiently detect which parts of a large dataset differ between nodes. Learn how Bitcoin, Cassandra, and Git use them for verification and anti-entropy.</td>
</tr>
<tr>
<td>20</td>
<td><a href="/observability-understanding-your-system-at-runtime">Observability: Understanding Your System at Runtime</a></td>
<td>Logs, metrics, and distributed traces are how you understand a system at runtime. Learn what each pillar provides, the tools involved, and how they work together.</td>
</tr>
<tr>
<td>21</td>
<td><a href="/distributed-systems-wrap-up">Distributed Systems: Wrap-Up</a></td>
<td>A recap of all 20 distributed systems concepts and the complete URL shortener architecture spanning all 8 pillars. The final post in the series.</td>
</tr>
</tbody></table>
<hr />
<h1>Quorum: How Many Nodes Must Agree?</h1>
<h2>The problem</h2>
<p>Your Cassandra cluster has five nodes. You write a record with replication factor 3 (the record is stored on 3 of the 5 nodes). A network partition isolates one of those three replica nodes. Another replica is temporarily overloaded and slow.</p>
<p>How many replicas must acknowledge the write before you return success to the client? And how many replicas must agree on a read before you return the result?</p>
<p>If you wait for all three replicas: high consistency, but the write fails if any replica is unavailable. At three nines availability, that's about 8 hours of downtime per year per write operation.</p>
<p>If you wait for just one replica: high availability, but you might read from a replica that hasn't received the latest write. Data is inconsistent.</p>
<p>If you wait for two of three: a quorum. A majority. The write succeeds if any two replicas respond. Reads can check two replicas and return the latest value. And — critically — the read quorum and write quorum overlap: any two nodes that acknowledge a write will include at least one node that participates in any read of two nodes.</p>
<p>This overlap is the key insight behind quorum-based consistency.</p>
<hr />
<h2>The core idea</h2>
<p>A quorum is the minimum number of nodes that must participate in an operation for it to be considered valid. By ensuring that the read quorum and write quorum overlap, a distributed system can guarantee that a read will always include at least one node that has the latest write — without requiring all replicas to be available.</p>
<hr />
<h2>The analogy: a jury that requires more than half</h2>
<p>A criminal verdict requires the agreement of at least 7 of 12 jurors (more than half) in many jurisdictions. For an acquittal to be valid, it also requires majority agreement. This ensures that no valid conviction and valid acquittal can exist simultaneously — the two quorums (conviction and acquittal) must overlap, so a majority agreeing to one precludes a majority agreeing to the other.</p>
<p>In distributed systems: the write quorum and read quorum must overlap, ensuring every valid read includes at least one node that participated in the last valid write.</p>
<hr />
<h2>How quorum works</h2>
<h3>The R + W &gt; N condition</h3>
<p>Given:</p>
<ul>
<li>N = replication factor (number of replicas storing the data)</li>
<li>W = write quorum (number of replicas that must acknowledge a write)</li>
<li>R = read quorum (number of replicas that must respond to a read)</li>
</ul>
<p><strong>Consistency is guaranteed when R + W &gt; N.</strong></p>
<p>This ensures the read set and write set overlap by at least one node. That overlapping node has the latest written value.</p>
<pre><code>N=3, W=2, R=2: R+W = 4 &gt; 3 ✓ — consistent
N=3, W=1, R=3: R+W = 4 &gt; 3 ✓ — consistent (but R=3 means all replicas must be available)
N=3, W=1, R=1: R+W = 2 ≤ 3 ✗ — not consistently guaranteed
N=5, W=3, R=3: R+W = 6 &gt; 5 ✓ — consistent
</code></pre>
<h3>Common quorum configurations</h3>
<p><strong>Quorum reads and writes (W = ⌊N/2⌋ + 1, R = ⌊N/2⌋ + 1):</strong>
The most common choice. For N=3: W=2, R=2. R+W=4 &gt; 3. Consistent. Tolerates 1 failure.</p>
<p><strong>Write-heavy workload (W=1, R=N):</strong>
Writes are fast (one ack). Reads require all replicas. Not suitable for availability — any replica failure makes reads fail.</p>
<p><strong>Read-heavy workload (W=N, R=1):</strong>
Writes require all replicas (durable, synchronous). Reads are fast. Writes fail if any replica is down. Better for read-heavy workloads where write durability is paramount.</p>
<p><strong>Eventual consistency (W=1, R=1):</strong>
Maximum availability. R+W=2 ≤ N=3. No consistency guarantee — reads may return stale data. Used when availability is paramount and staleness is acceptable (DNS, shopping carts, real-time counters).</p>
<h3>Cassandra's consistency levels</h3>
<p>Cassandra expresses quorum in named consistency levels per operation:</p>
<table>
<thead>
<tr>
<th>Level</th>
<th>W or R count</th>
<th>Use case</th>
</tr>
</thead>
<tbody><tr>
<td><code>ONE</code></td>
<td>1</td>
<td>Maximum availability, eventual consistency</td>
</tr>
<tr>
<td><code>QUORUM</code></td>
<td>⌊N/2⌋ + 1</td>
<td>Strong consistency, tolerates minority failures</td>
</tr>
<tr>
<td><code>ALL</code></td>
<td>N</td>
<td>Maximum durability, lowest availability</td>
</tr>
<tr>
<td><code>LOCAL_QUORUM</code></td>
<td>Majority in local DC</td>
<td>Multi-datacenter: consistency within DC</td>
</tr>
<tr>
<td><code>EACH_QUORUM</code></td>
<td>Majority in each DC</td>
<td>Multi-datacenter: consistency across DCs</td>
</tr>
</tbody></table>
<p>The URL shortener's click events use <code>CONSISTENCY = ONE</code> for writes (every write must succeed; durability comes from Cassandra's replication factor, not write acknowledgement) and <code>LOCAL_QUORUM</code> for reads that drive analytics dashboards.</p>
<h3>Quorum in consensus vs quorum in databases</h3>
<p><strong>Consensus quorum (Raft, Paxos):</strong> a majority of the total cluster must acknowledge each log entry before it's committed. This is a strict quorum that cannot be adjusted. With 5 nodes, 3 must respond for every write.</p>
<p><strong>Database quorum (Cassandra, DynamoDB):</strong> tunable per operation. The application can choose weak consistency for writes and strong consistency for reads, or vice versa. This flexibility is the leaderless database's key advantage over consensus-based systems.</p>
<hr />
<h2>Sloppy quorum</h2>
<p>Cassandra and Dynamo use <strong>sloppy quorum</strong> during failures. If the nodes responsible for a key are unavailable, the write is temporarily accepted by other available nodes (hinted handoff). The write satisfies quorum numerically but not strictly on the designated replicas.</p>
<p>When the failed nodes recover, the hints are replayed — the temporarily stored data is sent to the correct nodes. This improves availability at the cost of brief inconsistency until hints are delivered.</p>
<hr />
<h2>Tradeoffs</h2>
<p><strong>Availability vs consistency.</strong> Increasing W or R improves consistency but reduces availability (more nodes must respond). Decreasing W or R improves availability but allows stale reads. The R+W&gt;N formula is the mathematical boundary: cross it for consistency, fall below it for availability.</p>
<p><strong>Latency.</strong> Quorum reads and writes must wait for the slowest of W (or R) responding nodes. <code>ALL</code> consistency is bounded by the slowest replica in the cluster. <code>ONE</code> returns as soon as the first replica responds. The availability/consistency tradeoff is also a latency tradeoff.</p>
<p><strong>Stale reads at quorum.</strong> Even at QUORUM consistency, if the latest write hasn't propagated to the quorum before the read, the read may return a slightly older value. Read repair (Cassandra updates stale replicas after a quorum read detects version differences) mitigates but doesn't eliminate this.</p>
<hr />
<h2>The one thing to remember</h2>
<blockquote>
<p><strong>Quorum consistency is guaranteed when R + W &gt; N: the read quorum and write quorum overlap, ensuring every read includes at least one node that participated in the latest write.</strong> This is the mathematical basis for tunable consistency in distributed databases: increase W and R for stronger consistency (at the cost of availability); decrease them for higher availability (at the cost of possible stale reads). The right quorum settings depend entirely on the consistency requirements and availability targets of the specific operation.</p>
</blockquote>
<hr />
<p><em>← Previous: <strong><a href="/consensus-algorithms-agreeing-on-a-value-across-failures">Consensus Algorithms</a></strong> — the broader category of algorithms (Paxos, Raft, Zab) that allow distributed nodes to agree on a value despite failures.</em></p>
<p><em>→ Next: <strong><a href="/paxos-the-algorithm-that-started-it-all">Paxos</a></strong> — the foundational consensus algorithm, notoriously difficult to understand but the basis of many production systems.</em></p>
]]></content:encoded></item><item><title><![CDATA[Consensus Algorithms: Agreeing on a Value Across Failures]]></title><description><![CDATA[Series: System Design · Distributed Systems — Pillar 8 of 8

Systems Design



#
Post
What it covers



00
Distributed Systems: What Happens When Machines Disagree
Twenty concepts covering network par]]></description><link>https://cloudtuned.dev/consensus-algorithms-agreeing-on-a-value-across-failures</link><guid isPermaLink="true">https://cloudtuned.dev/consensus-algorithms-agreeing-on-a-value-across-failures</guid><category><![CDATA[systemdesign]]></category><category><![CDATA[distributedsystems]]></category><category><![CDATA[Consensus]]></category><category><![CDATA[paxos]]></category><category><![CDATA[raft]]></category><category><![CDATA[backend]]></category><category><![CDATA[SoftwareDevelopment]]></category><category><![CDATA[softwarearchitecture]]></category><category><![CDATA[engineering]]></category><dc:creator><![CDATA[Cloud Tuned]]></dc:creator><pubDate>Wed, 26 Feb 2025 12:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/602bee9a4bb9c4083f02795d/7714bd47-eb64-4513-a800-a6a4ae56fe10.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote>
<p><strong>Series:</strong> System Design · Distributed Systems — Pillar 8 of 8</p>
</blockquote>
<h2>Systems Design</h2>
<table>
<thead>
<tr>
<th>#</th>
<th>Post</th>
<th>What it covers</th>
</tr>
</thead>
<tbody><tr>
<td>00</td>
<td><a href="/distributed-systems-what-happens-when-machines-disagree">Distributed Systems: What Happens When Machines Disagree</a></td>
<td>Twenty concepts covering network partitions, consensus, clocks, distributed transactions, CDC, erasure coding, and observability. The final pillar.</td>
</tr>
<tr>
<td>01</td>
<td><a href="/network-partitions-the-failure-mode-you-cant-design-away">Network Partitions: The Failure Mode You Can't Design Away</a></td>
<td>Network partitions are inevitable. Learn what happens when nodes can't communicate, how systems choose between availability and consistency, and what that means in practice.</td>
</tr>
<tr>
<td>02</td>
<td><a href="/split-brain-when-two-nodes-both-think-theyre-the-leader">Split-Brain: When Two Nodes Both Think They're the Leader</a></td>
<td>Split-brain occurs when two nodes both believe they're the primary. Learn how it happens, why it causes data corruption, and how STONITH and fencing prevent it.</td>
</tr>
<tr>
<td>03</td>
<td><a href="/heartbeats-how-nodes-know-their-peers-are-alive">Heartbeats: How Nodes Know Their Peers Are Alive</a></td>
<td>Heartbeats let nodes detect peer failures. Learn how timeouts, phi accrual failure detectors, and the tradeoff between false positives and detection speed work.</td>
</tr>
<tr>
<td>04</td>
<td><a href="/leader-election-agreeing-on-whos-in-charge">Leader Election: Agreeing on Who's in Charge</a></td>
<td>Leader election coordinates which node acts as primary. Learn the bully algorithm, Raft-based election, and why exactly-one-leader guarantees are hard to achieve.</td>
</tr>
<tr>
<td>05</td>
<td><strong>Consensus Algorithms: Agreeing on a Value Across Failures</strong> ← you are here</td>
<td>Consensus lets distributed nodes agree on a value despite failures. Learn what FLP impossibility means, what Paxos and Raft provide, and where consensus is used.</td>
</tr>
<tr>
<td>06</td>
<td><a href="/quorum-how-many-nodes-must-agree">Quorum: How Many Nodes Must Agree?</a></td>
<td>Quorum determines how many nodes must agree for an operation to succeed. Learn how R + W &gt; N ensures consistency in distributed databases like Cassandra and DynamoDB.</td>
</tr>
<tr>
<td>07</td>
<td><a href="/paxos-the-algorithm-that-started-it-all">Paxos: The Algorithm That Started It All</a></td>
<td>Paxos is the foundational distributed consensus algorithm. Learn how its two phases work, why it's hard to implement, and what systems use it in production.</td>
</tr>
<tr>
<td>08</td>
<td><a href="/raft-consensus-made-understandable">Raft: Consensus Made Understandable</a></td>
<td>Raft makes distributed consensus understandable. Learn how leader election, log replication, and safety work in the algorithm that powers etcd, CockroachDB, and TiKV.</td>
</tr>
<tr>
<td>09</td>
<td><a href="/gossip-protocol-decentralised-cluster-communication">Gossip Protocol: Decentralised Cluster Communication</a></td>
<td>Gossip protocols propagate information across a cluster without a central coordinator. Learn how epidemic spreading works and where it's used in production.</td>
</tr>
<tr>
<td>10</td>
<td><a href="/logical-clocks-when-physical-time-isnt-enough">Logical Clocks: When Physical Time Isn't Enough</a></td>
<td>Physical clocks drift and can't establish event order in distributed systems. Logical clocks track causality instead. Learn why this matters and how it works.</td>
</tr>
<tr>
<td>11</td>
<td><a href="/lamport-timestamps-ordering-events-without-a-global-clock">Lamport Timestamps: Ordering Events Without a Global Clock</a></td>
<td>Lamport timestamps assign logical counters to events to establish causal order in distributed systems. Learn how they work and what they can and can't tell you.</td>
</tr>
<tr>
<td>12</td>
<td><a href="/vector-clocks-knowing-when-events-are-truly-concurrent">Vector Clocks: Knowing When Events Are Truly Concurrent</a></td>
<td>Vector clocks detect causality and concurrency in distributed systems. Learn how they work, how Dynamo uses them for conflict detection, and their limitations.</td>
</tr>
<tr>
<td>13</td>
<td><a href="/distributed-transactions-when-one-machine-isnt-enough">Distributed Transactions: When One Machine Isn't Enough</a></td>
<td>Distributed transactions are hard. Learn why cross-service atomicity is expensive, when to use it, and when eventual consistency is the right alternative.</td>
</tr>
<tr>
<td>14</td>
<td><a href="/two-phase-commit-coordinating-a-distributed-decision">Two-Phase Commit: Coordinating a Distributed Decision</a></td>
<td>2PC ensures distributed atomicity through prepare and commit phases. Learn how it works, the coordinator failure problem, and why it's rarely used in modern systems.</td>
</tr>
<tr>
<td>15</td>
<td><a href="/three-phase-commit-solving-2pcs-blocking-problem">Three-Phase Commit: Solving 2PC's Blocking Problem</a></td>
<td>3PC adds a pre-commit phase to eliminate 2PC's blocking problem. Learn how it works, what assumptions it requires, and why it's rarely used in production.</td>
</tr>
<tr>
<td>16</td>
<td><a href="/delivery-semantics-what-does-delivered-actually-mean">Delivery Semantics: What Does "Delivered" Actually Mean?</a></td>
<td>Message delivery guarantees define system reliability. Learn what at-most-once, at-least-once, and exactly-once mean, what they cost, and when each is appropriate.</td>
</tr>
<tr>
<td>17</td>
<td><a href="/change-data-capture-streaming-your-database-in-real-time">Change Data Capture: Streaming Your Database in Real Time</a></td>
<td>CDC streams database changes in real time by reading the write-ahead log. Learn how Debezium works, what CDC enables, and when to use it.</td>
</tr>
<tr>
<td>18</td>
<td><a href="/erasure-coding-fault-tolerance-without-full-replication">Erasure Coding: Fault Tolerance Without Full Replication</a></td>
<td>Erasure coding stores data across nodes using math, not full replication. Learn how Reed-Solomon works, how S3 uses it, and when it beats 3x replication.</td>
</tr>
<tr>
<td>19</td>
<td><a href="/merkle-trees-efficiently-finding-whats-different">Merkle Trees: Efficiently Finding What's Different</a></td>
<td>Merkle trees efficiently detect which parts of a large dataset differ between nodes. Learn how Bitcoin, Cassandra, and Git use them for verification and anti-entropy.</td>
</tr>
<tr>
<td>20</td>
<td><a href="/observability-understanding-your-system-at-runtime">Observability: Understanding Your System at Runtime</a></td>
<td>Logs, metrics, and distributed traces are how you understand a system at runtime. Learn what each pillar provides, the tools involved, and how they work together.</td>
</tr>
<tr>
<td>21</td>
<td><a href="/distributed-systems-wrap-up">Distributed Systems: Wrap-Up</a></td>
<td>A recap of all 20 distributed systems concepts and the complete URL shortener architecture spanning all 8 pillars. The final post in the series.</td>
</tr>
</tbody></table>
<hr />
<h1>Consensus Algorithms: Agreeing on a Value Across Failures</h1>
<h2>The problem</h2>
<p>Distributed systems need to agree on things. Which value should a configuration key have? Which node is the current leader? In what order should a sequence of writes be applied? What is the committed state of a transaction?</p>
<p>In a single-machine system, "agree" means "whatever the program says." In a distributed system with multiple nodes that can fail, agreeing becomes a formal problem: how do N nodes reach agreement on a single value, given that some nodes may crash, messages may be delayed, and no node can know for certain what the others have decided?</p>
<p>This is the consensus problem, and it has a family of solutions — Paxos, Raft, Zab, Multi-Paxos — each trading clarity, performance, and operational complexity differently.</p>
<hr />
<h2>The core idea</h2>
<p>A consensus algorithm allows a group of nodes to agree on a value such that: all non-faulty nodes eventually decide on the same value (<strong>agreement</strong>), the decided value was proposed by some node (<strong>validity</strong>), and every node that decides, decides exactly once (<strong>termination</strong>). This must hold even if up to ⌊(N-1)/2⌋ nodes fail.</p>
<hr />
<h2>The analogy: a committee voting on a resolution</h2>
<p>A committee must pass a resolution. Rules: a resolution passes only if a majority votes for it; no one can change their vote once cast; any committee member who doesn't respond is assumed absent (failed). The chairperson (proposer) proposes a resolution, collects votes, and declares it passed if a majority agree.</p>
<p>The difficulty: some members may receive the proposal late, vote on a different proposal, or fail mid-vote. The consensus algorithm is the set of rules that guarantees the committee eventually reaches a decision that a majority agreed to, despite these complications.</p>
<hr />
<h2>What consensus algorithms provide</h2>
<h3>The replicated state machine</h3>
<p>The most important application of consensus: building a <strong>replicated state machine</strong> (RSM). An RSM is a service that:</p>
<ul>
<li>Maintains state (a key-value store, a configuration registry, a transaction log)</li>
<li>Receives commands from clients</li>
<li>Applies commands in a consistent order on all replicas</li>
<li>Provides strongly consistent reads and writes despite node failures</li>
</ul>
<p>The consensus algorithm is how all replicas agree on the <strong>same order</strong> of commands. If replica A applies writes as [w1, w2, w3] and replica B applies them as [w2, w1, w3], they end up with different states. Consensus ensures all replicas apply writes in the same order.</p>
<p>Used by: etcd (Kubernetes configuration), ZooKeeper (Kafka coordination), CockroachDB, TiKV, Google Spanner's Paxos groups.</p>
<h3>Properties</h3>
<p><strong>Safety:</strong> all nodes decide the same value. A consensus algorithm that allows different nodes to decide different values is broken. Safety is unconditional — it must hold even under network partitions.</p>
<p><strong>Liveness:</strong> all non-faulty nodes eventually decide. A consensus algorithm that blocks forever is useless. Liveness requires a functioning majority.</p>
<p><strong>The FLP impossibility result</strong> (Fischer, Lynch, Paterson, 1985) proves that no purely asynchronous distributed system can guarantee consensus in the presence of even one failed node. This is not a limitation of algorithm design — it's a mathematical proof. In practice, consensus algorithms work around this by assuming partially synchronous networks (timeouts are bounded) and using randomisation or leader-based approaches to break tie states.</p>
<hr />
<h2>The consensus algorithm family</h2>
<h3>Single-Decree Paxos</h3>
<p>The original Paxos (Lamport, 1989) solves consensus for a single value: how do nodes agree on one value? It runs in two phases: <strong>prepare</strong> (a proposer asks acceptors to promise not to accept older proposals) and <strong>accept</strong> (the proposer sends the value; acceptors accept if they haven't promised a newer proposal).</p>
<p>Single-Decree Paxos is correct but impractical for logs — running a new Paxos round for every log entry is expensive.</p>
<h3>Multi-Paxos</h3>
<p>Extends single-decree Paxos to agree on a sequence of values (a log). A stable leader eliminates the prepare phase for subsequent entries: the leader appends log entries directly, running only the accept phase. When the leader fails, a new leader runs a full Paxos election to establish its authority, then continues appending.</p>
<p>Multi-Paxos is used by Google Chubby, Google Spanner, and is the theoretical basis for most production consensus implementations.</p>
<h3>Raft</h3>
<p>Raft (Ongaro and Ousterhout, 2014) was explicitly designed to be understandable — Paxos is notorious for being difficult to reason about. Raft decomposes consensus into leader election, log replication, and safety. Covered in depth in post 08.</p>
<h3>Zab (ZooKeeper Atomic Broadcast)</h3>
<p>Zab is ZooKeeper's consensus protocol. Similar to Raft in its leader-based approach. It provides total order broadcast: all delivered messages are delivered in the same order to all processes. Used exclusively by ZooKeeper.</p>
<hr />
<h2>When is consensus needed vs not needed?</h2>
<p><strong>Consensus is needed for:</strong></p>
<ul>
<li>Leader election (exactly one leader must be agreed upon)</li>
<li>Distributed configuration (all nodes must agree on the current config)</li>
<li>Ordered log replication (replicated databases, Kafka controller)</li>
<li>Distributed transactions (commit or abort must be agreed upon)</li>
</ul>
<p><strong>Consensus is NOT needed for:</strong></p>
<ul>
<li>Eventual consistency workloads (Cassandra, DynamoDB) — these accept different nodes seeing different values temporarily</li>
<li>Best-effort coordination (Gossip protocol membership)</li>
<li>Read-heavy workloads with relaxed consistency requirements</li>
</ul>
<p>Consensus algorithms are expensive — they require multiple round trips between nodes and at least a majority of nodes to be available and reachable. They should be applied precisely where their guarantees are required, not everywhere.</p>
<hr />
<h2>Tradeoffs</h2>
<p><strong>Throughput vs latency vs fault tolerance.</strong> A consensus algorithm requires at least one round-trip (often two) for each committed value. For a 5ms cross-region RTT, each consensus round takes at minimum 5ms. For a 1ms intra-datacenter RTT, 1ms. This is the fundamental latency floor of consensus-based systems.</p>
<p><strong>Fault tolerance requires more nodes.</strong> Tolerating f failures requires 2f+1 nodes. Tolerating 2 failures requires 5 nodes. More nodes means more messages per consensus round and higher coordination overhead.</p>
<p><strong>Leader bottleneck.</strong> Leader-based consensus (Raft, Multi-Paxos) routes all writes through one node. Under high write load, the leader becomes the bottleneck. Systems like CockroachDB mitigate this by running multiple independent Raft groups (one per range), each with its own leader.</p>
<hr />
<h2>The one thing to remember</h2>
<blockquote>
<p><strong>Consensus algorithms allow distributed nodes to agree on a value — or a sequence of values — despite a minority of failures.</strong> The key guarantee is that all non-faulty nodes decide the same thing (safety), and that a decision is eventually reached (liveness) as long as a majority is available. Raft is the most important consensus algorithm to understand in practice: it powers etcd, CockroachDB, TiKV, and most modern distributed databases. Consensus is expensive — use it where strong consistency is genuinely required, and accept eventual consistency everywhere else.</p>
</blockquote>
<hr />
<p><em>← Previous: <strong><a href="/leader-election-agreeing-on-whos-in-charge">Leader Election</a></strong> — when a leader fails, the cluster must agree on a new one; this post covers how that agreement is reached safely.</em></p>
<p><em>→ Next: <strong><a href="/quorum-how-many-nodes-must-agree">Quorum</a></strong> — the minimum vote count that makes consensus safe, and how choosing the right quorum size balances consistency against availability.</em></p>
]]></content:encoded></item></channel></rss>