<?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[Backend Blueprints]]></title><description><![CDATA[Backend Blueprints]]></description><link>https://backendblueprints.hashnode.dev</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1593680282896/kNC7E8IR4.png</url><title>Backend Blueprints</title><link>https://backendblueprints.hashnode.dev</link></image><generator>RSS for Node</generator><lastBuildDate>Sat, 19 Sep 2026 05:34:10 GMT</lastBuildDate><atom:link href="https://backendblueprints.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Why is it a tough ask to Scale a SQL Database Horizontally especially for Writes]]></title><description><![CDATA[Part 1: The Comfort of Vertical Scaling
Picture this. You've built an e-commerce backend on PostgreSQL. Everything is on a single server — one instance, one disk, one brain making all the decisions. F]]></description><link>https://backendblueprints.hashnode.dev/why-is-it-a-tough-ask-to-scale-a-sql-database-horizontally-especially-for-writes</link><guid isPermaLink="true">https://backendblueprints.hashnode.dev/why-is-it-a-tough-ask-to-scale-a-sql-database-horizontally-especially-for-writes</guid><category><![CDATA[System Design]]></category><category><![CDATA[backend]]></category><category><![CDATA[Java]]></category><category><![CDATA[spring-boot]]></category><category><![CDATA[hld]]></category><category><![CDATA[software development]]></category><category><![CDATA[Software Engineering]]></category><dc:creator><![CDATA[Devansh Verma]]></dc:creator><pubDate>Sat, 18 Jul 2026 19:31:02 GMT</pubDate><content:encoded><![CDATA[<h2>Part 1: The Comfort of Vertical Scaling</h2>
<p>Picture this. You've built an e-commerce backend on PostgreSQL. Everything is on a single server — one instance, one disk, one brain making all the decisions. For the first few months, life is good. Then Diwali sale traffic hits, and your dashboard starts looking unhappy: CPU pinned at 90%, query latency creeping from 50ms to 500ms, connections queuing up.</p>
<p>Your first instinct — and the <em>correct</em> first instinct — is <strong>vertical scaling</strong>. You go to your cloud console and upgrade the machine:</p>
<pre><code class="language-plaintext">Before:  4 vCPU  | 16 GB RAM | 500 GB SSD
After:   16 vCPU | 64 GB RAM | 2 TB NVMe SSD
</code></pre>
<p>More cores mean more parallel query execution. More RAM means a bigger buffer pool/page cache, so more of your working set stays in memory instead of hitting disk. A faster SSD means lower I/O latency for the queries that do have to touch disk. For a good while, this single lever fixes almost every scaling problem you throw at it. It's also <em>operationally free</em> — no application changes, no new failure modes, no distributed systems to reason about. You just resize the box and reboot (or fail over).</p>
<p>This is why vertical scaling is almost always the right first move. It's cheap in engineering effort, even if it's expensive in hardware cost.</p>
<h2>Part 2: The Wall You Eventually Hit</h2>
<p>But vertical scaling has a ceiling, and it's not just a budget ceiling — it's a physical one.</p>
<ul>
<li><p><strong>Hardware limits</strong>: Even the largest cloud instances top out at some finite number of vCPUs and RAM. You cannot buy a machine with infinite memory.</p>
</li>
<li><p><strong>Single point of failure</strong>: One box means one box can die. Vertical scaling doesn't buy you availability — it just delays the inevitable outage.</p>
</li>
<li><p><strong>Diminishing returns</strong>: A single database instance has one write path, one WAL/redo log, one lock manager. Beyond a point, adding more CPU cores doesn't help because your bottleneck isn't compute anymore — it's contention: rows getting locked, connections queueing, the transaction log becoming a serialization point.</p>
</li>
<li><p><strong>Cost curve isn't linear</strong>: Going from 16 to 32 vCPUs doesn't cost 2x, it often costs 4x or more, because you're now paying for rarer, higher-tier hardware.</p>
</li>
</ul>
<p>At this point, you're not fighting a hardware problem anymore — you're fighting an architectural one. A single node, no matter how big, is still <em>one</em> node. And this is exactly where <strong>horizontal scaling</strong> enters the conversation.</p>
<h2>Part 3: Horizontal Scaling — Spreading the Load Across Machines</h2>
<p><strong>Clearing the clutter in the start, What about using Replication?</strong></p>
<p>**Read replicas solve half the problem -**It lets you horizontally scale <em>reads</em> by copying entire data across multiple nodes — but they don't touch the actual bottleneck once your <strong>write</strong> volume outgrows a single machine, because every replica still funnels through one primary for writes.</p>
<p><strong>The core Idea of Horizontal scaling and how Sharding is related here?</strong></p>
<p>Sharding is the piece that actually solves <strong>horizontal write scaling</strong> for a SQL database: by physically partitioning the dataset itself, each shard only owns — and only has to write — its own slice of the data but at the cost of complexities like ike <strong>cross-shard transactions, broken joins, and painful resharding — trade-offs that turn a simple scaling decision into a genuine distributed systems problem.</strong></p>
<p><strong>The crucial point to keep in mind before moving forward -</strong> <em>sharding is the mechanism that actually scales SQL writes horizontally. Read replicas only help with reads; sharding is what splits the write load itself across independent servers.</em></p>
<p>Horizontal scaling means: instead of making one server bigger, you add more servers and split the work between them.</p>
<p>For <strong>reads</strong>, this is relatively approachable — you spin up read replicas, and route SELECT-heavy traffic to them via a load balancer while writes still go to the primary. Most teams do this early because it's low-risk.</p>
<p>But writes are the real problem. A read replica doesn't help you if your <em>write</em> volume itself has outgrown a single machine's capacity — one node can only accept so many writes per second before its disk I/O and lock manager become the bottleneck. That's the point where teams reach for <strong>sharding</strong>: splitting your dataset itself across multiple independent database instances, so that each shard only owns a slice of the data — and, crucially, only handles the write load for that slice.</p>
<h2>Part 4: How Sharding Actually Works</h2>
<p>Sharding takes one logical table and physically distributes its rows across N independent database servers. Each shard is a full, working SQL database — with its own disk, its own connections, its own query engine — but it only holds a fraction of the total rows.</p>
<p>There are three common strategies for deciding <em>which row goes to which shard</em>:</p>
<p><strong>1. Range-based sharding</strong> Rows are split by a range of the shard key — e.g., users A–M go to Shard 1, N–Z go to Shard 2. Simple to reason about, but prone to "hot ranges" (if most of your users have names starting with S, Shard 2 burns).</p>
<p><strong>2. Hash-based sharding</strong> You hash the shard key (say, <code>user_id</code>) and use the hash to decide the shard: <code>shard = hash(user_id) % N</code>. This spreads data much more evenly than range-based sharding, since a good hash function scatters keys uniformly regardless of their natural distribution.</p>
<p><strong>3. Directory-based sharding</strong> A separate lookup service maintains a mapping of key → shard. More flexible (you can move individual keys), but that lookup service itself becomes a new critical dependency and potential bottleneck.</p>
<p>Here's the mental picture:</p>
<pre><code class="language-plaintext">                     ┌─────────────────────┐
                     │   Application /      │
                     │   Query Router        │
                     └───────────┬──────────┘
                                 │  shard = hash(user_id) % 3
              ┌──────────────────┼──────────────────┐
              ▼                  ▼                  ▼
       ┌─────────────┐    ┌─────────────┐    ┌─────────────┐
       │   Shard 1    │    │   Shard 2    │    │   Shard 3    │
       │ users 1-33%  │    │ users 34-66% │    │ users 67-100%│
       │ orders, etc. │    │ orders, etc. │    │ orders, etc. │
       └─────────────┘    └─────────────┘    └─────────────┘
</code></pre>
<p>On paper, this looks clean. Reality is far messier — and that messiness is the actual point of this blog.</p>
<h2>Part 5: The Hero of the Show — Why Horizontal Scaling (Especially Writes) Is Genuinely Hard</h2>
<p>This is where most "just shard it" advice quietly skips over the painful parts. Let's not skip them.</p>
<h3>5.1 The Cross-Shard Write Problem</h3>
<p>In a single-node SQL database, a transaction like "transfer money from Account A to Account B" is trivial — both rows live on the same disk, protected by the same lock manager, wrapped in one ACID transaction.</p>
<p>Now shard by <code>account_id</code>. What if Account A lives on Shard 1 and Account B lives on Shard 2?</p>
<pre><code class="language-plaintext">BEGIN TRANSACTION
   UPDATE accounts SET balance = balance - 100 WHERE id = A   -- Shard 1
   UPDATE accounts SET balance = balance + 100 WHERE id = B   -- Shard 2
COMMIT
</code></pre>
<p>There is no single database engine that can atomically commit this across two independent Postgres/MySQL instances. You've stepped outside the guarantees of a single-node ACID transaction and into the world of <strong>distributed transactions</strong>.</p>
<p>The classical fix is <strong>Two-Phase Commit (2PC)</strong>:</p>
<pre><code class="language-plaintext">Coordinator                Shard 1                  Shard 2
    │──── PREPARE ─────────▶│                          │
    │──── PREPARE ────────────────────────────────────▶│
    │◀──── YES/READY ────────│                          │
    │◀──── YES/READY ───────────────────────────────────│
    │──── COMMIT ───────────▶│                          │
    │──── COMMIT ──────────────────────────────────────▶│
</code></pre>
<p>2PC works, but it's expensive and fragile:</p>
<ul>
<li><p>It's a blocking protocol — if the coordinator crashes between PREPARE and COMMIT, both shards sit holding locks indefinitely, waiting for a decision that may never come.</p>
</li>
<li><p>It adds latency — every cross-shard write now needs at least two network round-trips instead of one local commit.</p>
</li>
<li><p>It reduces availability — every participant must be reachable and healthy for the transaction to complete; one slow or down shard stalls the entire write.</p>
</li>
</ul>
<p>This single problem is <em>the</em> reason "just shard your writes" is much easier said than done.</p>
<h3>5.2 Joins and Referential Integrity Break Down</h3>
<p>In a single database, <code>JOIN orders ON orders.user_id = users.id</code> is one query, handled entirely within the engine's optimizer.</p>
<p>Once <code>users</code> and <code>orders</code> are sharded independently (or co-located imperfectly), that join has to become one of:</p>
<ul>
<li><p><strong>Scatter-gather</strong>: send the query to every shard, then merge results in the application layer. Correct, but slow — you're now bottlenecked by your <em>slowest</em> shard for every such query, and you've moved join logic that the database used to optimize for you into your own code.</p>
</li>
<li><p><strong>Co-partitioning</strong>: deliberately store <code>orders</code> on the same shard as the <code>users</code> row it belongs to (using the same shard key), so the join stays local. This works — but only for that <em>one</em> relationship. The moment you need to join <code>orders</code> with <code>products</code> (which is sharded by <code>product_id</code>, not <code>user_id</code>), you're back to scatter-gather.</p>
</li>
</ul>
<p>Foreign key constraints suffer the same fate — a database can't enforce <code>orders.user_id REFERENCES users.id</code> across two physically separate instances. That referential integrity check now has to be enforced (or, more often, silently <em>not</em> enforced) in application code.</p>
<h3>5.3 The Scatter Problem and Partition Pruning</h3>
<p>Even for pure reads, if your query doesn't include the shard key, the router has no way to know which shard holds the answer — it has to broadcast the query to <em>every</em> shard and merge results:</p>
<pre><code class="language-plaintext">Query: SELECT * FROM orders WHERE status = 'pending'
       (no user_id in the WHERE clause)

Router → Shard 1: run query
Router → Shard 2: run query
Router → Shard 3: run query
       ↓             ↓             ↓
     merge all results in the app layer
</code></pre>
<p>This is the <strong>scatter-gather problem</strong>, and it defeats much of the point of sharding — instead of one node doing 1/N of the work, all N nodes do the full query, and you pay N times the total system cost for one logical request. Good sharding schemes are designed so the <em>most frequent</em> queries include the shard key, enabling <strong>partition pruning</strong> — the router can go straight to the one shard that matters instead of asking everyone.</p>
<h3>5.4 Resharding Is Its Own Nightmare</h3>
<p>Say you launched with <code>shard = hash(user_id) % 4</code>. Traffic grows, and you need to go to 8 shards. With plain modulo hashing, this changes the destination shard for the vast majority of existing keys:</p>
<pre><code class="language-plaintext">% 4  → hash(user_id) % 4
% 8  → hash(user_id) % 8

Almost every key maps to a different shard the moment N changes!
</code></pre>
<p>That means a near-total data reshuffle — moving the majority of your dataset across the network — while the system is live and still taking writes. This is precisely the problem <strong>consistent hashing</strong> was invented to solve: shards (and their virtual nodes) sit on a hash ring, and adding or removing a node only remaps the small arc of keys adjacent to it, not the whole ring.</p>
<pre><code class="language-plaintext">              Hash Ring (0 ────────────────── 2^32-1)
                     ┌───────────┐
              ╭──────┤  Shard A   ├──────╮
             /        └───────────┘       \
      Shard D                              Shard B
             \        ┌───────────┐       /
              ╰──────┤  Shard C   ├──────╯
                     └───────────┘

  Adding Shard E only steals keys from its
  immediate neighbor on the ring — not from all shards.
</code></pre>
<p>Even with consistent hashing, virtual nodes (multiple ring positions per physical shard) are needed to avoid uneven load, and the actual data migration — copying rows, keeping both old and new locations consistent mid-migration, and cutting over writes without downtime — is a genuinely hard piece of distributed systems engineering, not a config change.</p>
<h3>5.5 Hotspots Don't Go Away — They Just Move</h3>
<p>Sharding assumes a roughly even key distribution. Real-world traffic rarely cooperates. A single viral product, a single celebrity user, or a single tenant in a multi-tenant system can dominate the write volume for their one shard, while the other N-1 shards sit idle. You've successfully scaled the <em>average</em> case while leaving the <em>worst</em> case — the one that actually pages you at 2 AM — completely unsolved.</p>
<h3>5.6 Putting It Together — Why "Just Shard It" Undersells the Problem</h3>
<table>
<thead>
<tr>
<th>Single-Node SQL</th>
<th>Sharded SQL</th>
</tr>
</thead>
<tbody><tr>
<td>One ACID transaction, always atomic</td>
<td>Cross-shard transactions need 2PC or Saga patterns, with real availability/latency trade-offs</td>
</tr>
<tr>
<td>Joins optimized by the engine</td>
<td>Joins become scatter-gather or require careful co-partitioning</td>
</tr>
<tr>
<td>FK constraints enforced by the DB</td>
<td>Referential integrity often pushed into application code</td>
</tr>
<tr>
<td>Adding capacity = resize one box</td>
<td>Adding capacity = re-map keys, migrate data live, avoid hotspots</td>
</tr>
<tr>
<td>One query plan, one node to reason about</td>
<td>Query router, partition pruning, and per-shard load all need active design</td>
</tr>
</tbody></table>
<p>None of this means sharding is a bad idea — for write-heavy systems at real scale, it's often the only path forward. But it's a trade: you're exchanging the simplicity of single-node ACID guarantees for the <em>capacity</em> to scale writes horizontally, and every piece of that simplicity you give up has to be rebuilt, deliberately, somewhere else in your architecture — in your routing layer, your transaction design, or your application code.</p>
<h2>Closing Thought</h2>
<p>Vertical scaling buys you time. Horizontal scaling — and sharding specifically — buys you capacity, but the invoice comes due in complexity: distributed transactions, broken joins, live data migrations, and hotspot management. Understanding <em>why</em> it's hard is what separates teams that shard successfully from teams that shard and then spend the next year firefighting consistency bugs.</p>
<p>If there's one takeaway to carry forward: <strong>don't shard until vertical scaling and read replicas are truly exhausted</strong> — and when you do shard, design your shard key around your <em>actual</em> query patterns, not just an even data distribution. The hardest problems above (cross-shard joins, cross-shard transactions) are almost always solvable by choosing a shard key that keeps related data together — the real engineering skill isn't sharding itself, it's picking the right key.</p>
]]></content:encoded></item><item><title><![CDATA[How consistent hashing works and helps in rebalancing shards in a SQL DB.]]></title><description><![CDATA[The problem consistent hashing solves
Say you shard your users table across 4 database nodes /shards using a hash function -> hash(user_id) % 4. This works fine — until you add a 5th node. Now % 4 bec]]></description><link>https://backendblueprints.hashnode.dev/how-consistent-hashing-works-and-helps-in-rebalancing-shards-in-a-sql-db</link><guid isPermaLink="true">https://backendblueprints.hashnode.dev/how-consistent-hashing-works-and-helps-in-rebalancing-shards-in-a-sql-db</guid><category><![CDATA[backend]]></category><category><![CDATA[System Design]]></category><category><![CDATA[Hashing]]></category><category><![CDATA[scalability]]></category><category><![CDATA[SQL]]></category><category><![CDATA[Java]]></category><dc:creator><![CDATA[Devansh Verma]]></dc:creator><pubDate>Mon, 13 Jul 2026 20:28:20 GMT</pubDate><content:encoded><![CDATA[<h3>The problem consistent hashing solves</h3>
<p>Say you shard your <code>users</code> table across 4 database nodes /shards using a hash function -&gt; <code>hash(user_id) % 4</code>. This works fine — until you add a 5th node. Now <code>% 4</code> becomes <code>% 5</code>, and almost <strong>every single key</strong> maps to a different node. You'd have to reshuffle nearly all your data just to add one machine. For a live system, that's a massive, disruptive migration.</p>
<p>Consistent hashing exists to fix exactly this: <strong>when you add or remove a node, only a small fraction of keys need to move — not all of them unlike normal hashing.</strong></p>
<p><strong>The core idea: a ring, not a line</strong></p>
<p>Instead of <code>hash(key) % N</code>, consistent hashing imagines the entire output space of your hash function (say, 0 to 2³²−1) bent into a circle — a <strong>ring</strong>.</p>
<ul>
<li><p>Both your <strong>nodes</strong> (servers) and your <strong>keys</strong> (user_ids, order_ids, whatever you're partitioning) get hashed onto positions on this same ring.</p>
</li>
<li><p>The record gets partitioned when we hash the partition key of the record in a hash function, this gives a unique position to this record on this ring and the nodes are hashed by running a hash function on a unique identifier value of that node like hostname/url etc and the value again places the nodes on the ring.</p>
</li>
<li><p>To find which node owns a given key: start at the key's position and walk <strong>clockwise</strong> until you hit the first node. That node owns the key.</p>
</li>
<li><p>Once the nodes and all records are placed on the ring the very next node towards the clock wise direction to the record is the node where that record lives physically.</p>
</li>
</ul>
<p>That one rule — "clockwise to the nearest node" — is the entire mechanism.</p>
<p><strong>Lets Walkthrough Consistent Hashing with an example scenario to understand it clearly:</strong></p>
<p>Lets say you have following tables:-</p>
<ol>
<li><p>users</p>
</li>
<li><p>orders</p>
</li>
<li><p>products</p>
</li>
</ol>
<p>You want to shard the data across 2 servers/nodes.</p>
<p><strong>NOTE:</strong> Data partitioning is the logical step where you take a conscious decision on how you want to partition the data based on your use case, load, access pattern (hot keys often used in your system for data querying).</p>
<p>Keeping that note in mind lets first partition our data and understand which shard receives what part of our data.</p>
<h3>Step 1: Partitioning <code>users</code></h3>
<p>The very first decision: pick a <strong>partitioning key</strong> for the <code>users</code> table. Lets chose <code>user_id</code>. This means: take every user's <code>user_id</code>, run it through a hash function, and the output number is that user's position on a conceptual circle (the "ring") going from 0° to 360°.</p>
<p>That's it — that's all "partitioning" means at this stage. No servers involved yet. We've just decided <em>which column</em> determines where a row conceptually sits.</p>
<h3>Step 2: Partitioning <code>orders</code> — the same way</h3>
<p>For <code>orders</code>, we made a deliberate choice: <strong>don't</strong> partition by <code>order_id</code>. Instead, partition by the <code>user_id</code> that each order belongs to.</p>
<p>Why?</p>
<p>So that a user's orders land at the <em>exact same ring position</em> as that user themselves — because they're hashing the identical value which is the user_id to hash both the user records and the order records so the output remains same and hence order records of a user gets the exact same position on the ring where that user sits which ensures user records and order records of that user is bound together on the ring. This will also ensure they are in the same partition.</p>
<p><strong>NOTE:</strong> This is the exact deliberate logical decision you need to make, here this decision works fine because we got our users and orders grouped into same partitions. This means in a partition/range some user records exist and also all order records related to these users exist with them.</p>
<p>This gets more clear further.</p>
<h3>Step 3: Now bring in physical servers — the ring gets nodes</h3>
<p>We have 2 physical machines available: call them <strong>Server 1</strong> and <strong>Server 2</strong>. To place them on the ring, we hash <em>their identifiers</em> (hostname, IP — something unique to the machine) through that same hash function. Whatever position that hash produces is where that server sits on the ring.</p>
<p>Say this hashing happens to put:</p>
<ul>
<li><p><strong>Server 1</strong> at the <strong>240°</strong> mark</p>
</li>
<li><p><strong>Server 2</strong> at the <strong>0°/360°</strong> mark (the very top, wrapping around)</p>
</li>
</ul>
<p>Now lets visualise this on our ring:-</p>
<img src="https://cdn.hashnode.com/uploads/covers/69e5c7da9bd01680c253d2b8/4f2d2fb2-7c83-456d-b6dd-2c3bdadbfa8f.png" alt="" style="display:block;margin:0 auto" />

<p>The two white circles are our servers which are placed on the ring based on a calculated value we got when we run the hash function on a unique identifier value of the servers.</p>
<p><strong>The blue and green arc are nothing but partitions</strong> which actually has data - both user and order records. Each position in the ring belongs to either blue or green part which are nothing but our partitions.</p>
<p><strong>So the placing of servers divided the ring into partitions.</strong></p>
<p><strong>In our case what these partitions contain?</strong></p>
<p>Both the green and blue arc contains:-</p>
<p>user records - say green arc has users with user id 10 - 20 and blue arc has users 1 - 10</p>
<p>hence the green arc also contains all orders for users with user id from 10- 20 and blue arc contains all orders for users with user id 1 - 10.</p>
<p><strong>What does this signify?</strong></p>
<p>We have two partitions blue and green and both partitions have a subset of data from users - some user records.</p>
<p><strong>But lets remember step 2 where we made a choice to partition the order records by the user_id, This ensured that a order record which belongs to user id = 1 (or any other user) is placed exactly where the user record with user id = 1 is placed on the ring and ensures that users and orders are partitioned but with all orders of a specific user is bound to that partition itself where the user exists.</strong></p>
<p><strong>Which shard does the data from partition goes?</strong></p>
<p>We have two partitions blue and green and two servers placed at 0°/360° and 240° on the ring.</p>
<p><strong>The ownership rule is clear: A server owns every ring position from the previous server's position (not including it) clockwise up to and including its own position.</strong></p>
<p>Hence all the data in the blue partition goes to the server placed at the point 240° and all the data inside the green partition goes to the server at 0°/360°</p>
<p>With that, you just successfully partitioned the data and also assigned them to shards with a informed design decision to partition and shard your data based on the user_id field.</p>
<h3>Why this solves the reshuffling problem</h3>
<p>Lets take a similar ring example where we have a few nodes and a few records sitting on the ring:-</p>
<p>The bigger blue circles are our actual physical servers which got their position on the ring by hashing the unique identifier value of those servers and the smaller brown circles represents some records which got their position on the ring by hashing the partition key in those records.</p>
<img src="https://cdn.hashnode.com/uploads/covers/69e5c7da9bd01680c253d2b8/0d884b12-2ffa-45ce-b848-373a0140c045.png" alt="" style="display:block;margin:0 auto" />

<p>Now suppose <strong>Node B goes down</strong>, or you add a new <strong>Node E</strong> somewhere on the ring. Only the keys sitting in the arc immediately counter-clockwise of that one node are affected — they get reassigned to the next node clockwise. Every other key, sitting on other arcs, doesn't move at all. Roughly <strong>1/N of the keys move</strong>, not all of them. That's the entire win over <code>hash % N</code>.</p>
<h3>Virtual nodes: fixing uneven load</h3>
<p>With only 2 real nodes placed on a ring, the arcs between them can be wildly uneven — one node might own 60% of the key space, another 5%. The fix used in practice (Cassandra, DynamoDB all do this): each physical node is hashed onto the ring <strong>multiple times</strong> under different virtual identifiers — <code>NodeA-1</code>, <code>NodeA-2</code>, <code>NodeA-3</code>... maybe 100–200 virtual points per physical node. This smooths out the arcs so load balances evenly, and it also means when a node fails, its load gets spread across <em>many</em> other nodes instead of dumping it all onto one neighbour.</p>
<p>This is how Consistent Hashing ensures following:-</p>
<ol>
<li><p>Data is Partitioned and Sharded effectively coupled with correct logical/design thinking.</p>
</li>
<li><p>Ensures that roughly 1/N of the total records need to reshuffle instead of all the records where N is the number of servers.</p>
</li>
</ol>
]]></content:encoded></item></channel></rss>