<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Sushant Gaurav</title>
    <description>The latest articles on DEV Community by Sushant Gaurav (@imsushant12).</description>
    <link>https://dev.to/imsushant12</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F728683%2Fd90afadb-75fb-4554-97de-06885c87683b.jpg</url>
      <title>DEV Community: Sushant Gaurav</title>
      <link>https://dev.to/imsushant12</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/imsushant12"/>
    <language>en</language>
    <item>
      <title>Rate Limiting, Circuit Breakers &amp; Handling Failures Gracefully</title>
      <dc:creator>Sushant Gaurav</dc:creator>
      <pubDate>Tue, 22 Sep 2026 05:41:00 +0000</pubDate>
      <link>https://dev.to/imsushant12/rate-limiting-circuit-breakers-handling-failures-gracefully-1chk</link>
      <guid>https://dev.to/imsushant12/rate-limiting-circuit-breakers-handling-failures-gracefully-1chk</guid>
      <description>&lt;p&gt;One of the biggest misconceptions about modern distributed systems is that they fail because servers are too slow or because there are not enough machines handling requests. While insufficient infrastructure can certainly become a bottleneck, it is rarely the root cause behind large-scale outages. In reality, some of the most significant production incidents have occurred in systems that had thousands of servers, multiple data centres, redundant databases, and sophisticated load balancers. The problem was not a lack of hardware. The problem was that the system was not prepared for failure.&lt;/p&gt;

&lt;p&gt;Imagine an e-commerce company launching its biggest sale of the year. Months of preparation have gone into the event. Engineers have increased server capacity, databases have been replicated across multiple regions, caches have been warmed, and additional instances of critical services have been deployed. Everything appears ready. At exactly 10:00 AM, the sale begins. Within seconds, millions of users start refreshing the homepage, searching for products, adding items to their carts, and attempting to complete purchases.&lt;/p&gt;

&lt;p&gt;Initially, everything works as expected. Requests are distributed across multiple application servers, response times remain low, and the infrastructure appears healthy. Then, one small problem begins to emerge. The inventory database, which keeps track of available stock, starts responding slightly slower than usual. Instead of taking 50 milliseconds to answer a query, it now takes 500 milliseconds. Half a second may not sound like much, but in a distributed system processing thousands of requests every second, that additional delay quickly becomes significant.&lt;/p&gt;

&lt;p&gt;Every checkout request must wait for the inventory service to confirm that a product is still available. Because the inventory service is now waiting longer for the database, the checkout service also begins waiting. Those waiting requests continue occupying server threads, database connections, and memory. Meanwhile, new customers continue arriving and generating even more requests. Within a few minutes, queues begin forming across multiple services. CPU utilisation rises sharply, memory consumption increases, and response times continue growing. Soon, services that were originally healthy also begin slowing down because they are waiting for other services that are already struggling.&lt;/p&gt;

&lt;p&gt;What started as a minor slowdown inside a single database has now spread throughout the entire application.&lt;/p&gt;

&lt;p&gt;This phenomenon is one of the defining challenges of distributed systems. Unlike monolithic applications, where most operations happen within a single process, distributed applications consist of dozens or even hundreds of independent services communicating continuously over the network. A single user request may pass through an API Gateway, an authentication service, a product service, an inventory service, a payment service, a notification service, and several databases before the user finally receives a response. Every additional dependency introduces another opportunity for delays, failures, or unexpected behaviour.&lt;/p&gt;

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

&lt;p&gt;At first glance, this architecture appears highly resilient because every service can scale independently. However, this same flexibility also creates a new type of risk. Services become interconnected. If one component slows down, every service depending on it begins slowing down as well. If those services become overloaded, they start affecting other services. Gradually, what began as an isolated problem spreads throughout the entire system like a chain reaction.&lt;/p&gt;

&lt;p&gt;Engineers often describe this behaviour as a &lt;strong&gt;cascading failure&lt;/strong&gt;. Much like a line of dominoes falling one after another, a failure in one component triggers failures in neighbouring components until eventually the entire application becomes unstable. Importantly, the original component that caused the issue may not even be the one users notice. Customers simply experience a website that feels slow, unresponsive, or completely unavailable.&lt;/p&gt;

&lt;p&gt;Large technology companies spend enormous amounts of time designing systems that prevent exactly this situation. Their objective is not merely to ensure that individual services remain operational. Instead, they aim to ensure that failures remain &lt;strong&gt;isolated&lt;/strong&gt;. A slow recommendation engine should never prevent users from placing orders. A malfunctioning notification service should never stop payments from being processed. An external API outage should not cause every application server to exhaust its available resources while waiting for responses that may never arrive.&lt;/p&gt;

&lt;p&gt;Achieving this level of resilience requires a fundamental shift in how engineers think about software design. Beginners often design applications assuming that every dependency will behave correctly. Every service will respond quickly. Every database query will succeed. Every network request will complete. Experienced system designers make exactly the opposite assumption. They expect services to fail. They expect networks to become unreliable. They expect traffic spikes to occur unexpectedly. Rather than hoping these situations never happen, they build systems specifically designed to continue operating when they do.&lt;/p&gt;

&lt;p&gt;This philosophy explains why modern distributed systems deliberately make decisions that initially seem counterintuitive. Sometimes they reject incoming requests even though additional users are trying to access the application. Sometimes they temporarily stop communicating with another service, even though that service may recover in a few seconds. Sometimes they return partial information instead of attempting to generate a complete response. These decisions may appear strange until one understands the goal behind them.&lt;/p&gt;

&lt;p&gt;The purpose is not to maximise the number of successful requests at any given moment.&lt;/p&gt;

&lt;p&gt;The purpose is to maximise the long-term health of the system.&lt;/p&gt;

&lt;p&gt;Consider a hospital emergency room during a major disaster. Doctors do not attempt to treat every patient simultaneously because doing so would overwhelm the entire medical staff. Instead, patients are prioritised based on urgency, and new admissions may even be redirected to nearby hospitals if capacity has been reached. Although this means some patients must wait longer, the hospital remains capable of treating those in the greatest need.&lt;/p&gt;

&lt;p&gt;Distributed systems behave in much the same way. Rather than allowing unlimited requests to consume every available resource, resilient applications establish protective mechanisms that regulate traffic, isolate failures, and recover gracefully when dependencies become unhealthy. These mechanisms prevent small problems from becoming catastrophic outages.&lt;/p&gt;

&lt;p&gt;Three design patterns have become particularly important for achieving this level of resilience.&lt;/p&gt;

&lt;p&gt;The first is &lt;strong&gt;Rate Limiting&lt;/strong&gt;, which controls how many requests clients are allowed to send, preventing systems from becoming overwhelmed during sudden traffic spikes or malicious attacks.&lt;/p&gt;

&lt;p&gt;The second is the &lt;strong&gt;Circuit Breaker Pattern&lt;/strong&gt;, which prevents applications from repeatedly communicating with services that are already failing, allowing both the calling service and the failing dependency time to recover.&lt;/p&gt;

&lt;p&gt;The third is &lt;strong&gt;Graceful Failure Handling&lt;/strong&gt;, where applications continue providing as much functionality as possible even when certain components become unavailable, ensuring that users experience degraded service rather than complete failure.&lt;/p&gt;

&lt;p&gt;Individually, each of these patterns addresses a different aspect of reliability. Together, they form one of the most important defensive strategies in distributed systems. Rather than attempting to eliminate failures, a practically impossible goal—they acknowledge that failures are inevitable and focus on containing their impact.&lt;/p&gt;

&lt;p&gt;At first, the idea of intentionally rejecting user requests seems almost contradictory. After all, the primary responsibility of a web application is to serve its users. If someone sends a request, shouldn't the system always try its best to process it?&lt;/p&gt;

&lt;p&gt;While this sounds reasonable in theory, it often leads to the exact opposite outcome in practice.&lt;/p&gt;

&lt;p&gt;Imagine a restaurant that has enough chefs to prepare one hundred meals every hour. Under normal conditions, around seventy customers arrive during that time, leaving enough capacity for the kitchen to operate efficiently. Orders are prepared quickly, waiters deliver food on time, and customers leave satisfied.&lt;/p&gt;

&lt;p&gt;Now imagine that a famous food blogger unexpectedly recommends the restaurant to millions of followers. Within minutes, five thousand customers arrive at the entrance. The restaurant has only two choices. It can either allow everyone inside, creating chaos in the kitchen, overwhelming the staff, exhausting ingredients, and ultimately disappointing every customer. Or it can temporarily stop accepting new customers until it regains control of the situation.&lt;/p&gt;

&lt;p&gt;Most well-managed restaurants choose the second option.&lt;/p&gt;

&lt;p&gt;Although some customers may have to wait or return later, the restaurant continues functioning. More importantly, the customers who are already inside still receive the quality of service they expect.&lt;/p&gt;

&lt;p&gt;Distributed systems face the same challenge.&lt;/p&gt;

&lt;p&gt;Every application has a finite amount of CPU, memory, network bandwidth, database connections, and processing threads. Regardless of whether the application runs on a single server or thousands of cloud instances, those resources are never unlimited. If incoming requests exceed the system's ability to process them, queues begin growing, response times increase, memory usage rises, and eventually the application becomes unstable.&lt;/p&gt;

&lt;p&gt;The surprising realisation is that &lt;strong&gt;processing every request is not always the best strategy&lt;/strong&gt;. Sometimes, rejecting a small percentage of requests allows the remaining ninety-nine percent to complete successfully. This principle forms the foundation of &lt;strong&gt;Rate Limiting&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding Rate Limiting
&lt;/h2&gt;

&lt;p&gt;Rate limiting is a mechanism that controls how many requests a client is allowed to make within a specified period of time. Instead of allowing unlimited traffic to reach backend services, the system establishes clear boundaries that define acceptable behaviour. Once a client exceeds those boundaries, additional requests are temporarily rejected until the allowed time window resets.&lt;/p&gt;

&lt;p&gt;Although this may sound restrictive, rate limiting serves multiple purposes beyond simply reducing traffic. It protects applications from accidental overload, prevents abuse by automated bots, limits the impact of malicious attacks, and ensures that no single client consumes a disproportionate share of system resources.&lt;/p&gt;

&lt;p&gt;Consider a public weather API that serves millions of developers around the world. If the API allowed unlimited requests, a single poorly written application caught in an infinite retry loop could generate thousands of requests every second. Even though the bug exists in only one client application, its behaviour could significantly degrade performance for every other developer using the same API.&lt;/p&gt;

&lt;p&gt;By enforcing a limit such as one hundred requests per minute for each API key, the service protects itself from misuse while still providing fair access to everyone else.&lt;/p&gt;

&lt;p&gt;This idea of &lt;strong&gt;fair resource allocation&lt;/strong&gt; is one of the primary motivations behind rate limiting.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Large Internet Companies Depend on Rate Limiting
&lt;/h2&gt;

&lt;p&gt;Almost every major technology company relies on rate limiting, even if users rarely notice it.&lt;/p&gt;

&lt;p&gt;When you use the GitHub API, you cannot make unlimited requests indefinitely. The platform enforces request limits to ensure that automated scripts do not monopolise shared infrastructure.&lt;/p&gt;

&lt;p&gt;Payment providers such as Stripe apply strict limits to protect financial systems from accidental duplicate requests and malicious abuse.&lt;/p&gt;

&lt;p&gt;Cloud providers implement request quotas to ensure that one customer cannot unintentionally consume resources needed by thousands of others.&lt;/p&gt;

&lt;p&gt;Even conversational AI platforms implement request limits. Without them, a handful of users—or even automated programs—could generate enormous volumes of requests, degrading response quality for everyone else using the service.&lt;/p&gt;

&lt;p&gt;These limits are not signs of weak infrastructure.&lt;/p&gt;

&lt;p&gt;Quite the opposite.&lt;/p&gt;

&lt;p&gt;They are evidence that the infrastructure has been designed to remain stable under unpredictable conditions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where Should Rate Limiting Be Applied?
&lt;/h2&gt;

&lt;p&gt;One of the most common questions engineers ask is where rate limiting should actually occur.&lt;/p&gt;

&lt;p&gt;Should it be implemented inside every microservice?&lt;/p&gt;

&lt;p&gt;Should databases reject excessive queries?&lt;/p&gt;

&lt;p&gt;Should the web server perform the limiting?&lt;/p&gt;

&lt;p&gt;While multiple approaches exist, the most common practice is to perform rate limiting as early as possible, before expensive backend operations begin.&lt;/p&gt;

&lt;p&gt;For this reason, many distributed systems enforce request limits at the &lt;strong&gt;API Gateway&lt;/strong&gt; or &lt;strong&gt;Load Balancer&lt;/strong&gt;.&lt;/p&gt;

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

&lt;p&gt;This placement provides an important advantage.&lt;/p&gt;

&lt;p&gt;Instead of allowing excessive traffic to travel through multiple services before finally being rejected, unwanted requests are filtered immediately at the system's entry point. Backend services never spend CPU cycles, memory, or database connections processing requests that should not have been accepted in the first place.&lt;/p&gt;

&lt;p&gt;This approach is remarkably similar to airport security. Rather than allowing passengers to enter restricted areas before checking identification, airports verify passengers at the entrance, preventing unnecessary congestion throughout the terminal.&lt;/p&gt;

&lt;h2&gt;
  
  
  Different Types of Rate Limits
&lt;/h2&gt;

&lt;p&gt;Not every client should necessarily receive the same limits.&lt;/p&gt;

&lt;p&gt;Consider a cloud platform serving both anonymous visitors and paying enterprise customers.&lt;/p&gt;

&lt;p&gt;Anonymous users might be allowed only a small number of requests each minute to discourage abuse. Registered users may receive higher limits, while enterprise customers paying for premium services could receive substantially larger quotas.&lt;/p&gt;

&lt;p&gt;Similarly, login endpoints often use much stricter limits than product search endpoints.&lt;/p&gt;

&lt;p&gt;A user might be allowed to search for products hundreds of times every minute, but only attempt five password submissions before the system temporarily blocks additional login attempts. This simple restriction dramatically reduces the effectiveness of brute-force password attacks.&lt;/p&gt;

&lt;p&gt;Rate limiting therefore becomes more than just a performance optimisation.&lt;/p&gt;

&lt;p&gt;It also becomes an important security mechanism.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Does a System Know When a User Has Exceeded the Limit?
&lt;/h2&gt;

&lt;p&gt;At this point, the overall idea of rate limiting is relatively straightforward.&lt;/p&gt;

&lt;p&gt;The more interesting question is how software actually keeps track of requests.&lt;/p&gt;

&lt;p&gt;Imagine an API serving ten million users.&lt;/p&gt;

&lt;p&gt;Every second, requests arrive from different countries, devices, and applications.&lt;/p&gt;

&lt;p&gt;How does the system determine whether a particular client has already exceeded one hundred requests during the current minute?&lt;/p&gt;

&lt;p&gt;The answer is that every incoming request is associated with some form of identity.&lt;/p&gt;

&lt;p&gt;Depending on the application, this identity could be an IP address, an authenticated user account, an API key, a session identifier, or even an organisation ID.&lt;/p&gt;

&lt;p&gt;Each request updates a small counter maintained by the rate-limiting system.&lt;/p&gt;

&lt;p&gt;Whenever another request arrives, the current count is checked against the configured limit.&lt;/p&gt;

&lt;p&gt;If the client remains within the permitted quota, the request proceeds normally.&lt;/p&gt;

&lt;p&gt;If the limit has already been exceeded, the request is rejected immediately, often with an HTTP &lt;strong&gt;429 Too Many Requests&lt;/strong&gt; response.&lt;/p&gt;

&lt;p&gt;The implementation sounds simple.&lt;/p&gt;

&lt;p&gt;However, designing a rate limiter that remains accurate while processing millions of requests every second across multiple servers is surprisingly difficult.&lt;/p&gt;

&lt;p&gt;Questions quickly begin to arise.&lt;/p&gt;

&lt;p&gt;What happens when the clock reaches the next minute?&lt;/p&gt;

&lt;p&gt;Should every counter immediately reset?&lt;/p&gt;

&lt;p&gt;How do multiple servers maintain consistent request counts?&lt;/p&gt;

&lt;p&gt;How can the system avoid sudden bursts of traffic exactly when counters reset?&lt;/p&gt;

&lt;p&gt;Answering these questions has led engineers to develop several sophisticated rate-limiting algorithms, each designed to solve different types of workload patterns.&lt;/p&gt;

&lt;p&gt;Some algorithms prioritise simplicity.&lt;/p&gt;

&lt;p&gt;Others prioritise fairness.&lt;/p&gt;

&lt;p&gt;Others are specifically designed to accommodate short bursts of traffic without allowing sustained overload.&lt;/p&gt;

&lt;p&gt;By now, we understand why modern distributed systems need rate limiting. Every application has finite resources, and allowing unlimited traffic inevitably leads to congestion, increased latency, and eventually service outages. However, knowing &lt;strong&gt;that&lt;/strong&gt; requests should be limited is only half the problem. The more interesting challenge is deciding &lt;strong&gt;how&lt;/strong&gt; those limits should actually be enforced.&lt;/p&gt;

&lt;p&gt;At first glance, the solution appears deceptively simple. Suppose an API allows one hundred requests per minute for every user. We could simply maintain a counter for each user, increment it every time a request arrives, and reset the counter when the next minute begins. If the counter reaches one hundred, every subsequent request is rejected until the minute resets.&lt;/p&gt;

&lt;p&gt;While this approach certainly works, engineers quickly discovered that it introduces an unexpected problem.&lt;/p&gt;

&lt;p&gt;Imagine the current time is 10:00:59. A client has not made a single request during the last minute. Suddenly, they send one hundred requests within a fraction of a second. Since the current minute has not yet ended, every request is accepted. One second later, the clock reaches 10:01:00, all counters are reset, and the client immediately sends another one hundred requests.&lt;/p&gt;

&lt;p&gt;Technically, the client has respected the configured limit of one hundred requests per minute.&lt;/p&gt;

&lt;p&gt;In reality, however, the server has processed two hundred requests within roughly two seconds.&lt;/p&gt;

&lt;p&gt;The system followed the rule perfectly.&lt;/p&gt;

&lt;p&gt;The rule simply was not designed well enough.&lt;/p&gt;

&lt;p&gt;This seemingly small observation has led to several different rate-limiting algorithms, each attempting to balance fairness, simplicity, performance, and implementation complexity. Rather than viewing these algorithms as competing solutions, it is more helpful to think of them as different tools designed for different workloads.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Fixed Window Algorithm
&lt;/h2&gt;

&lt;p&gt;The simplest and perhaps most intuitive rate-limiting strategy is the &lt;strong&gt;Fixed Window&lt;/strong&gt; algorithm.&lt;/p&gt;

&lt;p&gt;Time is divided into fixed intervals—for example, one minute. Every client receives a counter associated with the current window. Each incoming request increments that counter. Once the counter reaches the configured limit, all remaining requests during that window are rejected. When the next window begins, the counter is reset to zero.&lt;/p&gt;

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

&lt;p&gt;The primary advantage of this approach is its simplicity. It requires very little memory, is straightforward to implement, and performs extremely well even under heavy traffic. This is why many early APIs adopted the Fixed Window strategy.&lt;/p&gt;

&lt;p&gt;However, simplicity often comes with trade-offs.&lt;/p&gt;

&lt;p&gt;As we saw earlier, requests arriving near the boundary between two windows can effectively double the intended request rate. This phenomenon, commonly known as the &lt;strong&gt;boundary problem&lt;/strong&gt;, makes Fixed Window less suitable for systems where traffic patterns fluctuate rapidly.&lt;/p&gt;

&lt;p&gt;For many internal applications, this limitation is acceptable. For large public APIs serving millions of users, however, engineers generally prefer more sophisticated approaches.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sliding Window: A Fairer Approach
&lt;/h2&gt;

&lt;p&gt;Instead of dividing time into rigid intervals, the &lt;strong&gt;Sliding Window&lt;/strong&gt; algorithm continuously evaluates requests over the most recent time period.&lt;/p&gt;

&lt;p&gt;Suppose an API allows one hundred requests every sixty seconds.&lt;/p&gt;

&lt;p&gt;Rather than asking, "How many requests occurred during the current minute?" the Sliding Window algorithm asks a different question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"How many requests has this client made during the last sixty seconds?"&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Notice the difference.&lt;/p&gt;

&lt;p&gt;The observation window moves forward continuously with time.&lt;/p&gt;

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

&lt;p&gt;Because the window never resets abruptly, sudden bursts around minute boundaries disappear. Traffic becomes much smoother, and clients receive a more consistent experience.&lt;/p&gt;

&lt;p&gt;The trade-off is computational complexity.&lt;/p&gt;

&lt;p&gt;Instead of maintaining a single counter, the system must remember when recent requests occurred so that older requests can gradually expire from the sliding window. For applications processing millions of requests every second, this additional bookkeeping increases both memory usage and implementation complexity.&lt;/p&gt;

&lt;p&gt;Despite these challenges, Sliding Window is widely used because it produces significantly fairer traffic distribution than Fixed Window.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Leaky Bucket Algorithm
&lt;/h2&gt;

&lt;p&gt;Imagine pouring water into a bucket with a small hole at the bottom.&lt;/p&gt;

&lt;p&gt;Water may enter the bucket quickly, but it leaves at a constant rate.&lt;/p&gt;

&lt;p&gt;If water arrives faster than it can drain, the bucket eventually overflows.&lt;/p&gt;

&lt;p&gt;The Leaky Bucket algorithm applies the same idea to incoming requests.&lt;/p&gt;

&lt;p&gt;Instead of processing every request immediately, requests are placed into a queue and released at a steady rate.&lt;/p&gt;

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

&lt;p&gt;This approach produces an important benefit.&lt;/p&gt;

&lt;p&gt;Even if traffic arrives in sudden bursts, downstream services receive requests at a predictable and stable rate.&lt;/p&gt;

&lt;p&gt;Applications that perform expensive operations—such as generating reports, processing images, or communicating with slower external systems—often benefit from this smoothing effect.&lt;/p&gt;

&lt;p&gt;The drawback is that bursty traffic may experience increased waiting times. Requests that arrive together must wait for earlier requests to leave the queue, increasing latency even when the backend remains healthy.&lt;/p&gt;

&lt;p&gt;In other words, the Leaky Bucket prioritises consistency over responsiveness.&lt;/p&gt;

&lt;h2&gt;
  
  
  Token Bucket: Balancing Protection and Flexibility
&lt;/h2&gt;

&lt;p&gt;Perhaps the most widely adopted algorithm today is the &lt;strong&gt;Token Bucket&lt;/strong&gt; algorithm because it combines strong protection with enough flexibility to accommodate normal traffic patterns.&lt;/p&gt;

&lt;p&gt;The concept is surprisingly elegant.&lt;/p&gt;

&lt;p&gt;Imagine a bucket that gradually fills with tokens at a fixed rate. Every incoming request must consume one token before it can proceed. If tokens are available, the request is immediately accepted. If the bucket becomes empty, additional requests are rejected until new tokens are generated.&lt;/p&gt;

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

&lt;p&gt;Unlike the Leaky Bucket, the Token Bucket allows short bursts of activity.&lt;/p&gt;

&lt;p&gt;Suppose a user remains inactive for several seconds. During that time, unused tokens accumulate inside the bucket. When the user suddenly sends multiple requests, those stored tokens allow the requests to proceed immediately without violating the long-term rate limit.&lt;/p&gt;

&lt;p&gt;This makes the Token Bucket particularly well suited for interactive applications.&lt;/p&gt;

&lt;p&gt;Human users rarely generate perfectly uniform traffic. They may spend several minutes reading content before suddenly clicking several buttons in quick succession. Allowing these short bursts creates a smoother user experience while still protecting backend services from sustained overload.&lt;/p&gt;

&lt;p&gt;For this reason, Token Bucket has become the preferred choice for many API gateways, cloud platforms, and networking systems.&lt;/p&gt;

&lt;h2&gt;
  
  
  Choosing the Right Algorithm
&lt;/h2&gt;

&lt;p&gt;At this point, it should be clear that no single algorithm is universally superior.&lt;/p&gt;

&lt;p&gt;Each algorithm optimises for different priorities.&lt;/p&gt;

&lt;p&gt;The Fixed Window algorithm is simple, efficient, and easy to implement, but suffers from boundary effects.&lt;/p&gt;

&lt;p&gt;Sliding Window produces much fairer request distribution, although it requires more computational resources.&lt;/p&gt;

&lt;p&gt;Leaky Bucket excels at smoothing traffic and protecting downstream services from sudden bursts, making it useful for systems that require predictable processing rates.&lt;/p&gt;

&lt;p&gt;Token Bucket offers an excellent balance between fairness and flexibility by allowing temporary bursts while still enforcing long-term request limits, which explains its popularity in modern distributed systems.&lt;/p&gt;

&lt;p&gt;The most appropriate algorithm therefore depends not only on the application's traffic patterns but also on its business requirements.&lt;/p&gt;

&lt;p&gt;An authentication service protecting against brute-force attacks may prioritise strict enforcement. A streaming platform may prefer flexibility to accommodate natural user behaviour. A financial API may choose consistency above all else.&lt;/p&gt;

&lt;p&gt;Understanding these trade-offs is significantly more valuable than memorising the algorithms themselves.&lt;/p&gt;

&lt;p&gt;Up to this point, we have focused on protecting systems &lt;strong&gt;before requests enter the application&lt;/strong&gt;. Rate limiting controls incoming traffic and prevents services from becoming overwhelmed by excessive demand.&lt;/p&gt;

&lt;p&gt;But what happens when the problem does not originate from users at all?&lt;/p&gt;

&lt;p&gt;What if traffic levels remain perfectly normal, yet one of your dependencies suddenly becomes slow or completely unavailable?&lt;/p&gt;

&lt;p&gt;Should your application continue sending requests to a service that is already failing?&lt;/p&gt;

&lt;p&gt;Surprisingly, repeatedly retrying those requests often makes the situation even worse.&lt;/p&gt;

&lt;p&gt;To solve this problem, distributed systems employ another powerful resilience pattern known as the &lt;strong&gt;Circuit Breaker&lt;/strong&gt;. Instead of allowing failures to spread across services, a circuit breaker detects unhealthy dependencies, temporarily stops communication with them, and gives both systems time to recover.&lt;/p&gt;

&lt;p&gt;Up to this point, we have focused on protecting a system from &lt;strong&gt;excessive incoming traffic&lt;/strong&gt;. Rate limiting acts like a security guard standing at the entrance of a building, ensuring that only a manageable number of people are allowed inside at any given time. By controlling the rate at which requests enter the system, applications prevent themselves from becoming overwhelmed before any real damage occurs.&lt;/p&gt;

&lt;p&gt;However, not every failure originates from incoming traffic.&lt;/p&gt;

&lt;p&gt;Sometimes the application itself is healthy, the number of users is perfectly normal, and the infrastructure has more than enough resources to handle the workload. Yet requests still begin timing out, response times suddenly increase, and users start experiencing errors.&lt;/p&gt;

&lt;p&gt;In situations like these, the problem often lies &lt;strong&gt;outside the service itself&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Modern applications rarely operate in isolation. A typical microservice communicates with authentication services, payment providers, recommendation engines, notification systems, databases, search engines, cloud storage services, and numerous third-party APIs. Every one of these dependencies represents another system that can become slow, unavailable, or completely fail.&lt;/p&gt;

&lt;p&gt;The challenge is that applications generally assume these dependencies will respond within a reasonable amount of time. When they stop responding, the calling service often continues waiting patiently, hoping that the next request will succeed. Unfortunately, thousands of requests making the same assumption simultaneously can quickly exhaust the application's own resources.&lt;/p&gt;

&lt;p&gt;To understand why this happens, imagine an online travel booking platform.&lt;/p&gt;

&lt;p&gt;A customer searches for flights, selects one, enters passenger details, and finally clicks the &lt;strong&gt;Book Now&lt;/strong&gt; button. The Booking Service receives the request and immediately contacts the Payment Service to complete the transaction. Under normal conditions, the payment provider responds within a few hundred milliseconds, allowing the booking process to continue smoothly.&lt;/p&gt;

&lt;p&gt;Now imagine that the external payment provider experiences an outage.&lt;/p&gt;

&lt;p&gt;The Booking Service sends the payment request and waits.&lt;/p&gt;

&lt;p&gt;After several seconds, the request eventually times out.&lt;/p&gt;

&lt;p&gt;Meanwhile, another customer clicks &lt;strong&gt;Book Now&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A second payment request is sent.&lt;/p&gt;

&lt;p&gt;It also waits.&lt;/p&gt;

&lt;p&gt;Within a few moments, hundreds of booking requests are simultaneously waiting for responses that will never arrive.&lt;/p&gt;

&lt;p&gt;Every waiting request occupies memory, worker threads, and network connections. Although the Booking Service itself is functioning perfectly, it gradually runs out of resources because it is spending all of its time waiting for another service.&lt;/p&gt;

&lt;p&gt;Ironically, repeatedly calling the failing dependency only makes the situation worse.&lt;/p&gt;

&lt;p&gt;Instead of giving the Payment Service time to recover, thousands of additional requests continue arriving every second, increasing its workload even further. Both systems become overloaded, and what originally affected only one dependency now begins affecting the entire application.&lt;/p&gt;

&lt;p&gt;This behaviour is another example of cascading failure, but unlike the earlier example involving excessive traffic, this time the chain reaction begins with an unhealthy dependency rather than an overloaded server.&lt;/p&gt;

&lt;p&gt;The obvious question is therefore:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Should an application continue communicating with a service that is already failing?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The answer, surprisingly, is &lt;strong&gt;no&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Instead of repeatedly attempting operations that are almost certain to fail, resilient systems deliberately stop sending requests for a short period of time. This allows the failing service to recover while simultaneously protecting the calling application from wasting valuable resources.&lt;/p&gt;

&lt;p&gt;This idea is known as the &lt;strong&gt;Circuit Breaker Pattern&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding the Circuit Breaker Pattern
&lt;/h2&gt;

&lt;p&gt;The name "Circuit Breaker" comes from electrical engineering.&lt;/p&gt;

&lt;p&gt;In a home, electrical circuits contain protective switches called circuit breakers. Under normal conditions, electricity flows freely through the circuit. However, if excessive current begins flowing—perhaps because of a short circuit—the breaker immediately disconnects the circuit. Although electricity temporarily stops flowing, the interruption prevents far more serious damage such as overheating, equipment failure, or even fire.&lt;/p&gt;

&lt;p&gt;Software systems apply the same principle.&lt;/p&gt;

&lt;p&gt;Instead of electricity flowing between electrical components, requests flow between software services.&lt;/p&gt;

&lt;p&gt;Instead of excessive electrical current, the danger comes from repeated failures and long response times.&lt;/p&gt;

&lt;p&gt;Instead of physically disconnecting a wire, the application temporarily stops sending requests to the failing dependency.&lt;/p&gt;

&lt;p&gt;The objective is remarkably similar in both cases:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prevent a small problem from becoming a much larger one.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How a Circuit Breaker Protects Services
&lt;/h2&gt;

&lt;p&gt;Imagine two microservices communicating with one another.&lt;/p&gt;

&lt;p&gt;The Order Service depends on the Payment Service to complete customer purchases.&lt;/p&gt;

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

&lt;p&gt;Under normal conditions, every order request results in a successful call to the Payment Service.&lt;/p&gt;

&lt;p&gt;Now suppose the Payment Service becomes unavailable.&lt;/p&gt;

&lt;p&gt;Without any protection, every new order continues attempting payment.&lt;/p&gt;

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

&lt;p&gt;Each failed request consumes additional threads, memory, and network resources.&lt;/p&gt;

&lt;p&gt;As customer traffic continues increasing, the Order Service gradually becomes overloaded—not because it is malfunctioning, but because it is endlessly waiting for a dependency that cannot respond.&lt;/p&gt;

&lt;p&gt;Now imagine placing a circuit breaker between the two services.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4yxdhpnozm63plsj71w7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4yxdhpnozm63plsj71w7.png" alt="Circuit breaker between the two services" width="797" height="116"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Initially, requests continue flowing normally.&lt;/p&gt;

&lt;p&gt;However, once the circuit breaker observes that the Payment Service has failed repeatedly, it changes its behaviour.&lt;/p&gt;

&lt;p&gt;Instead of forwarding every request, it immediately rejects new calls without contacting the Payment Service at all.&lt;/p&gt;

&lt;p&gt;The Order Service no longer wastes time waiting for responses that are unlikely to arrive.&lt;/p&gt;

&lt;p&gt;The failing dependency receives an opportunity to recover without being flooded with additional traffic.&lt;/p&gt;

&lt;p&gt;More importantly, the rest of the application remains healthy.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Three States of a Circuit Breaker
&lt;/h2&gt;

&lt;p&gt;Although the concept sounds straightforward, circuit breakers are not simply "enabled" or "disabled."&lt;/p&gt;

&lt;p&gt;Instead, they move through three different operational states depending on the health of the downstream service.&lt;/p&gt;

&lt;h3&gt;
  
  
  Closed State
&lt;/h3&gt;

&lt;p&gt;When everything is functioning normally, the circuit breaker remains &lt;strong&gt;Closed&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In this state, every request is forwarded to the downstream service exactly as if the circuit breaker did not exist.&lt;/p&gt;

&lt;p&gt;The circuit breaker quietly monitors response times, error rates, and timeouts while allowing traffic to pass.&lt;/p&gt;

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

&lt;p&gt;At this stage, users are completely unaware that a circuit breaker exists.&lt;/p&gt;

&lt;p&gt;It simply observes the health of the dependency.&lt;/p&gt;

&lt;h3&gt;
  
  
  Open State
&lt;/h3&gt;

&lt;p&gt;Suppose the downstream service suddenly begins returning failures.&lt;/p&gt;

&lt;p&gt;After the circuit breaker observes that a predefined failure threshold has been exceeded—for example, fifty consecutive failures or an error rate above a configured percentage—it assumes the service is unhealthy.&lt;/p&gt;

&lt;p&gt;Rather than continuing to send requests that are almost guaranteed to fail, the circuit breaker &lt;strong&gt;opens&lt;/strong&gt;.&lt;/p&gt;

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

&lt;p&gt;Once open, incoming requests never reach the failing dependency.&lt;/p&gt;

&lt;p&gt;Instead, they fail immediately, allowing the application to respond much more quickly than waiting for repeated timeouts.&lt;/p&gt;

&lt;p&gt;Although this may appear harsh, it significantly improves the overall stability of the system.&lt;/p&gt;

&lt;p&gt;A fast failure is often preferable to a slow one.&lt;/p&gt;

&lt;h3&gt;
  
  
  Half-Open State
&lt;/h3&gt;

&lt;p&gt;Of course, services eventually recover.&lt;/p&gt;

&lt;p&gt;The circuit breaker therefore cannot remain open forever.&lt;/p&gt;

&lt;p&gt;After waiting for a configurable period, it enters an intermediate state known as &lt;strong&gt;Half-Open&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Rather than forwarding every request, it allows only a small number of carefully selected requests to reach the downstream service.&lt;/p&gt;

&lt;p&gt;These requests act as health probes.&lt;/p&gt;

&lt;p&gt;If they succeed, the circuit breaker concludes that the dependency has recovered and transitions back to the Closed state.&lt;/p&gt;

&lt;p&gt;If they fail again, the breaker immediately returns to the Open state and waits before testing once more.&lt;/p&gt;

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

&lt;p&gt;This gradual recovery process prevents thousands of waiting clients from simultaneously overwhelming a service that has only just restarted.&lt;/p&gt;

&lt;p&gt;Instead, traffic is restored carefully and progressively.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Fast Failure Is Better Than Slow Failure
&lt;/h2&gt;

&lt;p&gt;Many engineers instinctively believe that applications should keep retrying failed requests because the next attempt might succeed.&lt;/p&gt;

&lt;p&gt;Retries certainly have their place, especially when failures are temporary.&lt;/p&gt;

&lt;p&gt;However, unlimited retries against an already failing service usually create more problems than they solve.&lt;/p&gt;

&lt;p&gt;Every retry generates additional network traffic.&lt;/p&gt;

&lt;p&gt;Every retry occupies another application thread.&lt;/p&gt;

&lt;p&gt;Every retry increases the workload on a dependency that is already struggling.&lt;/p&gt;

&lt;p&gt;Eventually, the retries themselves become part of the outage.&lt;/p&gt;

&lt;p&gt;Circuit breakers solve this problem by recognising that continuing to attempt impossible operations serves no useful purpose.&lt;/p&gt;

&lt;p&gt;Sometimes the healthiest decision a distributed system can make is to stop trying—for a little while.&lt;/p&gt;

&lt;p&gt;This simple principle has made circuit breakers one of the most widely adopted resilience patterns in modern microservice architectures.&lt;/p&gt;

&lt;p&gt;Throughout this article, we have explored two of the most important resilience patterns used in distributed systems. We began with &lt;strong&gt;Rate Limiting&lt;/strong&gt;, where applications deliberately control incoming traffic to prevent themselves from becoming overwhelmed. We then examined the &lt;strong&gt;Circuit Breaker Pattern&lt;/strong&gt;, which prevents services from repeatedly communicating with dependencies that are already failing.&lt;/p&gt;

&lt;p&gt;Both patterns share a common objective.&lt;/p&gt;

&lt;p&gt;They protect the system before failures spread.&lt;/p&gt;

&lt;p&gt;However, they still leave us with an important question.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What should the application do after a failure has already occurred?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Suppose a recommendation service is unavailable.&lt;/p&gt;

&lt;p&gt;Should the entire website stop loading?&lt;/p&gt;

&lt;p&gt;If a notification service fails, should customers be prevented from placing orders?&lt;/p&gt;

&lt;p&gt;If an analytics platform becomes unreachable, should payments stop processing?&lt;/p&gt;

&lt;p&gt;In many cases, the answer is clearly no.&lt;/p&gt;

&lt;p&gt;Although these services are valuable, they are not equally important. Some features are essential to the application's core functionality, while others simply enhance the user experience. A resilient distributed system understands this distinction and is designed to continue providing its most critical functionality even when less important components become unavailable.&lt;/p&gt;

&lt;p&gt;This philosophy is known as &lt;strong&gt;Graceful Failure Handling&lt;/strong&gt;, or more commonly, &lt;strong&gt;Graceful Degradation&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Rather than allowing a single failure to bring down the entire application, the system accepts that some features may temporarily become unavailable while ensuring that users can still accomplish their primary objectives.&lt;/p&gt;

&lt;h2&gt;
  
  
  Not Every Failure Should Become an Outage
&lt;/h2&gt;

&lt;p&gt;Imagine opening your favourite e-commerce website.&lt;/p&gt;

&lt;p&gt;The homepage loads successfully.&lt;/p&gt;

&lt;p&gt;Products appear almost instantly.&lt;/p&gt;

&lt;p&gt;You search for a laptop, compare specifications, and decide to purchase one.&lt;/p&gt;

&lt;p&gt;During checkout, however, you notice that the "Recommended Products" section is missing.&lt;/p&gt;

&lt;p&gt;Would you abandon the purchase because personalised recommendations failed to load?&lt;/p&gt;

&lt;p&gt;Probably not.&lt;/p&gt;

&lt;p&gt;The recommendation engine improves the shopping experience, but it is not essential to completing an order.&lt;/p&gt;

&lt;p&gt;Now imagine a different situation.&lt;/p&gt;

&lt;p&gt;The recommendation engine works perfectly, but the payment service fails every time you attempt to check out.&lt;/p&gt;

&lt;p&gt;In this case, the website becomes practically useless because the application's most important business function has stopped working.&lt;/p&gt;

&lt;p&gt;This simple comparison illustrates one of the most important principles in system design:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Not every service deserves the same level of priority.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Understanding which services are mission-critical and which are optional allows architects to design systems that fail intelligently instead of failing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Graceful Degradation in Practice
&lt;/h2&gt;

&lt;p&gt;Consider the architecture of a modern streaming platform.&lt;/p&gt;

&lt;p&gt;When a user opens the application, several independent services work together to build the experience.&lt;/p&gt;

&lt;p&gt;One service authenticates the user.&lt;/p&gt;

&lt;p&gt;Another retrieves the list of available movies.&lt;/p&gt;

&lt;p&gt;A recommendation engine suggests content based on viewing history.&lt;/p&gt;

&lt;p&gt;A separate analytics service records user interactions.&lt;/p&gt;

&lt;p&gt;Another service sends notifications about newly released shows.&lt;/p&gt;

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

&lt;p&gt;Now imagine that the recommendation service suddenly becomes unavailable.&lt;/p&gt;

&lt;p&gt;Should the entire streaming platform stop functioning?&lt;/p&gt;

&lt;p&gt;Of course not.&lt;/p&gt;

&lt;p&gt;A much better approach is to temporarily hide the recommendation section while continuing to display the movie catalogue.&lt;/p&gt;

&lt;p&gt;The user can still browse content, watch movies, and enjoy the platform.&lt;/p&gt;

&lt;p&gt;The application has degraded gracefully rather than failing completely.&lt;/p&gt;

&lt;p&gt;This approach prioritises the features that matter most to users while temporarily sacrificing less important functionality.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fallbacks: Having a Plan B
&lt;/h2&gt;

&lt;p&gt;One of the most common techniques used during graceful degradation is the concept of a &lt;strong&gt;fallback&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A fallback is simply an alternative response that the application returns when the preferred operation cannot be completed.&lt;/p&gt;

&lt;p&gt;Imagine a weather application that normally retrieves forecasts from a third-party weather provider.&lt;/p&gt;

&lt;p&gt;If the provider becomes unavailable, the application has several possible choices.&lt;/p&gt;

&lt;p&gt;It could display the most recently cached forecast.&lt;/p&gt;

&lt;p&gt;It could return a simplified forecast from another provider.&lt;/p&gt;

&lt;p&gt;Or it could simply inform the user that live weather information is temporarily unavailable.&lt;/p&gt;

&lt;p&gt;Any of these options is generally preferable to allowing the entire application to crash.&lt;/p&gt;

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

&lt;p&gt;Fallbacks are widely used across distributed systems because they allow applications to continue serving useful responses even when external dependencies experience problems.&lt;/p&gt;

&lt;p&gt;Although the returned information may not be perfect, it is often significantly better than returning an error page.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Timeouts Matter
&lt;/h2&gt;

&lt;p&gt;One subtle but extremely important aspect of graceful failure handling is knowing &lt;strong&gt;when to stop waiting&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Suppose an application sends a request to another service.&lt;/p&gt;

&lt;p&gt;If no response arrives after one second, should it continue waiting?&lt;/p&gt;

&lt;p&gt;What about ten seconds?&lt;/p&gt;

&lt;p&gt;Or one minute?&lt;/p&gt;

&lt;p&gt;Without clearly defined limits, applications can spend enormous amounts of time waiting for responses that may never arrive.&lt;/p&gt;

&lt;p&gt;Those waiting requests continue consuming memory, threads, and network connections.&lt;/p&gt;

&lt;p&gt;Eventually, the application itself begins slowing down despite being perfectly healthy.&lt;/p&gt;

&lt;p&gt;This is why modern distributed systems almost always configure &lt;strong&gt;timeouts&lt;/strong&gt; for communication between services.&lt;/p&gt;

&lt;p&gt;Instead of waiting indefinitely, requests are automatically abandoned after a predefined period.&lt;/p&gt;

&lt;p&gt;The application can then trigger a fallback response, retry the request if appropriate, or simply inform the user that the operation could not be completed.&lt;/p&gt;

&lt;p&gt;Timeouts work particularly well when combined with circuit breakers.&lt;/p&gt;

&lt;p&gt;The timeout detects that a dependency has become slow.&lt;/p&gt;

&lt;p&gt;The circuit breaker notices repeated failures.&lt;/p&gt;

&lt;p&gt;Eventually, the breaker opens, preventing further requests from reaching the unhealthy service until recovery begins.&lt;/p&gt;

&lt;p&gt;Together, these mechanisms stop small delays from escalating into widespread outages.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bringing Everything Together
&lt;/h2&gt;

&lt;p&gt;By now, it should be clear that these resilience patterns are not independent techniques.&lt;/p&gt;

&lt;p&gt;They complement one another.&lt;/p&gt;

&lt;p&gt;Imagine a customer attempting to place an order during an unusually busy shopping event.&lt;/p&gt;

&lt;p&gt;The request first reaches the API Gateway, where &lt;strong&gt;Rate Limiting&lt;/strong&gt; ensures that incoming traffic remains within safe operating limits.&lt;/p&gt;

&lt;p&gt;The request is then forwarded to the Order Service, which communicates with the Payment Service through a &lt;strong&gt;Circuit Breaker&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If the payment provider begins failing, the circuit breaker quickly opens, preventing thousands of additional requests from overwhelming both services.&lt;/p&gt;

&lt;p&gt;Finally, if certain non-essential services such as recommendation engines or notification systems become unavailable, &lt;strong&gt;Graceful Degradation&lt;/strong&gt; ensures that the checkout process continues while those optional features are temporarily disabled.&lt;/p&gt;

&lt;p&gt;The entire flow looks something like this.&lt;/p&gt;

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

&lt;p&gt;Notice how each resilience pattern solves a different problem.&lt;/p&gt;

&lt;p&gt;Rate limiting protects the application from excessive demand.&lt;/p&gt;

&lt;p&gt;Circuit breakers protect services from failing dependencies.&lt;/p&gt;

&lt;p&gt;Graceful degradation protects the user experience when failures inevitably occur.&lt;/p&gt;

&lt;p&gt;Individually, each technique improves reliability.&lt;/p&gt;

&lt;p&gt;Together, they create systems capable of surviving situations that would otherwise result in complete outages.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reliability Is About Trade-offs, Not Perfection
&lt;/h2&gt;

&lt;p&gt;One recurring theme throughout this System Design series is that there are very few absolute answers.&lt;/p&gt;

&lt;p&gt;No architecture guarantees perfect scalability.&lt;/p&gt;

&lt;p&gt;No consistency model is always correct.&lt;/p&gt;

&lt;p&gt;There is no caching strategy that works for every workload.&lt;/p&gt;

&lt;p&gt;Reliability follows the same pattern.&lt;/p&gt;

&lt;p&gt;Every resilience mechanism introduces trade-offs.&lt;/p&gt;

&lt;p&gt;Rate limiting may reject legitimate requests during periods of exceptionally high demand.&lt;/p&gt;

&lt;p&gt;Circuit breakers may temporarily deny requests even after a service has recovered if recovery thresholds are configured too conservatively.&lt;/p&gt;

&lt;p&gt;Fallback responses may return stale or incomplete information instead of live data.&lt;/p&gt;

&lt;p&gt;Yet these trade-offs are almost always preferable to complete system failure.&lt;/p&gt;

&lt;p&gt;A slightly degraded application is far more valuable than one that is entirely unavailable.&lt;/p&gt;

&lt;p&gt;Modern distributed systems are therefore designed with a simple philosophy:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Accept that failures will happen, isolate them quickly, and recover gracefully without affecting the rest of the system.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That single idea lies at the heart of resilient software architecture.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;As software systems continue evolving into increasingly distributed architectures, resilience is no longer a luxury—it is a fundamental requirement. Every dependency introduces another opportunity for failure, and every new feature adds another layer of complexity. Engineers cannot eliminate these failures, but they can control how systems respond to them.&lt;/p&gt;

&lt;p&gt;Rate limiting prevents applications from accepting more work than they can safely process.&lt;/p&gt;

&lt;p&gt;Circuit breakers prevent failures from spreading across service boundaries.&lt;/p&gt;

&lt;p&gt;Graceful degradation ensures that users continue receiving value even when parts of the application become unavailable.&lt;/p&gt;

&lt;p&gt;Together, these patterns transform software from a collection of independent services into a resilient system capable of operating under real-world conditions, where failures are not exceptional events but expected realities.&lt;/p&gt;

&lt;p&gt;Perhaps the most important lesson is that reliability is not measured by how rarely a system fails. It is measured by &lt;strong&gt;how well the system continues serving users when failures inevitably occur&lt;/strong&gt;. That mindset separates software that merely works from software that remains dependable at scale.&lt;/p&gt;

</description>
      <category>systemdesign</category>
      <category>architecture</category>
      <category>programming</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Designing for Reliability: Redundancy, Replication, and Fault Tolerance</title>
      <dc:creator>Sushant Gaurav</dc:creator>
      <pubDate>Tue, 08 Sep 2026 05:41:00 +0000</pubDate>
      <link>https://dev.to/imsushant12/designing-for-reliability-redundancy-replication-and-fault-tolerance-3238</link>
      <guid>https://dev.to/imsushant12/designing-for-reliability-redundancy-replication-and-fault-tolerance-3238</guid>
      <description>&lt;p&gt;If there is one assumption every software engineer eventually learns to make, it is this:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Failures are not exceptional events—they are inevitable.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Servers crash. Hard disks fail. Network cables get unplugged. Data centers lose power. Cloud regions experience outages. Software contains bugs. Human operators make mistakes. Even seemingly reliable hardware eventually reaches the end of its lifespan.&lt;/p&gt;

&lt;p&gt;When applications are small, these failures are often inconvenient but manageable. A company may simply restart the server or restore a backup. Users might experience a few minutes of downtime, but the impact remains relatively limited.&lt;/p&gt;

&lt;p&gt;As systems grow larger, however, this mindset no longer works.&lt;/p&gt;

&lt;p&gt;Imagine an online banking platform serving millions of customers. Or a streaming service with viewers spread across the globe. Or an e-commerce platform processing thousands of orders every second during a major shopping festival.&lt;/p&gt;

&lt;p&gt;For these applications, even a few minutes of downtime can translate into millions of dollars in lost revenue, damaged customer trust, and long-term reputational harm.&lt;/p&gt;

&lt;p&gt;The question therefore changes.&lt;/p&gt;

&lt;p&gt;Instead of asking,&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"How do we prevent failures?"&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;experienced system designers ask,&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"How do we keep the system running even when failures occur?"&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That single shift in thinking defines modern distributed systems.&lt;/p&gt;

&lt;p&gt;Reliability is not achieved by building components that never fail.&lt;/p&gt;

&lt;p&gt;Reliability is achieved by designing systems that continue functioning despite failures.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reliability Is More Than Just Uptime
&lt;/h2&gt;

&lt;p&gt;When people hear the word &lt;em&gt;reliable&lt;/em&gt;, they often think of uptime.&lt;/p&gt;

&lt;p&gt;If an application remains online, it must be reliable.&lt;/p&gt;

&lt;p&gt;While availability is certainly an important aspect of reliability, the two concepts are not identical.&lt;/p&gt;

&lt;p&gt;Consider an online shopping website.&lt;/p&gt;

&lt;p&gt;Suppose customers can still browse products, but every payment attempt fails because the payment service has crashed.&lt;/p&gt;

&lt;p&gt;Technically, the website is still online.&lt;/p&gt;

&lt;p&gt;Yet very few people would call it reliable.&lt;/p&gt;

&lt;p&gt;Now imagine another scenario.&lt;/p&gt;

&lt;p&gt;The payment succeeds, but inventory updates are lost because one database server failed before writing the latest stock count.&lt;/p&gt;

&lt;p&gt;Again, the application appears available.&lt;/p&gt;

&lt;p&gt;However, it is no longer behaving correctly.&lt;/p&gt;

&lt;p&gt;A reliable system is therefore one that continues delivering its intended functionality despite unexpected failures.&lt;/p&gt;

&lt;p&gt;It is not simply about remaining accessible.&lt;/p&gt;

&lt;p&gt;It is about continuing to perform the operations users depend upon.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Failures Become More Common as Systems Grow
&lt;/h2&gt;

&lt;p&gt;A single-server application contains relatively few moving parts.&lt;/p&gt;

&lt;p&gt;One application.&lt;/p&gt;

&lt;p&gt;One database.&lt;/p&gt;

&lt;p&gt;One machine.&lt;/p&gt;

&lt;p&gt;Naturally, there are fewer opportunities for something to go wrong.&lt;/p&gt;

&lt;p&gt;Modern distributed systems look very different.&lt;/p&gt;

&lt;p&gt;A single user request might involve an API Gateway, an authentication service, an order service, a payment service, an inventory service, a cache, multiple databases, a message broker, and several third-party APIs.&lt;/p&gt;

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

&lt;p&gt;Every additional component improves scalability, flexibility, or maintainability.&lt;/p&gt;

&lt;p&gt;However, every additional component also introduces another potential point of failure.&lt;/p&gt;

&lt;p&gt;If even one critical dependency becomes unavailable, the entire request may fail.&lt;/p&gt;

&lt;p&gt;Ironically, the very architectures that allow systems to scale also make them more vulnerable to failures.&lt;/p&gt;

&lt;p&gt;This is why reliability becomes one of the central concerns in distributed system design.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Philosophy of Designing for Failure
&lt;/h2&gt;

&lt;p&gt;One of the biggest differences between beginner and experienced engineers is how they think about failures.&lt;/p&gt;

&lt;p&gt;Beginners often assume that failures are rare exceptions.&lt;/p&gt;

&lt;p&gt;Experienced engineers assume failures are guaranteed.&lt;/p&gt;

&lt;p&gt;This difference influences every architectural decision.&lt;/p&gt;

&lt;p&gt;Instead of asking,&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"What happens if the server crashes?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;they ask,&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"When the server crashes, what happens next?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Instead of asking,&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"What if the database becomes unavailable?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;they ask,&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"How quickly can another database take over?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This philosophy is commonly known as &lt;strong&gt;designing for failure&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Rather than attempting to eliminate failures—which is practically impossible—the goal is to ensure that failures remain isolated and recoverable.&lt;/p&gt;

&lt;p&gt;A well-designed distributed system accepts that individual components will eventually fail.&lt;/p&gt;

&lt;p&gt;The overall system should not.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three Pillars of Reliability
&lt;/h2&gt;

&lt;p&gt;Although reliability encompasses many different engineering practices, most distributed systems achieve it through three fundamental ideas.&lt;/p&gt;

&lt;p&gt;The first is &lt;strong&gt;redundancy&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Critical components should never exist as a single copy. If one server fails, another should already be available to continue serving requests.&lt;/p&gt;

&lt;p&gt;The second is &lt;strong&gt;replication&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Important data should be stored on multiple machines rather than on a single storage device. If hardware fails, information remains available elsewhere.&lt;/p&gt;

&lt;p&gt;The third is &lt;strong&gt;fault tolerance&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Even when failures occur, the application should continue operating with little or no disruption to users.&lt;/p&gt;

&lt;p&gt;Although these concepts are closely related, they solve different problems.&lt;/p&gt;

&lt;p&gt;Understanding the distinction between them is essential because they are often confused with one another.&lt;/p&gt;

&lt;p&gt;The remainder of this article will explore each concept individually before showing how they work together to build highly reliable systems.&lt;/p&gt;

&lt;h2&gt;
  
  
  Redundancy: Never Depend on a Single Component
&lt;/h2&gt;

&lt;p&gt;Imagine a suspension bridge supported by only one steel cable.&lt;/p&gt;

&lt;p&gt;If that cable snaps, the bridge immediately collapses.&lt;/p&gt;

&lt;p&gt;Now imagine the same bridge supported by dozens of independent cables.&lt;/p&gt;

&lt;p&gt;Losing one cable no longer causes disaster because the remaining cables continue carrying the load.&lt;/p&gt;

&lt;p&gt;Distributed systems apply the same principle.&lt;/p&gt;

&lt;p&gt;Whenever a component is critical to the application's operation, relying on a single instance becomes extremely risky.&lt;/p&gt;

&lt;p&gt;Suppose an application is deployed on just one server.&lt;/p&gt;

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

&lt;p&gt;Everything works perfectly until that server experiences a hardware failure.&lt;/p&gt;

&lt;p&gt;At that moment, the application becomes completely unavailable.&lt;/p&gt;

&lt;p&gt;Now consider a different architecture.&lt;/p&gt;

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

&lt;p&gt;Instead of depending on one server, requests are distributed across several identical instances.&lt;/p&gt;

&lt;p&gt;If one server crashes, the load balancer simply redirects traffic to the remaining healthy servers.&lt;/p&gt;

&lt;p&gt;Most users may never even notice that a failure occurred.&lt;/p&gt;

&lt;p&gt;This is redundancy in its simplest form.&lt;/p&gt;

&lt;p&gt;The purpose of redundancy is not to make systems faster.&lt;/p&gt;

&lt;p&gt;Its primary purpose is to eliminate &lt;strong&gt;single points of failure&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is a Single Point of Failure?
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;Single Point of Failure (SPOF)&lt;/strong&gt; is any component whose failure causes the entire system—or a critical part of it—to stop functioning.&lt;/p&gt;

&lt;p&gt;Single points of failure are dangerous because they concentrate risk.&lt;/p&gt;

&lt;p&gt;If everything depends on one component, the reliability of the entire application becomes limited by that component.&lt;/p&gt;

&lt;p&gt;Consider a system with three application servers but only one database.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fj8dztzavue4m4wxrgs3n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fj8dztzavue4m4wxrgs3n.png" alt="A system with three application servers but only one database" width="800" height="790"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Although the application layer is redundant, the database remains a single point of failure.&lt;/p&gt;

&lt;p&gt;If that database crashes, every application server loses access to the data it needs.&lt;/p&gt;

&lt;p&gt;The application effectively stops working.&lt;/p&gt;

&lt;p&gt;Identifying and eliminating single points of failure is therefore one of the first responsibilities of system architects.&lt;/p&gt;

&lt;p&gt;Every critical dependency should eventually have a backup plan.&lt;/p&gt;

&lt;p&gt;By running several application servers instead of one, the system can continue serving users even if an individual server crashes.&lt;/p&gt;

&lt;p&gt;At first glance, it may seem that redundancy alone is enough to build a reliable system.&lt;/p&gt;

&lt;p&gt;After all, if every component has a backup, what else could go wrong?&lt;/p&gt;

&lt;p&gt;The answer lies in one important observation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Application servers can usually be recreated. Data cannot.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If an application server crashes, we can simply start another one from the same deployment package or container image.&lt;/p&gt;

&lt;p&gt;If the only copy of a customer's payment history, medical records, or financial transactions disappears, recreating that data is impossible.&lt;/p&gt;

&lt;p&gt;Infrastructure can be rebuilt.&lt;/p&gt;

&lt;p&gt;Lost data often cannot.&lt;/p&gt;

&lt;p&gt;This is why distributed systems treat data very differently from application code.&lt;/p&gt;

&lt;p&gt;Rather than simply deploying multiple servers, they create multiple &lt;strong&gt;copies of the data itself&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This brings us to one of the most fundamental concepts in distributed systems:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Replication.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is Replication?
&lt;/h2&gt;

&lt;p&gt;Replication is the process of maintaining multiple copies of the same data on different machines.&lt;/p&gt;

&lt;p&gt;The goal is straightforward.&lt;/p&gt;

&lt;p&gt;If one database server becomes unavailable, another server should already contain the same information and be capable of continuing operations.&lt;/p&gt;

&lt;p&gt;Notice the subtle difference between redundancy and replication.&lt;/p&gt;

&lt;p&gt;Redundancy creates additional infrastructure.&lt;/p&gt;

&lt;p&gt;Replication creates additional copies of data.&lt;/p&gt;

&lt;p&gt;Although these concepts work together, they solve different problems.&lt;/p&gt;

&lt;p&gt;Consider a database deployed on a single machine.&lt;/p&gt;

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

&lt;p&gt;Every customer record, transaction, product, and order exists in exactly one location.&lt;/p&gt;

&lt;p&gt;As long as that machine remains healthy, everything works normally.&lt;/p&gt;

&lt;p&gt;But if its storage device fails, the application immediately loses access to its data.&lt;/p&gt;

&lt;p&gt;Now imagine introducing replicas.&lt;/p&gt;

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

&lt;p&gt;The application still has one primary database responsible for accepting writes.&lt;/p&gt;

&lt;p&gt;However, every change made to the primary is copied to multiple replicas.&lt;/p&gt;

&lt;p&gt;Now, if one machine fails, another already contains the same information.&lt;/p&gt;

&lt;p&gt;The system has become significantly more resilient.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Replication Matters
&lt;/h2&gt;

&lt;p&gt;Imagine running an online banking platform.&lt;/p&gt;

&lt;p&gt;Every deposit, withdrawal, and transfer updates customer balances stored in a database.&lt;/p&gt;

&lt;p&gt;Suppose that database exists on only one physical server.&lt;/p&gt;

&lt;p&gt;One afternoon, the server's storage device experiences a catastrophic failure.&lt;/p&gt;

&lt;p&gt;Without replication, every transaction that has not been backed up is gone.&lt;/p&gt;

&lt;p&gt;Even if backups exist, restoring them may take hours.&lt;/p&gt;

&lt;p&gt;Customers lose access to their accounts.&lt;/p&gt;

&lt;p&gt;Businesses cannot process payments.&lt;/p&gt;

&lt;p&gt;Trust disappears almost instantly.&lt;/p&gt;

&lt;p&gt;Now consider the same application with replicated databases.&lt;/p&gt;

&lt;p&gt;The primary server unexpectedly crashes.&lt;/p&gt;

&lt;p&gt;Although one database becomes unavailable, another replica already contains nearly identical information.&lt;/p&gt;

&lt;p&gt;Instead of restoring backups from scratch, the application promotes one of the replicas to become the new primary.&lt;/p&gt;

&lt;p&gt;Users experience only a brief interruption—or perhaps none at all.&lt;/p&gt;

&lt;p&gt;The application survives because the data survived.&lt;/p&gt;

&lt;p&gt;Replication protects one of the most valuable assets any software system possesses:&lt;/p&gt;

&lt;p&gt;Its information.&lt;/p&gt;

&lt;h2&gt;
  
  
  Primary-Replica Architecture
&lt;/h2&gt;

&lt;p&gt;The most common replication strategy is known as &lt;strong&gt;Primary-Replica Replication&lt;/strong&gt;, sometimes called &lt;strong&gt;Leader-Follower Replication&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In this architecture, one database acts as the primary.&lt;/p&gt;

&lt;p&gt;Every write operation flows through this server.&lt;/p&gt;

&lt;p&gt;The remaining replicas continuously receive updates from the primary.&lt;/p&gt;

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

&lt;p&gt;Whenever a customer places an order, the write is first stored on the primary database.&lt;/p&gt;

&lt;p&gt;The primary then propagates the change to its replicas.&lt;/p&gt;

&lt;p&gt;These replicas remain synchronised so that they can take over if the primary becomes unavailable.&lt;/p&gt;

&lt;p&gt;Many relational databases, including PostgreSQL and MySQL, support this replication model because it balances simplicity with reliability.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reads and Writes Are Treated Differently
&lt;/h2&gt;

&lt;p&gt;One interesting property of primary-replica architectures is that not every request must go to the primary database.&lt;/p&gt;

&lt;p&gt;Write operations almost always target the primary because allowing multiple independent servers to modify the same data simultaneously introduces significant coordination challenges.&lt;/p&gt;

&lt;p&gt;Read operations, however, are often distributed across replicas.&lt;/p&gt;

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

&lt;p&gt;This architecture provides two important benefits.&lt;/p&gt;

&lt;p&gt;First, the primary handles fewer read requests, allowing it to focus on processing writes efficiently.&lt;/p&gt;

&lt;p&gt;Second, multiple replicas can serve read traffic simultaneously, significantly increasing the system's overall throughput.&lt;/p&gt;

&lt;p&gt;This approach is extremely common in applications where reads greatly outnumber writes.&lt;/p&gt;

&lt;p&gt;Social media platforms, e-commerce websites, streaming services, and news portals all spend far more time serving content than modifying it.&lt;/p&gt;

&lt;p&gt;Replication therefore improves not only reliability but also scalability.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Happens When the Primary Fails?
&lt;/h2&gt;

&lt;p&gt;Replication becomes truly valuable during failures.&lt;/p&gt;

&lt;p&gt;Imagine that the primary database suddenly becomes unavailable.&lt;/p&gt;

&lt;p&gt;Without replication, every application attempting to write data immediately fails.&lt;/p&gt;

&lt;p&gt;With replication, however, the system can perform a process known as &lt;strong&gt;failover&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Failover simply means transferring responsibility from a failed component to a healthy one.&lt;/p&gt;

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

&lt;p&gt;Instead of waiting for the failed server to recover, one of the replicas becomes the new primary.&lt;/p&gt;

&lt;p&gt;Applications reconnect to the newly promoted server and continue operating.&lt;/p&gt;

&lt;p&gt;From the user's perspective, the interruption may last only a few seconds.&lt;/p&gt;

&lt;p&gt;This automatic transition is one of the defining characteristics of highly available systems.&lt;/p&gt;

&lt;h2&gt;
  
  
  Replication Is Not Free
&lt;/h2&gt;

&lt;p&gt;At this point, replication sounds like the perfect solution.&lt;/p&gt;

&lt;p&gt;More copies of the data.&lt;/p&gt;

&lt;p&gt;Better availability.&lt;/p&gt;

&lt;p&gt;Improved read scalability.&lt;/p&gt;

&lt;p&gt;Automatic recovery from failures.&lt;/p&gt;

&lt;p&gt;So why doesn't every distributed system simply replicate everything?&lt;/p&gt;

&lt;p&gt;Because replication introduces its own challenges.&lt;/p&gt;

&lt;p&gt;Every time data changes, every replica must eventually receive the update.&lt;/p&gt;

&lt;p&gt;Until synchronisation completes, different replicas may temporarily contain different versions of the same information.&lt;/p&gt;

&lt;p&gt;If a customer updates their shipping address and immediately performs another request, one replica may already contain the new address while another still returns the previous one.&lt;/p&gt;

&lt;p&gt;Suddenly, we encounter a familiar concept.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Consistency.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In our previous article, we explored the trade-offs between strong consistency and eventual consistency.&lt;/p&gt;

&lt;p&gt;Replication is one of the primary reasons those consistency models exist.&lt;/p&gt;

&lt;p&gt;The more copies of data we maintain, the harder it becomes to ensure that every copy remains synchronised at every moment.&lt;/p&gt;

&lt;p&gt;In other words, replication improves reliability while simultaneously introducing coordination challenges.&lt;/p&gt;

&lt;p&gt;This is one of the recurring themes throughout distributed systems.&lt;/p&gt;

&lt;p&gt;Every solution creates new engineering problems that must be solved thoughtfully.&lt;/p&gt;

&lt;h2&gt;
  
  
  Redundancy vs Replication
&lt;/h2&gt;

&lt;p&gt;Because these two terms are frequently confused, it is useful to summarise the distinction before moving forward.&lt;/p&gt;

&lt;p&gt;Redundancy focuses on &lt;strong&gt;components&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If one application server fails, another should already be available.&lt;/p&gt;

&lt;p&gt;Replication focuses on &lt;strong&gt;data&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If one database fails, another should already contain the same information.&lt;/p&gt;

&lt;p&gt;A useful way to remember the difference is this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Redundancy protects services. Replication protects information.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Modern distributed systems almost always employ both.&lt;/p&gt;

&lt;p&gt;Running multiple application servers without replicated databases still leaves the data vulnerable.&lt;/p&gt;

&lt;p&gt;Replicating databases without redundant application servers still leaves users unable to access the application when servers fail.&lt;/p&gt;

&lt;p&gt;Reliable systems require both infrastructure redundancy and data replication working together.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is Fault Tolerance?
&lt;/h2&gt;

&lt;p&gt;Fault tolerance is the ability of a system to continue operating correctly even when one or more of its components fail.&lt;/p&gt;

&lt;p&gt;Notice the wording carefully.&lt;/p&gt;

&lt;p&gt;The objective is not to prevent failures.&lt;/p&gt;

&lt;p&gt;Failures are inevitable.&lt;/p&gt;

&lt;p&gt;Instead, the objective is to prevent those failures from becoming service outages.&lt;/p&gt;

&lt;p&gt;Imagine driving a modern car.&lt;/p&gt;

&lt;p&gt;If one tyre suddenly bursts, the vehicle does not instantly stop functioning.&lt;/p&gt;

&lt;p&gt;Safety systems help the driver maintain control until they can safely stop.&lt;/p&gt;

&lt;p&gt;The failure still occurs.&lt;/p&gt;

&lt;p&gt;The system simply handles it gracefully.&lt;/p&gt;

&lt;p&gt;Distributed systems follow the same philosophy.&lt;/p&gt;

&lt;p&gt;When an application server crashes, another server should automatically begin handling requests.&lt;/p&gt;

&lt;p&gt;When a database becomes unavailable, a healthy replica should take over.&lt;/p&gt;

&lt;p&gt;When one availability zone experiences an outage, traffic should be redirected to another.&lt;/p&gt;

&lt;p&gt;Users should experience little or no disruption.&lt;/p&gt;

&lt;p&gt;Fault tolerance is therefore about &lt;strong&gt;maintaining service despite failures&lt;/strong&gt;, not eliminating failures.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building Systems That Expect Failure
&lt;/h2&gt;

&lt;p&gt;One of the biggest mindset shifts in distributed systems is moving from &lt;em&gt;failure prevention&lt;/em&gt; to &lt;em&gt;failure management&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Traditional software often assumes that servers will remain available.&lt;/p&gt;

&lt;p&gt;Distributed systems assume exactly the opposite.&lt;/p&gt;

&lt;p&gt;Every component is treated as if it could fail at any moment.&lt;/p&gt;

&lt;p&gt;This assumption influences every architectural decision.&lt;/p&gt;

&lt;p&gt;Instead of asking,&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Will this service ever fail?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;engineers ask,&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"What happens when this service fails?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Suppose an application depends on a recommendation engine to suggest products to customers.&lt;/p&gt;

&lt;p&gt;If the recommendation service crashes, should the checkout process stop working?&lt;/p&gt;

&lt;p&gt;Probably not.&lt;/p&gt;

&lt;p&gt;A better design allows customers to continue purchasing products while temporarily hiding personalised recommendations.&lt;/p&gt;

&lt;p&gt;The system loses a non-essential feature.&lt;/p&gt;

&lt;p&gt;The core business functionality continues operating.&lt;/p&gt;

&lt;p&gt;This approach is known as &lt;strong&gt;graceful degradation&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Graceful Degradation
&lt;/h2&gt;

&lt;p&gt;Not every component inside an application has the same level of importance.&lt;/p&gt;

&lt;p&gt;Some services are essential.&lt;/p&gt;

&lt;p&gt;Others simply improve the user experience.&lt;/p&gt;

&lt;p&gt;A well-designed distributed system recognises this difference.&lt;/p&gt;

&lt;p&gt;Imagine watching a movie on a streaming platform.&lt;/p&gt;

&lt;p&gt;If the recommendation service becomes unavailable, you might stop seeing personalised suggestions.&lt;/p&gt;

&lt;p&gt;However, the movie itself should continue playing without interruption.&lt;/p&gt;

&lt;p&gt;Similarly, an online shopping platform should continue accepting orders even if its analytics service temporarily stops processing events.&lt;/p&gt;

&lt;p&gt;Customers care far more about completing purchases than updating business dashboards.&lt;/p&gt;

&lt;p&gt;This idea is illustrated below.&lt;/p&gt;

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

&lt;p&gt;Instead of allowing one failing service to bring down the entire application, the system isolates the failure and continues providing its most important functionality.&lt;/p&gt;

&lt;p&gt;This philosophy is one of the defining characteristics of resilient software.&lt;/p&gt;

&lt;h2&gt;
  
  
  Detecting Failures Automatically
&lt;/h2&gt;

&lt;p&gt;Fault tolerance depends on quickly identifying unhealthy components.&lt;/p&gt;

&lt;p&gt;A system cannot recover from failures it does not detect.&lt;/p&gt;

&lt;p&gt;For this reason, distributed systems continuously monitor the health of their services.&lt;/p&gt;

&lt;p&gt;Load balancers periodically send lightweight &lt;strong&gt;health check&lt;/strong&gt; requests to application servers.&lt;/p&gt;

&lt;p&gt;If a server responds successfully, it continues receiving traffic.&lt;/p&gt;

&lt;p&gt;If it stops responding, the load balancer automatically removes it from the pool.&lt;/p&gt;

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

&lt;p&gt;Notice that users do not need to know a server has failed.&lt;/p&gt;

&lt;p&gt;The infrastructure quietly redirects requests to healthy instances.&lt;/p&gt;

&lt;p&gt;Once the failed server recovers, it can safely rejoin the system.&lt;/p&gt;

&lt;p&gt;Health checks form the foundation of automatic recovery in modern cloud platforms and container orchestration systems such as Kubernetes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Automatic Recovery and Self-Healing Systems
&lt;/h2&gt;

&lt;p&gt;Detecting failures is only the first step.&lt;/p&gt;

&lt;p&gt;The next challenge is recovering automatically.&lt;/p&gt;

&lt;p&gt;Modern distributed systems increasingly rely on &lt;strong&gt;self-healing&lt;/strong&gt; infrastructure.&lt;/p&gt;

&lt;p&gt;Suppose an application is configured to always run four instances.&lt;/p&gt;

&lt;p&gt;If one instance crashes unexpectedly, the orchestration platform immediately notices that only three instances remain.&lt;/p&gt;

&lt;p&gt;Instead of waiting for a human operator, it automatically launches a replacement.&lt;/p&gt;

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

&lt;p&gt;This idea may seem simple, but it fundamentally changes system operations.&lt;/p&gt;

&lt;p&gt;Applications no longer depend on engineers manually restarting failed servers.&lt;/p&gt;

&lt;p&gt;The infrastructure continuously restores the desired state on its own.&lt;/p&gt;

&lt;p&gt;Cloud-native platforms such as Kubernetes have made this style of self-healing architecture a standard practice.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reliability Requires Layers of Protection
&lt;/h2&gt;

&lt;p&gt;One of the most important lessons in system design is that no single technique makes a system reliable.&lt;/p&gt;

&lt;p&gt;Instead, reliability emerges from multiple layers working together.&lt;/p&gt;

&lt;p&gt;Consider an online banking platform.&lt;/p&gt;

&lt;p&gt;Multiple application servers provide redundancy.&lt;/p&gt;

&lt;p&gt;Database replication protects customer information.&lt;/p&gt;

&lt;p&gt;Health checks identify failed services.&lt;/p&gt;

&lt;p&gt;Load balancers redirect traffic.&lt;/p&gt;

&lt;p&gt;Automatic failover promotes replicas when necessary.&lt;/p&gt;

&lt;p&gt;Backups protect against catastrophic data loss.&lt;/p&gt;

&lt;p&gt;Monitoring systems alert engineers when unusual behaviour occurs.&lt;/p&gt;

&lt;p&gt;Each mechanism addresses a different type of failure.&lt;/p&gt;

&lt;p&gt;Together, they create a system capable of surviving situations that would completely disable a simpler architecture.&lt;/p&gt;

&lt;p&gt;This layered approach is often referred to as &lt;strong&gt;defence in depth&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Rather than relying on one perfect solution, distributed systems combine multiple protective mechanisms so that if one layer fails, another continues providing protection.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reliability in the Real World
&lt;/h2&gt;

&lt;p&gt;Companies operating internet-scale platforms rarely ask whether failures will occur.&lt;/p&gt;

&lt;p&gt;Instead, they invest significant effort into ensuring that failures remain localised.&lt;/p&gt;

&lt;p&gt;Streaming platforms continue serving videos even when recommendation services experience issues.&lt;/p&gt;

&lt;p&gt;Cloud providers replicate customer data across multiple availability zones so that hardware failures do not result in permanent data loss.&lt;/p&gt;

&lt;p&gt;Large e-commerce companies deploy services across multiple data centres, allowing customer traffic to continue flowing even if an entire region experiences an outage.&lt;/p&gt;

&lt;p&gt;In each case, the objective is not perfection.&lt;/p&gt;

&lt;p&gt;The objective is resilience.&lt;/p&gt;

&lt;p&gt;Reliable systems acknowledge that failures are unavoidable and design architectures capable of recovering from them quickly and automatically.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bringing Everything Together
&lt;/h2&gt;

&lt;p&gt;By now, you may have noticed that the three concepts discussed in this article build upon one another.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Redundancy&lt;/strong&gt; ensures that critical infrastructure never depends on a single component.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Replication&lt;/strong&gt; ensures that valuable data exists in multiple locations instead of one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fault tolerance&lt;/strong&gt; combines these ideas with automatic detection, failover, recovery, and graceful degradation to ensure that the overall system continues functioning despite failures.&lt;/p&gt;

&lt;p&gt;The relationship between these concepts can be visualized as follows.&lt;/p&gt;

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

&lt;p&gt;Although each concept provides value individually, modern distributed systems almost always combine all three.&lt;/p&gt;

&lt;p&gt;Removing any one of them weakens the overall architecture.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;As applications grow from small monoliths into globally distributed platforms, reliability becomes one of the defining characteristics of good system design.&lt;/p&gt;

&lt;p&gt;Users rarely notice a system that works flawlessly.&lt;/p&gt;

&lt;p&gt;They immediately notice one that fails.&lt;/p&gt;

&lt;p&gt;Designing reliable software therefore means assuming that servers will crash, networks will become unreliable, databases will fail, and unexpected situations will occur.&lt;/p&gt;

&lt;p&gt;Instead of treating these events as disasters, modern distributed systems treat them as routine operating conditions.&lt;/p&gt;

&lt;p&gt;Redundancy ensures that critical services always have backups.&lt;/p&gt;

&lt;p&gt;Replication protects the information those services manage.&lt;/p&gt;

&lt;p&gt;Fault tolerance allows the entire application to continue functioning while failures are detected, isolated, and automatically recovered.&lt;/p&gt;

&lt;p&gt;Perhaps the most important lesson from this article is that reliability is not a feature that can be added later.&lt;/p&gt;

&lt;p&gt;It is an architectural principle that influences every design decision from the very beginning.&lt;/p&gt;

&lt;p&gt;The most reliable systems are not the ones that never fail.&lt;/p&gt;

&lt;p&gt;They are the ones that are designed to recover so quickly and gracefully that most users never realise a failure occurred.&lt;/p&gt;

</description>
      <category>systemdesign</category>
      <category>architecture</category>
      <category>beginners</category>
      <category>programming</category>
    </item>
    <item>
      <title>Consistency Models in Distributed Systems: Strong vs Eventual Consistency</title>
      <dc:creator>Sushant Gaurav</dc:creator>
      <pubDate>Tue, 25 Aug 2026 05:41:00 +0000</pubDate>
      <link>https://dev.to/imsushant12/consistency-models-in-distributed-systems-strong-vs-eventual-consistency-476d</link>
      <guid>https://dev.to/imsushant12/consistency-models-in-distributed-systems-strong-vs-eventual-consistency-476d</guid>
      <description>&lt;p&gt;One of the biggest promises of distributed systems is that they allow applications to scale beyond the limits of a single machine. By distributing data across multiple servers, applications become capable of handling millions of users, surviving hardware failures, and serving requests from different parts of the world.&lt;/p&gt;

&lt;p&gt;At first glance, this sounds like the perfect solution.&lt;/p&gt;

&lt;p&gt;If one database server is no longer enough, simply add another.&lt;/p&gt;

&lt;p&gt;If one data centre becomes overloaded, deploy another in a different region.&lt;/p&gt;

&lt;p&gt;If a server fails, allow another replica to take over.&lt;/p&gt;

&lt;p&gt;Everything appears straightforward.&lt;/p&gt;

&lt;p&gt;However, the moment multiple copies of the same data begin existing on different machines, distributed systems encounter one of their most fundamental challenges.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do we ensure that every copy of the data remains correct?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This question sounds deceptively simple.&lt;/p&gt;

&lt;p&gt;In reality, it is one of the hardest problems in computer science.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Single Database Never Faces This Problem
&lt;/h2&gt;

&lt;p&gt;Imagine an application that stores all of its information inside a single database server.&lt;/p&gt;

&lt;p&gt;A customer updates their delivery address.&lt;/p&gt;

&lt;p&gt;The application writes the new address into the database.&lt;/p&gt;

&lt;p&gt;Every future request reads that exact value.&lt;/p&gt;

&lt;p&gt;There is no confusion.&lt;/p&gt;

&lt;p&gt;There is only one copy of the data, so every user sees the same information.&lt;/p&gt;

&lt;p&gt;Life is simple.&lt;/p&gt;

&lt;p&gt;This simplicity is one of the reasons monolithic applications are relatively easy to reason about.&lt;/p&gt;

&lt;p&gt;There is only one source of truth.&lt;/p&gt;

&lt;p&gt;As long as that database is healthy, every request returns identical information.&lt;/p&gt;

&lt;p&gt;Now imagine the application becomes enormously successful.&lt;/p&gt;

&lt;p&gt;Millions of users begin accessing it every day.&lt;/p&gt;

&lt;p&gt;The single database starts struggling under the load.&lt;/p&gt;

&lt;p&gt;To improve availability and scalability, engineers decide to introduce database replication.&lt;/p&gt;

&lt;p&gt;Instead of maintaining one database server, they now maintain several identical copies.&lt;/p&gt;

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

&lt;p&gt;At first glance, nothing appears to have changed.&lt;/p&gt;

&lt;p&gt;The application still stores the same data.&lt;/p&gt;

&lt;p&gt;Users still perform the same operations.&lt;/p&gt;

&lt;p&gt;But internally, the architecture has become dramatically more complicated.&lt;/p&gt;

&lt;p&gt;There is no longer one copy of the data.&lt;/p&gt;

&lt;p&gt;There are several.&lt;/p&gt;

&lt;p&gt;And those copies must somehow remain synchronised.&lt;/p&gt;

&lt;h2&gt;
  
  
  When Copies Disagree
&lt;/h2&gt;

&lt;p&gt;Suppose a customer changes their password.&lt;/p&gt;

&lt;p&gt;The application successfully writes the new password to the primary database.&lt;/p&gt;

&lt;p&gt;Immediately afterwards, the updated information begins replicating to the remaining database replicas.&lt;/p&gt;

&lt;p&gt;But replication is not instantaneous.&lt;/p&gt;

&lt;p&gt;It takes time.&lt;/p&gt;

&lt;p&gt;Perhaps only a few milliseconds.&lt;/p&gt;

&lt;p&gt;Sometimes hundreds of milliseconds.&lt;/p&gt;

&lt;p&gt;Occasionally even longer.&lt;/p&gt;

&lt;p&gt;Now imagine another request arrives before every replica has received the update.&lt;/p&gt;

&lt;p&gt;One server contains the new password.&lt;/p&gt;

&lt;p&gt;Another still contains the old one.&lt;/p&gt;

&lt;p&gt;Which version should the application return?&lt;/p&gt;

&lt;p&gt;Consider another example.&lt;/p&gt;

&lt;p&gt;A customer transfers money between two bank accounts.&lt;/p&gt;

&lt;p&gt;The transaction completes successfully.&lt;/p&gt;

&lt;p&gt;One database replica reflects the new account balance.&lt;/p&gt;

&lt;p&gt;Another replica has not yet received the update.&lt;/p&gt;

&lt;p&gt;If the customer immediately refreshes their banking application, should they see the old balance or the new one?&lt;/p&gt;

&lt;p&gt;Neither answer feels satisfactory.&lt;/p&gt;

&lt;p&gt;Returning outdated information can confuse users.&lt;/p&gt;

&lt;p&gt;Waiting indefinitely until every server agrees can make the system painfully slow.&lt;/p&gt;

&lt;p&gt;This is the central dilemma of consistency in distributed systems.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding Consistency
&lt;/h2&gt;

&lt;p&gt;When engineers talk about &lt;strong&gt;consistency&lt;/strong&gt;, they are not referring to data correctness in the traditional sense.&lt;/p&gt;

&lt;p&gt;Instead, they are asking a very specific question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;If one client writes new data, when should every other client be able to observe that change?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Notice what this definition focuses on.&lt;/p&gt;

&lt;p&gt;It is not asking whether the data is valid.&lt;/p&gt;

&lt;p&gt;It is asking &lt;strong&gt;when different parts of the system should agree on the latest value.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That single word—&lt;em&gt;when&lt;/em&gt;—is incredibly important.&lt;/p&gt;

&lt;p&gt;Some systems require agreement immediately.&lt;/p&gt;

&lt;p&gt;Others can tolerate small delays.&lt;/p&gt;

&lt;p&gt;The acceptable answer depends entirely on the application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Perfect Consistency Is Surprisingly Difficult
&lt;/h2&gt;

&lt;p&gt;At first, the solution seems obvious.&lt;/p&gt;

&lt;p&gt;Whenever data changes, simply update every server before responding to the user.&lt;/p&gt;

&lt;p&gt;Problem solved.&lt;/p&gt;

&lt;p&gt;Unfortunately, distributed systems operate over networks.&lt;/p&gt;

&lt;p&gt;Networks introduce latency.&lt;/p&gt;

&lt;p&gt;Messages can be delayed.&lt;/p&gt;

&lt;p&gt;Servers can temporarily become unavailable.&lt;/p&gt;

&lt;p&gt;Entire data centres can lose connectivity.&lt;/p&gt;

&lt;p&gt;Imagine an application with database replicas in New York, London, Singapore, and Sydney.&lt;/p&gt;

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

&lt;p&gt;Every update must now travel thousands of miles across the internet.&lt;/p&gt;

&lt;p&gt;Even travelling at nearly the speed of light, information still requires time to move between continents.&lt;/p&gt;

&lt;p&gt;Network congestion, routing changes, and temporary failures increase that delay even further.&lt;/p&gt;

&lt;p&gt;Now consider a customer in Singapore updating their profile picture.&lt;/p&gt;

&lt;p&gt;Should a user in London immediately see the new image?&lt;/p&gt;

&lt;p&gt;What if the network cable connecting Europe and Asia is temporarily unavailable?&lt;/p&gt;

&lt;p&gt;Should the application wait?&lt;/p&gt;

&lt;p&gt;Should it reject all requests?&lt;/p&gt;

&lt;p&gt;Or should it temporarily allow users to see slightly outdated information?&lt;/p&gt;

&lt;p&gt;These are not theoretical questions.&lt;/p&gt;

&lt;p&gt;Large internet companies make decisions like these every day.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Relationship Between Replication and Consistency
&lt;/h2&gt;

&lt;p&gt;In our previous article about &lt;strong&gt;Data Partitioning and Sharding&lt;/strong&gt;, we discussed how systems distribute data across multiple machines to improve scalability.&lt;/p&gt;

&lt;p&gt;In another article, we explored &lt;strong&gt;Replication&lt;/strong&gt;, where multiple copies of the same data improve availability and fault tolerance.&lt;/p&gt;

&lt;p&gt;Replication solves one problem while creating another.&lt;/p&gt;

&lt;p&gt;The moment multiple copies of the same information exist, the system must decide how quickly those copies should become identical.&lt;/p&gt;

&lt;p&gt;The faster replicas synchronise, the more consistent the system becomes.&lt;/p&gt;

&lt;p&gt;The longer synchronisation takes, the greater the possibility that different users temporarily observe different versions of the same information.&lt;/p&gt;

&lt;p&gt;Replication and consistency are therefore deeply connected.&lt;/p&gt;

&lt;p&gt;One cannot exist without influencing the other.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Real-World Example Everyone Has Experienced
&lt;/h2&gt;

&lt;p&gt;Most people have experienced eventual consistency without realising it.&lt;/p&gt;

&lt;p&gt;Suppose you change your profile picture on a social media platform.&lt;/p&gt;

&lt;p&gt;Immediately afterwards, you refresh your own profile and see the new image.&lt;/p&gt;

&lt;p&gt;A friend opens your profile from another country a few seconds later.&lt;/p&gt;

&lt;p&gt;Surprisingly, they still see the old picture.&lt;/p&gt;

&lt;p&gt;A short time afterwards, they refresh again.&lt;/p&gt;

&lt;p&gt;Now the new picture appears.&lt;/p&gt;

&lt;p&gt;Was the system broken?&lt;/p&gt;

&lt;p&gt;Not at all.&lt;/p&gt;

&lt;p&gt;The update simply required time to propagate across multiple servers distributed around the world.&lt;/p&gt;

&lt;p&gt;During those few seconds, different users observed different versions of the same data.&lt;/p&gt;

&lt;p&gt;This behaviour is completely normal in many distributed systems.&lt;/p&gt;

&lt;p&gt;The important question is whether that temporary inconsistency is acceptable.&lt;/p&gt;

&lt;p&gt;For a profile picture, probably yes.&lt;/p&gt;

&lt;p&gt;For a bank balance, almost certainly not.&lt;/p&gt;

&lt;p&gt;And that distinction leads us to the two primary consistency models used in distributed systems:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Strong Consistency&lt;/strong&gt; and &lt;strong&gt;Eventual Consistency&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Although both models attempt to solve the same problem, they make very different trade-offs between correctness, availability, latency, and user experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding Strong Consistency
&lt;/h2&gt;

&lt;p&gt;Imagine you withdraw money from an ATM.&lt;/p&gt;

&lt;p&gt;Your account balance is $2,500.&lt;/p&gt;

&lt;p&gt;You withdraw $500.&lt;/p&gt;

&lt;p&gt;The transaction completes successfully.&lt;/p&gt;

&lt;p&gt;A few seconds later, you check your balance using your banking application's mobile app.&lt;/p&gt;

&lt;p&gt;How much money should it display?&lt;/p&gt;

&lt;p&gt;There is really only one acceptable answer.&lt;/p&gt;

&lt;p&gt;It should display &lt;strong&gt;$2,000&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Seeing the old balance—even for a few seconds—would immediately reduce your trust in the banking system.&lt;/p&gt;

&lt;p&gt;You would naturally wonder:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Did the withdrawal actually happen?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is precisely the guarantee that strong consistency provides.&lt;/p&gt;

&lt;p&gt;Once a write operation has been acknowledged as successful, &lt;strong&gt;every subsequent read must return that latest value&lt;/strong&gt;, regardless of which server processes the request.&lt;/p&gt;

&lt;p&gt;There is only one version of the truth.&lt;/p&gt;

&lt;p&gt;Every client sees it immediately.&lt;/p&gt;

&lt;p&gt;From the user's perspective, it feels almost as though there is only a single database, even though the data may actually be replicated across multiple machines.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Strong Consistency Is Achieved
&lt;/h2&gt;

&lt;p&gt;Achieving strong consistency sounds simple in theory.&lt;/p&gt;

&lt;p&gt;Whenever data changes, ensure that every replica receives the update before confirming success to the client.&lt;/p&gt;

&lt;p&gt;However, implementing this guarantee in a distributed environment is considerably more challenging.&lt;/p&gt;

&lt;p&gt;Consider a distributed database with one primary node and three replicas.&lt;/p&gt;

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

&lt;p&gt;Notice the order of events.&lt;/p&gt;

&lt;p&gt;The client does &lt;strong&gt;not&lt;/strong&gt; immediately receive a success response after writing to the primary database.&lt;/p&gt;

&lt;p&gt;Instead, the primary waits until the replicas acknowledge the update.&lt;/p&gt;

&lt;p&gt;Only after sufficient replicas confirm the change does the system inform the client that the operation has completed successfully.&lt;/p&gt;

&lt;p&gt;This waiting period is what allows every future read to return the same value.&lt;/p&gt;

&lt;p&gt;The consistency guarantee comes from coordination.&lt;/p&gt;

&lt;p&gt;And coordination always has a cost.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Strong Consistency Increases Latency
&lt;/h2&gt;

&lt;p&gt;One of the recurring themes throughout this System Design series has been that every architectural decision involves trade-offs.&lt;/p&gt;

&lt;p&gt;Strong consistency is no exception.&lt;/p&gt;

&lt;p&gt;Imagine a database replicated across three continents.&lt;/p&gt;

&lt;p&gt;A customer in India updates their shipping address.&lt;/p&gt;

&lt;p&gt;The primary database accepts the request.&lt;/p&gt;

&lt;p&gt;Before confirming success, however, it must replicate that update to servers located in Europe and North America.&lt;/p&gt;

&lt;p&gt;Although data travels incredibly fast across fibre-optic networks, it is still constrained by the laws of physics.&lt;/p&gt;

&lt;p&gt;Information cannot travel instantaneously.&lt;/p&gt;

&lt;p&gt;Every additional replica introduces communication delays.&lt;/p&gt;

&lt;p&gt;Every acknowledgement requires another network round trip.&lt;/p&gt;

&lt;p&gt;The client remains waiting until the coordination process finishes.&lt;/p&gt;

&lt;p&gt;As a result, the response time increases.&lt;/p&gt;

&lt;p&gt;In other words, stronger consistency often comes at the cost of higher latency.&lt;/p&gt;

&lt;p&gt;This is one of the most important trade-offs in distributed systems.&lt;/p&gt;

&lt;p&gt;Applications demanding immediate agreement frequently sacrifice speed to achieve correctness.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Cost of Waiting
&lt;/h2&gt;

&lt;p&gt;Now imagine that one of the replicas becomes temporarily unreachable.&lt;/p&gt;

&lt;p&gt;Perhaps a network cable has been damaged.&lt;/p&gt;

&lt;p&gt;Perhaps a data centre is experiencing maintenance.&lt;/p&gt;

&lt;p&gt;Perhaps temporary congestion has increased network delays.&lt;/p&gt;

&lt;p&gt;The primary database now faces a difficult decision.&lt;/p&gt;

&lt;p&gt;Should it continue waiting?&lt;/p&gt;

&lt;p&gt;Should it reject the write request?&lt;/p&gt;

&lt;p&gt;Or should it proceed without updating every replica?&lt;/p&gt;

&lt;p&gt;If the system chooses to wait, users experience delays.&lt;/p&gt;

&lt;p&gt;If it chooses to reject requests, availability decreases.&lt;/p&gt;

&lt;p&gt;If it proceeds anyway, consistency is no longer guaranteed.&lt;/p&gt;

&lt;p&gt;Notice how this dilemma resembles the trade-offs we discussed in the article on &lt;strong&gt;CAP Theorem&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Maintaining immediate consistency during failures often requires sacrificing availability.&lt;/p&gt;

&lt;p&gt;This is one reason why strong consistency is relatively expensive to maintain in globally distributed systems.&lt;/p&gt;

&lt;h2&gt;
  
  
  Strong Consistency in the Real World
&lt;/h2&gt;

&lt;p&gt;Despite these challenges, many applications simply cannot tolerate inconsistent data.&lt;/p&gt;

&lt;p&gt;Imagine purchasing the last available ticket for an international flight.&lt;/p&gt;

&lt;p&gt;If two customers simultaneously purchase what appears to be the final seat because different replicas disagree, the airline now has a serious operational problem.&lt;/p&gt;

&lt;p&gt;The same issue appears in hotel reservations.&lt;/p&gt;

&lt;p&gt;Suppose only one room remains available.&lt;/p&gt;

&lt;p&gt;Two booking requests arrive at different replicas before synchronisation completes.&lt;/p&gt;

&lt;p&gt;Without strong consistency, both customers may successfully reserve the same room.&lt;/p&gt;

&lt;p&gt;Financial systems provide another obvious example.&lt;/p&gt;

&lt;p&gt;If your account balance differs depending on which database replica processes your request, users quickly lose confidence in the system.&lt;/p&gt;

&lt;p&gt;Healthcare systems also depend heavily on strong consistency.&lt;/p&gt;

&lt;p&gt;Imagine two doctors viewing different versions of a patient's allergy information because replicas have not yet synchronised.&lt;/p&gt;

&lt;p&gt;The consequences could be severe.&lt;/p&gt;

&lt;p&gt;Inventory management systems face similar challenges.&lt;/p&gt;

&lt;p&gt;When only one product remains in stock, every customer must observe the same inventory count.&lt;/p&gt;

&lt;p&gt;Otherwise, multiple customers may purchase an item that no longer exists.&lt;/p&gt;

&lt;p&gt;In each of these scenarios, correctness is significantly more important than minimising response time.&lt;/p&gt;

&lt;p&gt;Users are generally willing to wait an additional few hundred milliseconds if it guarantees that the information they receive is accurate.&lt;/p&gt;

&lt;h2&gt;
  
  
  Consensus: Getting Multiple Servers to Agree
&lt;/h2&gt;

&lt;p&gt;Strong consistency introduces another fascinating challenge.&lt;/p&gt;

&lt;p&gt;How do multiple independent servers actually agree on the latest value?&lt;/p&gt;

&lt;p&gt;Suppose four replicas receive slightly different information because of temporary network delays.&lt;/p&gt;

&lt;p&gt;Which version becomes the correct one?&lt;/p&gt;

&lt;p&gt;Distributed databases solve this using &lt;strong&gt;consensus algorithms&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Although the underlying algorithms are mathematically sophisticated, the central idea is surprisingly intuitive.&lt;/p&gt;

&lt;p&gt;Before accepting certain operations, multiple servers participate in a coordinated decision-making process.&lt;/p&gt;

&lt;p&gt;Rather than allowing individual replicas to decide independently, the cluster reaches agreement collectively.&lt;/p&gt;

&lt;p&gt;This process ensures that every server eventually shares the same understanding of the system's state.&lt;/p&gt;

&lt;p&gt;Several well-known distributed databases rely on consensus algorithms such as &lt;strong&gt;Raft&lt;/strong&gt; or &lt;strong&gt;Paxos&lt;/strong&gt; to provide strong consistency guarantees.&lt;/p&gt;

&lt;p&gt;While these algorithms are beyond the scope of this article, it is important to recognise that strong consistency is not achieved through replication alone.&lt;/p&gt;

&lt;p&gt;It requires coordination, agreement, and carefully designed protocols capable of handling failures.&lt;/p&gt;

&lt;h2&gt;
  
  
  Strong Consistency Is About Trust
&lt;/h2&gt;

&lt;p&gt;Perhaps the easiest way to understand strong consistency is to think about trust.&lt;/p&gt;

&lt;p&gt;Whenever users interact with a banking application, stock trading platform, payment gateway, airline reservation system, or healthcare database, they expect the system to provide one definitive answer.&lt;/p&gt;

&lt;p&gt;There should never be uncertainty regarding the latest account balance, available seat, completed payment, or medical record.&lt;/p&gt;

&lt;p&gt;Strong consistency provides that confidence.&lt;/p&gt;

&lt;p&gt;Every successful write becomes immediately visible to every subsequent read.&lt;/p&gt;

&lt;p&gt;The system behaves as though there were only a single, perfectly synchronised source of truth.&lt;/p&gt;

&lt;p&gt;Achieving this guarantee is technically demanding.&lt;/p&gt;

&lt;p&gt;It increases latency.&lt;/p&gt;

&lt;p&gt;It requires coordination.&lt;/p&gt;

&lt;p&gt;It becomes more difficult during network failures.&lt;/p&gt;

&lt;p&gt;Yet for many applications, those costs are entirely justified because the business value of correctness far outweighs the additional complexity.&lt;/p&gt;

&lt;p&gt;However, not every application requires this level of precision.&lt;/p&gt;

&lt;p&gt;Many systems prioritise responsiveness, scalability, and availability over immediate agreement.&lt;/p&gt;

&lt;p&gt;Instead of forcing every server to synchronise instantly, they allow updates to propagate gradually throughout the system.&lt;/p&gt;

&lt;p&gt;This alternative approach is known as &lt;strong&gt;Eventual Consistency&lt;/strong&gt;, and it has become one of the defining characteristics of many modern internet-scale applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding Eventual Consistency
&lt;/h2&gt;

&lt;p&gt;Imagine updating your profile picture on a social media platform.&lt;/p&gt;

&lt;p&gt;You upload a new image.&lt;/p&gt;

&lt;p&gt;Within a second, you refresh your own profile and see the updated picture.&lt;/p&gt;

&lt;p&gt;A friend living on another continent opens your profile almost immediately afterwards.&lt;/p&gt;

&lt;p&gt;Surprisingly, they still see the old picture.&lt;/p&gt;

&lt;p&gt;A few moments later, they refresh again.&lt;/p&gt;

&lt;p&gt;Now the new image appears.&lt;/p&gt;

&lt;p&gt;Nothing was broken.&lt;/p&gt;

&lt;p&gt;The system simply required time to distribute the update across its globally distributed infrastructure.&lt;/p&gt;

&lt;p&gt;This is the essence of eventual consistency.&lt;/p&gt;

&lt;p&gt;Unlike strong consistency, eventual consistency does not require every replica to agree immediately.&lt;/p&gt;

&lt;p&gt;Instead, it guarantees something slightly different.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;If no new updates occur, all replicas will eventually converge to the same value.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The word &lt;strong&gt;eventually&lt;/strong&gt; is doing all the work here.&lt;/p&gt;

&lt;p&gt;The system accepts that different users may temporarily observe different versions of the same data.&lt;/p&gt;

&lt;p&gt;However, given enough time, every replica will synchronise and reach the same final state.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Eventual Consistency Exists
&lt;/h2&gt;

&lt;p&gt;At first, allowing inconsistent data sounds like a terrible idea.&lt;/p&gt;

&lt;p&gt;After all, haven't we spent the entire article discussing why consistency matters?&lt;/p&gt;

&lt;p&gt;The answer depends entirely on the type of data involved.&lt;/p&gt;

&lt;p&gt;Consider the homepage of a video streaming platform.&lt;/p&gt;

&lt;p&gt;Suppose a movie's thumbnail changes.&lt;/p&gt;

&lt;p&gt;If some users continue seeing the previous thumbnail for five seconds while others see the updated version immediately, has the application failed?&lt;/p&gt;

&lt;p&gt;Probably not.&lt;/p&gt;

&lt;p&gt;Now imagine an online news website.&lt;/p&gt;

&lt;p&gt;An article receives a new featured image.&lt;/p&gt;

&lt;p&gt;Readers in Europe see the change immediately.&lt;/p&gt;

&lt;p&gt;Readers in Asia see the previous image for another ten seconds.&lt;/p&gt;

&lt;p&gt;Again, the user experience remains almost unaffected.&lt;/p&gt;

&lt;p&gt;The cost of delaying every request until every server agrees would likely outweigh the temporary inconsistency.&lt;/p&gt;

&lt;p&gt;In situations like these, eventual consistency becomes an extremely practical trade-off.&lt;/p&gt;

&lt;p&gt;Rather than waiting for worldwide synchronisation, applications prioritise speed and availability.&lt;/p&gt;

&lt;p&gt;Users receive responses almost instantly, while the system quietly propagates updates in the background.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Eventual Consistency Works
&lt;/h2&gt;

&lt;p&gt;Let's revisit the replicated database architecture from the previous section.&lt;/p&gt;

&lt;p&gt;This time, however, the write process follows a different sequence.&lt;/p&gt;

&lt;p&gt;Instead of waiting for every replica to acknowledge the update, the primary database accepts the write and immediately responds to the client.&lt;/p&gt;

&lt;p&gt;Replication happens afterwards.&lt;/p&gt;

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

&lt;p&gt;Notice the difference from strong consistency.&lt;/p&gt;

&lt;p&gt;The user receives confirmation almost immediately.&lt;/p&gt;

&lt;p&gt;The application does not pause while waiting for every replica to synchronise.&lt;/p&gt;

&lt;p&gt;Instead, replication continues in the background.&lt;/p&gt;

&lt;p&gt;This significantly improves response time.&lt;/p&gt;

&lt;p&gt;However, it also creates a short period during which different replicas may contain different versions of the data.&lt;/p&gt;

&lt;p&gt;That temporary disagreement is an intentional design decision.&lt;/p&gt;

&lt;h2&gt;
  
  
  Living With Temporary Inconsistency
&lt;/h2&gt;

&lt;p&gt;To understand eventual consistency, it helps to stop thinking of inconsistency as an error.&lt;/p&gt;

&lt;p&gt;Instead, think of it as a transition period.&lt;/p&gt;

&lt;p&gt;Suppose an e-commerce company updates the description of a product.&lt;/p&gt;

&lt;p&gt;Some users immediately receive the updated description.&lt;/p&gt;

&lt;p&gt;Others continue seeing the previous version for a short time.&lt;/p&gt;

&lt;p&gt;Eventually, every replica contains the new information.&lt;/p&gt;

&lt;p&gt;The inconsistency existed only while the update was propagating.&lt;/p&gt;

&lt;p&gt;The same idea appears in many cloud services.&lt;/p&gt;

&lt;p&gt;When a DNS record changes, internet providers around the world do not update simultaneously.&lt;/p&gt;

&lt;p&gt;Some DNS servers refresh their records immediately.&lt;/p&gt;

&lt;p&gt;Others continue serving cached information until their cache expires.&lt;/p&gt;

&lt;p&gt;Eventually, every DNS server reflects the new record.&lt;/p&gt;

&lt;p&gt;The internet itself relies heavily on eventual consistency.&lt;/p&gt;

&lt;h2&gt;
  
  
  Eventual Consistency in Everyday Applications
&lt;/h2&gt;

&lt;p&gt;One of the reasons eventual consistency is so widely adopted is that users rarely notice it.&lt;/p&gt;

&lt;p&gt;Consider a messaging application.&lt;/p&gt;

&lt;p&gt;You send a message to a group chat.&lt;/p&gt;

&lt;p&gt;Some participants receive it almost instantly.&lt;/p&gt;

&lt;p&gt;Others experience a slight delay because of network conditions.&lt;/p&gt;

&lt;p&gt;Despite these temporary differences, everyone eventually receives the same message.&lt;/p&gt;

&lt;p&gt;Similarly, when you like a social media post, the like count may not increase simultaneously for every user viewing that page.&lt;/p&gt;

&lt;p&gt;One person may see &lt;strong&gt;1,024 likes&lt;/strong&gt; while another briefly sees &lt;strong&gt;1,023 likes&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A few seconds later, both users observe the same value.&lt;/p&gt;

&lt;p&gt;Streaming platforms exhibit similar behaviour.&lt;/p&gt;

&lt;p&gt;Suppose a creator uploads a new video.&lt;/p&gt;

&lt;p&gt;The video may appear immediately in one region while taking a little longer to become available elsewhere.&lt;/p&gt;

&lt;p&gt;This delay is often caused by content propagation across geographically distributed servers.&lt;/p&gt;

&lt;p&gt;Again, eventual consistency allows the platform to scale globally without forcing every server to synchronise before serving users.&lt;/p&gt;

&lt;p&gt;These examples illustrate an important principle.&lt;/p&gt;

&lt;p&gt;Not every piece of information requires perfect synchronisation.&lt;/p&gt;

&lt;p&gt;For many user experiences, slight delays are practically invisible.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Eventual Consistency Improves Availability
&lt;/h2&gt;

&lt;p&gt;Another significant advantage of eventual consistency appears during failures.&lt;/p&gt;

&lt;p&gt;Imagine that one replica temporarily loses network connectivity.&lt;/p&gt;

&lt;p&gt;In a strongly consistent system, writes may need to pause until coordination is restored.&lt;/p&gt;

&lt;p&gt;An eventually consistent system often behaves differently.&lt;/p&gt;

&lt;p&gt;The primary database continues accepting updates.&lt;/p&gt;

&lt;p&gt;Healthy replicas continue receiving changes.&lt;/p&gt;

&lt;p&gt;The unavailable replica simply catches up later after connectivity returns.&lt;/p&gt;

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

&lt;p&gt;This ability to continue operating despite temporary failures makes eventual consistency particularly attractive for globally distributed applications.&lt;/p&gt;

&lt;p&gt;Rather than sacrificing availability whenever communication becomes difficult, the system tolerates temporary divergence and resolves it later.&lt;/p&gt;

&lt;p&gt;This design aligns closely with the trade-offs discussed in our article on the &lt;strong&gt;CAP Theorem&lt;/strong&gt;, where distributed systems frequently prioritise availability over immediate consistency during network partitions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Eventual Does Not Mean Random
&lt;/h2&gt;

&lt;p&gt;One misconception beginners often have is that eventual consistency means replicas simply update whenever they feel like it.&lt;/p&gt;

&lt;p&gt;That is not how distributed systems work.&lt;/p&gt;

&lt;p&gt;Modern databases use carefully designed replication mechanisms, version tracking, timestamps, conflict resolution strategies, and synchronisation protocols to ensure replicas eventually converge toward the same state.&lt;/p&gt;

&lt;p&gt;The delay may vary depending on network conditions, infrastructure, or workload, but the synchronisation process is deliberate and carefully managed.&lt;/p&gt;

&lt;p&gt;Without these mechanisms, replicas could permanently diverge, creating conflicting versions of the same data.&lt;/p&gt;

&lt;p&gt;Eventual consistency accepts temporary disagreement.&lt;/p&gt;

&lt;p&gt;It does &lt;strong&gt;not&lt;/strong&gt; accept permanent disagreement.&lt;/p&gt;

&lt;p&gt;That distinction is crucial.&lt;/p&gt;

&lt;h2&gt;
  
  
  Eventual Consistency Is About Practicality
&lt;/h2&gt;

&lt;p&gt;Perhaps the easiest way to understand eventual consistency is to think about priorities.&lt;/p&gt;

&lt;p&gt;Instead of asking,&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Can every server agree immediately?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;the system asks,&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Is immediate agreement actually necessary?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For profile pictures, product descriptions, recommendation lists, analytics dashboards, news feeds, and countless other types of information, the answer is often no.&lt;/p&gt;

&lt;p&gt;Users generally prefer receiving information immediately—even if it is a few seconds behind—rather than waiting longer for perfect synchronisation.&lt;/p&gt;

&lt;p&gt;This practical mindset is one of the reasons eventual consistency powers so many of today's largest distributed platforms.&lt;/p&gt;

&lt;p&gt;It acknowledges an important reality of globally distributed systems:&lt;/p&gt;

&lt;p&gt;Sometimes delivering information quickly is more valuable than delivering perfectly synchronised information.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Side-by-Side Comparison
&lt;/h2&gt;

&lt;p&gt;One of the easiest ways to understand these consistency models is to compare how they behave when the same event occurs.&lt;/p&gt;

&lt;p&gt;Imagine a user updates their profile information.&lt;/p&gt;

&lt;h3&gt;
  
  
  Under Strong Consistency
&lt;/h3&gt;

&lt;p&gt;The system waits until the update has been synchronised according to its consistency requirements before acknowledging success.&lt;/p&gt;

&lt;p&gt;Every subsequent request immediately observes the updated information.&lt;/p&gt;

&lt;p&gt;There is never any ambiguity regarding which version is correct.&lt;/p&gt;

&lt;p&gt;Users receive one consistent answer regardless of which server processes the request.&lt;/p&gt;

&lt;h3&gt;
  
  
  Under Eventual Consistency
&lt;/h3&gt;

&lt;p&gt;The system acknowledges the update almost immediately.&lt;/p&gt;

&lt;p&gt;Replication continues in the background.&lt;/p&gt;

&lt;p&gt;For a short period, different users may observe different versions of the data depending on which replica serves their request.&lt;/p&gt;

&lt;p&gt;Eventually, every replica converges to the same state.&lt;/p&gt;

&lt;p&gt;The difference is not whether synchronisation happens.&lt;/p&gt;

&lt;p&gt;The difference is &lt;strong&gt;when&lt;/strong&gt; synchronisation becomes visible to users.&lt;/p&gt;

&lt;h2&gt;
  
  
  Visualising the Difference
&lt;/h2&gt;

&lt;p&gt;The following diagram illustrates the behaviour of both consistency models after a write operation.&lt;/p&gt;

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

&lt;p&gt;Notice that both systems ultimately reach the same final state.&lt;/p&gt;

&lt;p&gt;The distinction lies in whether the client waits for synchronisation or whether synchronisation continues after the response has already been returned.&lt;/p&gt;

&lt;h2&gt;
  
  
  Choosing the Right Model Depends on the Business Problem
&lt;/h2&gt;

&lt;p&gt;A common mistake among beginners is assuming that every application should strive for strong consistency because it sounds safer.&lt;/p&gt;

&lt;p&gt;In reality, insisting on strong consistency everywhere often leads to unnecessary complexity and reduced performance.&lt;/p&gt;

&lt;p&gt;Imagine an online retail platform.&lt;/p&gt;

&lt;p&gt;When a customer updates their shipping address, seeing the previous address for two or three seconds is unlikely to create significant problems.&lt;/p&gt;

&lt;p&gt;However, when that same customer submits a payment, displaying an outdated account balance would be completely unacceptable.&lt;/p&gt;

&lt;p&gt;The application therefore treats different pieces of information differently.&lt;/p&gt;

&lt;p&gt;Profile information may tolerate eventual consistency.&lt;/p&gt;

&lt;p&gt;Financial transactions generally require strong consistency.&lt;/p&gt;

&lt;p&gt;The same application may therefore use multiple consistency models simultaneously.&lt;/p&gt;

&lt;p&gt;This idea surprises many engineers when they first encounter distributed systems.&lt;/p&gt;

&lt;p&gt;Consistency is rarely an application-wide decision.&lt;/p&gt;

&lt;p&gt;It is usually made at the level of individual business operations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Real-World Examples
&lt;/h2&gt;

&lt;p&gt;Large technology companies rarely commit themselves exclusively to one consistency model.&lt;/p&gt;

&lt;p&gt;Instead, they carefully choose the appropriate model for each type of data.&lt;/p&gt;

&lt;p&gt;Consider a typical social media platform.&lt;/p&gt;

&lt;p&gt;When you upload a new profile picture, the update propagates across content delivery networks and replicated databases around the world.&lt;/p&gt;

&lt;p&gt;Some users may briefly continue seeing the previous image.&lt;/p&gt;

&lt;p&gt;This temporary inconsistency has almost no business impact.&lt;/p&gt;

&lt;p&gt;The platform therefore favours eventual consistency because it delivers excellent scalability and responsiveness.&lt;/p&gt;

&lt;p&gt;Now consider the payment system used by that same company.&lt;/p&gt;

&lt;p&gt;Suppose a user purchases a premium subscription.&lt;/p&gt;

&lt;p&gt;The payment must only be processed once.&lt;/p&gt;

&lt;p&gt;The account balance must remain accurate.&lt;/p&gt;

&lt;p&gt;Subscription status must not fluctuate between different servers.&lt;/p&gt;

&lt;p&gt;In this scenario, strong consistency becomes essential.&lt;/p&gt;

&lt;p&gt;The same organisation therefore employs both models—simply for different purposes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Can a Single Application Use Both?
&lt;/h2&gt;

&lt;p&gt;Absolutely.&lt;/p&gt;

&lt;p&gt;In fact, this is exactly how many modern distributed systems are designed.&lt;/p&gt;

&lt;p&gt;Consider an e-commerce platform.&lt;/p&gt;

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

&lt;p&gt;Notice how different business capabilities have different requirements.&lt;/p&gt;

&lt;p&gt;The payment service cannot afford inconsistent account balances.&lt;/p&gt;

&lt;p&gt;The inventory service must accurately determine whether products remain available.&lt;/p&gt;

&lt;p&gt;On the other hand, recommendation systems, analytics dashboards, search indexes, and notification services can safely process information asynchronously.&lt;/p&gt;

&lt;p&gt;Attempting to force every component to use strong consistency would increase latency and reduce scalability without providing meaningful business value.&lt;/p&gt;

&lt;p&gt;Conversely, making payment processing eventually consistent could result in duplicate transactions or oversold inventory.&lt;/p&gt;

&lt;p&gt;Good system design therefore involves identifying which operations genuinely require immediate correctness and which can tolerate temporary inconsistency.&lt;/p&gt;

&lt;h2&gt;
  
  
  Strong Consistency vs Eventual Consistency
&lt;/h2&gt;

&lt;p&gt;The following table summarises the primary differences between the two models.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Characteristic&lt;/th&gt;
&lt;th&gt;Strong Consistency&lt;/th&gt;
&lt;th&gt;Eventual Consistency&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Data visibility&lt;/td&gt;
&lt;td&gt;Latest data is always returned&lt;/td&gt;
&lt;td&gt;Temporary stale reads are possible&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Read behavior&lt;/td&gt;
&lt;td&gt;Every client observes the same value&lt;/td&gt;
&lt;td&gt;Different replicas may briefly return different values&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Latency&lt;/td&gt;
&lt;td&gt;Typically higher because of coordination&lt;/td&gt;
&lt;td&gt;Usually lower because responses are returned immediately&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Availability during failures&lt;/td&gt;
&lt;td&gt;May decrease while replicas coordinate&lt;/td&gt;
&lt;td&gt;Generally higher because updates continue despite temporary failures&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scalability&lt;/td&gt;
&lt;td&gt;More difficult at global scale&lt;/td&gt;
&lt;td&gt;Easier to scale across regions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Typical applications&lt;/td&gt;
&lt;td&gt;Banking, payments, reservations, inventory&lt;/td&gt;
&lt;td&gt;Social media, analytics, recommendations, DNS, caching&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Rather than viewing these differences as advantages or disadvantages, think of them as design trade-offs.&lt;/p&gt;

&lt;p&gt;Every distributed system decides where it wants to position itself along this spectrum.&lt;/p&gt;

&lt;h2&gt;
  
  
  Consistency Is a Business Decision
&lt;/h2&gt;

&lt;p&gt;One of the most important lessons for system designers is that consistency is not merely a technical concern.&lt;/p&gt;

&lt;p&gt;It is ultimately a business decision.&lt;/p&gt;

&lt;p&gt;Technology provides the available options.&lt;/p&gt;

&lt;p&gt;Business requirements determine which option is appropriate.&lt;/p&gt;

&lt;p&gt;A stock trading platform cannot allow customers to observe outdated portfolio values.&lt;/p&gt;

&lt;p&gt;An airline cannot sell the same seat to multiple passengers.&lt;/p&gt;

&lt;p&gt;A hospital cannot display different versions of a patient's medical history.&lt;/p&gt;

&lt;p&gt;These applications willingly accept additional complexity to guarantee correctness.&lt;/p&gt;

&lt;p&gt;Conversely, a social media platform benefits far more from responsiveness and availability than from forcing every profile update to synchronise globally before users can continue browsing.&lt;/p&gt;

&lt;p&gt;The acceptable level of inconsistency depends entirely on the consequences of stale data.&lt;/p&gt;

&lt;p&gt;Understanding those consequences is often more important than understanding the underlying algorithms.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Throughout this System Design series, one idea has consistently appeared across every topic we have explored.&lt;/p&gt;

&lt;p&gt;No architecture is universally optimal.&lt;/p&gt;

&lt;p&gt;Monolithic systems trade flexibility for simplicity.&lt;/p&gt;

&lt;p&gt;Distributed systems trade simplicity for scalability.&lt;/p&gt;

&lt;p&gt;Horizontal scaling trades hardware limitations for operational complexity.&lt;/p&gt;

&lt;p&gt;Microservices trade organisational independence for increased communication overhead.&lt;/p&gt;

&lt;p&gt;Consistency models follow the same pattern.&lt;/p&gt;

&lt;p&gt;Strong consistency prioritises correctness, even if that means accepting additional latency and coordination.&lt;/p&gt;

&lt;p&gt;Eventual consistency prioritises scalability, responsiveness, and availability, while accepting that replicas may temporarily disagree.&lt;/p&gt;

&lt;p&gt;Neither philosophy is inherently better.&lt;/p&gt;

&lt;p&gt;They simply optimise for different priorities.&lt;/p&gt;

&lt;p&gt;As you continue studying distributed systems, you will notice that nearly every architectural decision revolves around balancing competing trade-offs rather than maximising a single metric.&lt;/p&gt;

&lt;p&gt;The best engineers are not those who always choose the most advanced technology.&lt;/p&gt;

&lt;p&gt;They are the ones who understand the strengths and limitations of every approach and select the one that best serves the problem they are trying to solve.&lt;/p&gt;

&lt;p&gt;That, ultimately, is the essence of system design.&lt;/p&gt;

</description>
      <category>systemdesign</category>
      <category>architecture</category>
      <category>programming</category>
      <category>distributedsystems</category>
    </item>
    <item>
      <title>Communication Between Services: REST, gRPC, and Message Queues</title>
      <dc:creator>Sushant Gaurav</dc:creator>
      <pubDate>Tue, 11 Aug 2026 05:41:00 +0000</pubDate>
      <link>https://dev.to/imsushant12/communication-between-services-rest-grpc-and-message-queues-4ik1</link>
      <guid>https://dev.to/imsushant12/communication-between-services-rest-grpc-and-message-queues-4ik1</guid>
      <description>&lt;p&gt;In the previous article, we explored how large applications gradually evolve from monoliths into collections of smaller, independently deployable services. Instead of one massive application responsible for authentication, payments, inventory, notifications, and analytics, we now have multiple services, each responsible for a single business capability.&lt;/p&gt;

&lt;p&gt;At first glance, this seems like a clean and elegant solution. Every service owns its own logic, its own database, and can be deployed independently without affecting the rest of the system.&lt;/p&gt;

&lt;p&gt;But splitting an application into multiple services immediately creates a new challenge.&lt;/p&gt;

&lt;p&gt;The components that once lived inside the same process now live on different machines.&lt;/p&gt;

&lt;p&gt;Inside a monolithic application, communication is almost effortless. If the payment module needs information about a user, it simply calls a function from the user module. The call happens inside the same process, uses the same memory space, and usually completes in a fraction of a millisecond. Developers rarely stop to think about this communication because, from their perspective, it is almost free.&lt;/p&gt;

&lt;p&gt;Microservices change this assumption entirely.&lt;/p&gt;

&lt;p&gt;The payment service no longer has direct access to the user service. They may be running on different servers, in different containers, or even in different regions of the world. Every interaction between them must now travel through a network.&lt;/p&gt;

&lt;p&gt;What was once a simple function call has become a network request.&lt;/p&gt;

&lt;p&gt;This seemingly small architectural change has enormous consequences.&lt;/p&gt;

&lt;p&gt;Network requests introduce latency. They can fail unexpectedly. They may experience congestion, timeouts, packet loss, or temporary service outages. Unlike local function calls, network communication is inherently unreliable.&lt;/p&gt;

&lt;p&gt;This is why experienced engineers often say that moving to microservices means moving into the world of distributed systems.&lt;/p&gt;

&lt;p&gt;The application is no longer just executing code.&lt;/p&gt;

&lt;p&gt;It is coordinating communication between independent systems.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Communication Becomes a System Design Problem
&lt;/h2&gt;

&lt;p&gt;Imagine a customer placing an order on an e-commerce platform.&lt;/p&gt;

&lt;p&gt;From the customer's perspective, the process appears straightforward. They click the &lt;strong&gt;"Place Order"&lt;/strong&gt; button, wait a few seconds, and receive a confirmation message.&lt;/p&gt;

&lt;p&gt;Behind the scenes, however, the request may travel through several independent services before the order is successfully processed.&lt;/p&gt;

&lt;p&gt;The order service must verify the customer.&lt;/p&gt;

&lt;p&gt;The inventory service must confirm that the requested items are available.&lt;/p&gt;

&lt;p&gt;The payment service must process the transaction.&lt;/p&gt;

&lt;p&gt;The notification service must send a confirmation email or SMS.&lt;/p&gt;

&lt;p&gt;Each of these services performs its own responsibility, but together they must behave as if they were a single application.&lt;/p&gt;

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

&lt;p&gt;Notice something interesting about this interaction.&lt;/p&gt;

&lt;p&gt;The Order Service is not solving business problems alone.&lt;/p&gt;

&lt;p&gt;It spends a significant amount of time communicating with other services.&lt;/p&gt;

&lt;p&gt;As systems grow larger, communication itself becomes one of the biggest consumers of time and resources.&lt;/p&gt;

&lt;p&gt;This is one of the reasons distributed systems are fundamentally different from traditional applications.&lt;/p&gt;

&lt;p&gt;The challenge is no longer writing business logic.&lt;/p&gt;

&lt;p&gt;The challenge is coordinating independent systems efficiently and reliably.&lt;/p&gt;

&lt;h2&gt;
  
  
  Not Every Conversation Between Services Is the Same
&lt;/h2&gt;

&lt;p&gt;Suppose the Order Service needs to verify whether a product exists before allowing a purchase.&lt;/p&gt;

&lt;p&gt;The answer is needed immediately.&lt;/p&gt;

&lt;p&gt;The customer is waiting.&lt;/p&gt;

&lt;p&gt;The Order Service cannot continue until it receives a response.&lt;/p&gt;

&lt;p&gt;Now consider a different situation.&lt;/p&gt;

&lt;p&gt;A payment has been completed successfully, and the customer should receive a confirmation email.&lt;/p&gt;

&lt;p&gt;Does the customer really need to wait until the email has been delivered?&lt;/p&gt;

&lt;p&gt;Probably not.&lt;/p&gt;

&lt;p&gt;The order should complete successfully even if the email arrives a few seconds later.&lt;/p&gt;

&lt;p&gt;Now imagine another scenario.&lt;/p&gt;

&lt;p&gt;A recommendation engine wants to learn which products users purchase so that it can improve future recommendations.&lt;/p&gt;

&lt;p&gt;Should the payment process slow down while waiting for the recommendation engine to process analytics?&lt;/p&gt;

&lt;p&gt;Again, the answer is no.&lt;/p&gt;

&lt;p&gt;These examples illustrate an important principle in distributed systems:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Not every interaction between services has the same urgency.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Some requests require an immediate response.&lt;/p&gt;

&lt;p&gt;Others can happen later.&lt;/p&gt;

&lt;p&gt;Some require a direct conversation.&lt;/p&gt;

&lt;p&gt;Others simply need to notify another service that an event has occurred.&lt;/p&gt;

&lt;p&gt;Understanding these differences is the key to choosing the right communication mechanism.&lt;/p&gt;

&lt;h2&gt;
  
  
  Synchronous vs Asynchronous Communication
&lt;/h2&gt;

&lt;p&gt;Before discussing REST, gRPC, or messaging systems, we need to understand two fundamental communication models that appear throughout distributed systems.&lt;/p&gt;

&lt;p&gt;The first is &lt;strong&gt;synchronous communication&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In synchronous communication, one service sends a request and waits for the response before continuing.&lt;/p&gt;

&lt;p&gt;It is very similar to a phone call.&lt;/p&gt;

&lt;p&gt;When you call someone, the conversation happens in real time. You ask a question and wait for the answer before continuing the discussion.&lt;/p&gt;

&lt;p&gt;Most web applications work this way.&lt;/p&gt;

&lt;p&gt;When your browser requests a webpage, it waits until the server responds.&lt;/p&gt;

&lt;p&gt;Likewise, when one microservice calls another using REST or gRPC, it often waits for the response before moving forward.&lt;/p&gt;

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

&lt;p&gt;This approach is simple to understand because it closely resembles traditional programming.&lt;/p&gt;

&lt;p&gt;However, it also creates dependencies.&lt;/p&gt;

&lt;p&gt;If Service B becomes slow, Service A also becomes slow.&lt;/p&gt;

&lt;p&gt;If Service B becomes unavailable, Service A may fail entirely.&lt;/p&gt;

&lt;p&gt;In other words, synchronous communication couples the availability and performance of multiple services.&lt;/p&gt;

&lt;p&gt;Asynchronous communication takes a very different approach.&lt;/p&gt;

&lt;p&gt;Instead of waiting for an immediate response, one service simply publishes a message and continues its own work.&lt;/p&gt;

&lt;p&gt;Receiving services process that message whenever they are ready.&lt;/p&gt;

&lt;p&gt;A useful analogy is email.&lt;/p&gt;

&lt;p&gt;When you send an email, you do not wait with your computer open until the recipient replies.&lt;/p&gt;

&lt;p&gt;You send the message and continue with your day.&lt;/p&gt;

&lt;p&gt;The recipient responds later.&lt;/p&gt;

&lt;p&gt;Distributed systems often behave in exactly the same way.&lt;/p&gt;

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

&lt;p&gt;This model dramatically reduces coupling between services.&lt;/p&gt;

&lt;p&gt;The Order Service no longer needs to know whether the Notification Service is currently running.&lt;/p&gt;

&lt;p&gt;Its responsibility ends once the message has been successfully placed into the queue.&lt;/p&gt;

&lt;p&gt;The notification can be processed seconds—or even minutes—later without affecting the customer experience.&lt;/p&gt;

&lt;p&gt;As systems become larger, this asynchronous style of communication becomes increasingly common because it improves resilience and allows services to operate independently.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three Ways Services Usually Communicate
&lt;/h2&gt;

&lt;p&gt;Almost every distributed system relies on one of three primary communication mechanisms.&lt;/p&gt;

&lt;p&gt;The first is &lt;strong&gt;REST&lt;/strong&gt;, which has become the standard way of building web APIs over the last two decades. It is simple, human-readable, and supported by virtually every programming language and framework.&lt;/p&gt;

&lt;p&gt;The second is &lt;strong&gt;gRPC&lt;/strong&gt;, a high-performance communication framework designed for fast and efficient communication between services. Instead of exchanging human-readable JSON, gRPC uses a compact binary protocol, making it significantly faster in many internal service-to-service scenarios.&lt;/p&gt;

&lt;p&gt;The third approach uses &lt;strong&gt;message queues&lt;/strong&gt;, where services communicate indirectly by publishing events instead of sending direct requests. Rather than waiting for immediate responses, services exchange information through brokers such as queues or event streams, enabling asynchronous communication and improving system resilience.&lt;/p&gt;

&lt;p&gt;Although all three approaches allow services to communicate, they solve different problems.&lt;/p&gt;

&lt;p&gt;Choosing between them is rarely about which technology is better.&lt;/p&gt;

&lt;p&gt;It is about understanding the nature of the conversation taking place between services.&lt;/p&gt;

&lt;p&gt;Should the sender wait for a response?&lt;/p&gt;

&lt;p&gt;Does the receiver need to respond immediately?&lt;/p&gt;

&lt;p&gt;Can the work happen later?&lt;/p&gt;

&lt;p&gt;Should failures affect the user?&lt;/p&gt;

&lt;p&gt;The answers to these questions determine the most appropriate communication model.&lt;/p&gt;

&lt;p&gt;And this is where our discussion truly begins.&lt;/p&gt;

&lt;h2&gt;
  
  
  REST: The Language of the Web
&lt;/h2&gt;

&lt;p&gt;Long before microservices became popular, applications already needed a way to communicate over networks.&lt;/p&gt;

&lt;p&gt;Web browsers needed to request web pages.&lt;/p&gt;

&lt;p&gt;Mobile applications needed to fetch user profiles.&lt;/p&gt;

&lt;p&gt;Third-party developers needed access to payment systems, maps, weather data, and social media platforms.&lt;/p&gt;

&lt;p&gt;The internet itself needed a common language that every application, regardless of the programming language it was written in, could understand.&lt;/p&gt;

&lt;p&gt;This is where REST entered the picture.&lt;/p&gt;

&lt;p&gt;REST, which stands for &lt;strong&gt;Representational State Transfer&lt;/strong&gt;, is not a protocol or a programming language. It is an architectural style proposed by Roy Fielding in his doctoral dissertation in the year 2000. Rather than introducing a completely new communication protocol, REST embraced technologies that were already powering the web—primarily HTTP.&lt;/p&gt;

&lt;p&gt;This decision played a significant role in REST's widespread adoption.&lt;/p&gt;

&lt;p&gt;Instead of asking developers to learn an entirely new ecosystem, REST leveraged concepts they were already familiar with. URLs identified resources, HTTP methods described operations, and responses were returned using formats such as JSON or XML.&lt;/p&gt;

&lt;p&gt;Over time, REST became the de facto standard for building APIs, and today, it powers a significant portion of the modern internet.&lt;/p&gt;

&lt;p&gt;Whether you're checking your bank balance, booking a flight, ordering food, or scrolling through social media, there's a good chance your device is communicating with backend services through REST APIs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Thinking in Resources Instead of Functions
&lt;/h2&gt;

&lt;p&gt;One of the biggest mindset shifts when learning REST is understanding that it is &lt;strong&gt;resource-oriented&lt;/strong&gt;, not &lt;strong&gt;function-oriented&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In traditional programming, we tend to think in terms of actions.&lt;/p&gt;

&lt;p&gt;We write functions like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;createUser()
getUser()
deleteUser()
updateUser()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;REST encourages us to think differently.&lt;/p&gt;

&lt;p&gt;Instead of focusing on actions, we focus on &lt;strong&gt;resources&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A user is a resource.&lt;/p&gt;

&lt;p&gt;An order is a resource.&lt;/p&gt;

&lt;p&gt;A product is a resource.&lt;/p&gt;

&lt;p&gt;A payment is a resource.&lt;/p&gt;

&lt;p&gt;Once a resource exists, HTTP methods describe what we want to do with it.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET    /users/125
POST   /users
PUT    /users/125
DELETE /users/125
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice how the URL represents &lt;strong&gt;what&lt;/strong&gt; we are working with, while the HTTP method represents &lt;strong&gt;what operation&lt;/strong&gt; we want to perform.&lt;/p&gt;

&lt;p&gt;This separation makes APIs easier to understand because they resemble the structure of the real-world entities they represent.&lt;/p&gt;

&lt;h2&gt;
  
  
  How a REST Request Travels Through the System
&lt;/h2&gt;

&lt;p&gt;Let's consider a simple example.&lt;/p&gt;

&lt;p&gt;A customer opens an e-commerce application and wants to view the details of a product.&lt;/p&gt;

&lt;p&gt;The frontend application sends an HTTP request to the Product Service.&lt;/p&gt;

&lt;p&gt;The Product Service processes the request, retrieves the necessary information from its database, converts the result into JSON, and sends it back to the client.&lt;/p&gt;

&lt;p&gt;The interaction looks something like this:&lt;/p&gt;

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

&lt;p&gt;From the user's perspective, this entire interaction feels almost instantaneous.&lt;/p&gt;

&lt;p&gt;Behind the scenes, however, several things have happened.&lt;/p&gt;

&lt;p&gt;The request travelled through the internet.&lt;/p&gt;

&lt;p&gt;The server authenticated the client.&lt;/p&gt;

&lt;p&gt;Business logic was executed.&lt;/p&gt;

&lt;p&gt;A database query was performed.&lt;/p&gt;

&lt;p&gt;The response was serialised into JSON.&lt;/p&gt;

&lt;p&gt;Finally, the data was transmitted back over the network.&lt;/p&gt;

&lt;p&gt;Every REST request follows this general request-response lifecycle.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why REST Became So Popular
&lt;/h2&gt;

&lt;p&gt;One of REST's greatest strengths is its simplicity.&lt;/p&gt;

&lt;p&gt;Almost every programming language today can send an HTTP request.&lt;/p&gt;

&lt;p&gt;Browsers understand HTTP natively.&lt;/p&gt;

&lt;p&gt;Firewalls are designed to work with HTTP traffic.&lt;/p&gt;

&lt;p&gt;Cloud platforms, API gateways, reverse proxies, load balancers, and CDNs all understand HTTP exceptionally well.&lt;/p&gt;

&lt;p&gt;Because of this universal support, REST APIs can be consumed by virtually anything.&lt;/p&gt;

&lt;p&gt;A web browser.&lt;/p&gt;

&lt;p&gt;A mobile application.&lt;/p&gt;

&lt;p&gt;A desktop application.&lt;/p&gt;

&lt;p&gt;Another backend service.&lt;/p&gt;

&lt;p&gt;Even command-line tools like &lt;code&gt;curl&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This universality is one of the reasons REST became the default communication mechanism for modern applications.&lt;/p&gt;

&lt;p&gt;It reduced friction.&lt;/p&gt;

&lt;p&gt;Developers no longer needed specialised libraries or proprietary communication protocols.&lt;/p&gt;

&lt;p&gt;If two systems could speak HTTP, they could usually communicate with one another.&lt;/p&gt;

&lt;h2&gt;
  
  
  REST Is Stateless - And That Is a Good Thing
&lt;/h2&gt;

&lt;p&gt;One of the defining characteristics of REST is that it is &lt;strong&gt;stateless&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;At first, the word sounds technical, but the idea is remarkably simple.&lt;/p&gt;

&lt;p&gt;Every request should contain all the information required to process it.&lt;/p&gt;

&lt;p&gt;The server should not rely on memory from previous requests.&lt;/p&gt;

&lt;p&gt;Imagine asking someone for directions.&lt;/p&gt;

&lt;p&gt;If every time you ask, you provide your current location and destination, they can answer immediately.&lt;/p&gt;

&lt;p&gt;They don't need to remember your previous conversations.&lt;/p&gt;

&lt;p&gt;REST works in the same way.&lt;/p&gt;

&lt;p&gt;Suppose a client sends the following request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;GET /orders/1254
Authorization: Bearer &amp;lt;token&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The request already contains everything the server needs.&lt;/p&gt;

&lt;p&gt;It specifies:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which resource is being requested.&lt;/li&gt;
&lt;li&gt;Who is making the request.&lt;/li&gt;
&lt;li&gt;Authentication credentials.&lt;/li&gt;
&lt;li&gt;Any additional headers or parameters.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The server processes the request, sends the response, and then forgets everything about that interaction.&lt;/p&gt;

&lt;p&gt;The next request starts from scratch.&lt;/p&gt;

&lt;p&gt;This stateless design provides significant scalability benefits.&lt;/p&gt;

&lt;p&gt;Since servers do not need to remember client sessions, incoming requests can be distributed across multiple application instances using a load balancer.&lt;/p&gt;

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

&lt;p&gt;Any server can process any request because every request is self-contained.&lt;/p&gt;

&lt;p&gt;This aligns perfectly with the horizontal scaling principles we discussed earlier in this series.&lt;/p&gt;

&lt;h2&gt;
  
  
  JSON: The Universal Language of REST
&lt;/h2&gt;

&lt;p&gt;Although REST itself does not require JSON, the two have become almost inseparable.&lt;/p&gt;

&lt;p&gt;JSON is lightweight, human-readable, and supported by virtually every modern programming language.&lt;/p&gt;

&lt;p&gt;A typical REST response might look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;105&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Mechanical Keyboard"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"price"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;89.99&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"stock"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One reason developers appreciate JSON is that it is easy to inspect.&lt;/p&gt;

&lt;p&gt;If something goes wrong, developers can open browser developer tools, examine the response, and immediately understand what the server returned.&lt;/p&gt;

&lt;p&gt;This readability makes debugging significantly easier than many binary communication formats.&lt;/p&gt;

&lt;p&gt;However, this convenience comes with a trade-off.&lt;/p&gt;

&lt;p&gt;Text-based data is generally larger than binary data.&lt;/p&gt;

&lt;p&gt;A JSON document contains field names, punctuation, quotation marks, and whitespace, all of which increase the size of the response.&lt;/p&gt;

&lt;p&gt;For applications serving millions of requests every minute, these additional bytes become significant.&lt;/p&gt;

&lt;p&gt;This limitation eventually motivated the development of faster communication mechanisms such as gRPC, which we'll explore in the next part.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where REST Truly Shines
&lt;/h2&gt;

&lt;p&gt;REST is exceptionally well suited for communication between clients and servers.&lt;/p&gt;

&lt;p&gt;When a web browser requests product information, when a mobile application fetches a user's profile, or when an external partner integrates with your platform, REST is often an excellent choice.&lt;/p&gt;

&lt;p&gt;Its simplicity, interoperability, and widespread tooling make it ideal for public-facing APIs.&lt;/p&gt;

&lt;p&gt;It is also highly cache-friendly.&lt;/p&gt;

&lt;p&gt;Since REST is built on HTTP, it naturally benefits from HTTP caching, proxy servers, reverse proxies, and Content Delivery Networks (CDNs). Responses that do not change frequently can often be cached closer to users, reducing latency and improving performance.&lt;/p&gt;

&lt;p&gt;This is one of the reasons many public APIs continue to rely on REST despite the emergence of newer communication technologies.&lt;/p&gt;

&lt;p&gt;Its ecosystem is mature, battle-tested, and universally understood.&lt;/p&gt;

&lt;h2&gt;
  
  
  REST Is Not Perfect
&lt;/h2&gt;

&lt;p&gt;Despite its popularity, REST is not the answer to every communication problem.&lt;/p&gt;

&lt;p&gt;Because REST relies on HTTP and typically exchanges JSON, each request carries a certain amount of overhead.&lt;/p&gt;

&lt;p&gt;Headers must be transmitted.&lt;/p&gt;

&lt;p&gt;JSON must be serialised by the sender.&lt;/p&gt;

&lt;p&gt;JSON must be parsed by the receiver.&lt;/p&gt;

&lt;p&gt;Every interaction involves opening, processing, and completing an HTTP request-response cycle.&lt;/p&gt;

&lt;p&gt;For occasional communication, this overhead is almost negligible.&lt;/p&gt;

&lt;p&gt;But imagine hundreds of microservices communicating thousands of times every second.&lt;/p&gt;

&lt;p&gt;The cumulative cost becomes noticeable.&lt;/p&gt;

&lt;p&gt;Applications requiring extremely low latency or high throughput often begin looking for more efficient alternatives.&lt;/p&gt;

&lt;p&gt;Another limitation is that REST is fundamentally request-driven.&lt;/p&gt;

&lt;p&gt;One service asks another for information and waits until the response arrives.&lt;/p&gt;

&lt;p&gt;As we discussed in the previous part, this synchronous style of communication creates dependencies between services.&lt;/p&gt;

&lt;p&gt;If one service becomes slow, the calling service also slows down.&lt;/p&gt;

&lt;p&gt;If one service becomes unavailable, requests may begin failing throughout the system.&lt;/p&gt;

&lt;p&gt;These limitations do not make REST a poor choice.&lt;/p&gt;

&lt;p&gt;They simply highlight that every communication model involves trade-offs.&lt;/p&gt;

&lt;p&gt;And understanding those trade-offs is precisely what system design is about.&lt;/p&gt;

&lt;h2&gt;
  
  
  gRPC: Built for High-Performance Service-to-Service Communication
&lt;/h2&gt;

&lt;p&gt;REST revolutionised the way applications communicate over the web, and even today it remains one of the most widely adopted architectural styles for building APIs. It is simple, readable, and supported by virtually every programming language and framework.&lt;/p&gt;

&lt;p&gt;However, as organisations embraced microservices, engineers began noticing a different kind of challenge.&lt;/p&gt;

&lt;p&gt;The majority of service-to-service communication was no longer happening between browsers and backend servers.&lt;/p&gt;

&lt;p&gt;Instead, it was happening between backend services themselves.&lt;/p&gt;

&lt;p&gt;A single user request could trigger communication between dozens of internal services.&lt;/p&gt;

&lt;p&gt;An Order Service might call the Inventory Service, which in turn communicates with the Pricing Service, the Recommendation Service, the Shipping Service, and the Notification Service before the original request is completed.&lt;/p&gt;

&lt;p&gt;Each REST call may take only a few milliseconds, but when hundreds of these calls occur during the processing of a single request—and millions more occur every day—the overhead begins to accumulate.&lt;/p&gt;

&lt;p&gt;The issue wasn't that REST was slow.&lt;/p&gt;

&lt;p&gt;The issue was that REST was designed primarily for interoperability and simplicity rather than maximum performance.&lt;/p&gt;

&lt;p&gt;This is where &lt;strong&gt;gRPC&lt;/strong&gt; enters the picture.&lt;/p&gt;

&lt;p&gt;Developed by Google, gRPC is a high-performance Remote Procedure Call (RPC) framework specifically designed for efficient communication between services.&lt;/p&gt;

&lt;p&gt;Unlike REST, which encourages thinking in terms of resources and HTTP operations, gRPC focuses on calling methods on remote services almost as if they were local functions.&lt;/p&gt;

&lt;p&gt;This makes service-to-service communication feel much closer to traditional programming while retaining the advantages of distributed systems.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding Remote Procedure Calls
&lt;/h2&gt;

&lt;p&gt;Before understanding gRPC, it helps to understand what a &lt;strong&gt;Remote Procedure Call (RPC)&lt;/strong&gt; actually means.&lt;/p&gt;

&lt;p&gt;Imagine writing the following function in your application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;calculateShipping(orderId)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inside a monolithic application, calling this function is straightforward.&lt;/p&gt;

&lt;p&gt;The code executes within the same process, accesses local memory, and immediately returns a result.&lt;/p&gt;

&lt;p&gt;Now imagine that the shipping logic has been extracted into its own microservice.&lt;/p&gt;

&lt;p&gt;The function still appears to exist, but in reality it now executes on an entirely different machine.&lt;/p&gt;

&lt;p&gt;Instead of calling local code, the application must:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Serialise the request.&lt;/li&gt;
&lt;li&gt;Send it across the network.&lt;/li&gt;
&lt;li&gt;Wait for the remote server to execute the operation.&lt;/li&gt;
&lt;li&gt;Receive the response.&lt;/li&gt;
&lt;li&gt;Deserialise the result.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;From the developer's perspective, however, the interaction still resembles a normal function call.&lt;/p&gt;

&lt;p&gt;This is the philosophy behind RPC systems.&lt;/p&gt;

&lt;p&gt;Rather than thinking in terms of URLs and HTTP resources, developers think in terms of methods and services.&lt;/p&gt;

&lt;h2&gt;
  
  
  How gRPC Communicates
&lt;/h2&gt;

&lt;p&gt;One of the biggest differences between REST and gRPC lies in how data is transmitted.&lt;/p&gt;

&lt;p&gt;REST typically exchanges data using JSON.&lt;/p&gt;

&lt;p&gt;JSON is human-readable, easy to debug, and universally supported.&lt;/p&gt;

&lt;p&gt;However, it is also relatively verbose.&lt;/p&gt;

&lt;p&gt;Consider a simple JSON response:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"productId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;101&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Mechanical Keyboard"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"price"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;89.99&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every field name is transmitted over the network.&lt;/p&gt;

&lt;p&gt;Quotation marks, commas, braces, and whitespace all contribute to the size of the payload.&lt;/p&gt;

&lt;p&gt;For applications serving millions of requests every second, these extra bytes matter.&lt;/p&gt;

&lt;p&gt;gRPC takes a different approach.&lt;/p&gt;

&lt;p&gt;Instead of JSON, it uses &lt;strong&gt;Protocol Buffers (Protobuf)&lt;/strong&gt;, a compact binary serialisation format.&lt;/p&gt;

&lt;p&gt;Rather than transmitting descriptive text, Protobuf represents data in a highly efficient binary format.&lt;/p&gt;

&lt;p&gt;The resulting payloads are significantly smaller.&lt;/p&gt;

&lt;p&gt;Smaller payloads require less bandwidth.&lt;/p&gt;

&lt;p&gt;Less bandwidth means faster transmission.&lt;/p&gt;

&lt;p&gt;Faster transmission contributes to lower latency and higher throughput.&lt;/p&gt;

&lt;p&gt;Although these improvements may appear minor for a single request, they become substantial when multiplied across billions of service calls every day.&lt;/p&gt;

&lt;h2&gt;
  
  
  Defining APIs Before Writing Code
&lt;/h2&gt;

&lt;p&gt;One particularly elegant aspect of gRPC is that communication contracts are defined before implementation begins.&lt;/p&gt;

&lt;p&gt;Instead of writing API endpoints directly, developers first create a &lt;strong&gt;Protocol Buffer definition file&lt;/strong&gt;, commonly called a &lt;strong&gt;.proto file&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This file describes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The services available.&lt;/li&gt;
&lt;li&gt;The methods each service exposes.&lt;/li&gt;
&lt;li&gt;The structure of every request.&lt;/li&gt;
&lt;li&gt;The structure of every response.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Conceptually, it looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;service PaymentService {
    rpc ProcessPayment(PaymentRequest)
        returns (PaymentResponse);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From this single definition, tools automatically generate client libraries and server code in multiple programming languages.&lt;/p&gt;

&lt;p&gt;This process eliminates much of the repetitive work developers traditionally perform when building APIs.&lt;/p&gt;

&lt;p&gt;More importantly, both the client and the server now share the same contract.&lt;/p&gt;

&lt;p&gt;This significantly reduces integration errors because both sides are generated from the same specification.&lt;/p&gt;

&lt;h2&gt;
  
  
  HTTP/2 Makes a Difference
&lt;/h2&gt;

&lt;p&gt;Another reason gRPC performs exceptionally well is that it is built on top of &lt;strong&gt;HTTP/2&lt;/strong&gt; rather than traditional HTTP/1.1.&lt;/p&gt;

&lt;p&gt;Without diving too deeply into networking internals, HTTP/2 introduces several improvements that make communication more efficient.&lt;/p&gt;

&lt;p&gt;Instead of opening multiple independent connections, HTTP/2 allows many requests and responses to travel simultaneously over a single connection.&lt;/p&gt;

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

&lt;p&gt;This reduces connection overhead and allows multiple conversations to happen concurrently.&lt;/p&gt;

&lt;p&gt;HTTP/2 also compresses headers and improves how data is transmitted across the network.&lt;/p&gt;

&lt;p&gt;The result is faster communication with lower latency, especially in environments where services exchange thousands of requests every second.&lt;/p&gt;

&lt;p&gt;For large distributed systems, these efficiencies accumulate into significant performance improvements.&lt;/p&gt;

&lt;h2&gt;
  
  
  Streaming: A Capability REST Doesn't Naturally Provide
&lt;/h2&gt;

&lt;p&gt;Perhaps one of gRPC's most impressive features is its support for &lt;strong&gt;streaming&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Traditional REST communication generally follows a simple pattern:&lt;/p&gt;

&lt;p&gt;One request.&lt;/p&gt;

&lt;p&gt;One response.&lt;/p&gt;

&lt;p&gt;The conversation ends.&lt;/p&gt;

&lt;p&gt;Sometimes, however, applications need continuous communication rather than isolated requests.&lt;/p&gt;

&lt;p&gt;Imagine a live stock market dashboard.&lt;/p&gt;

&lt;p&gt;A multiplayer online game.&lt;/p&gt;

&lt;p&gt;A GPS navigation system.&lt;/p&gt;

&lt;p&gt;A live sports score application.&lt;/p&gt;

&lt;p&gt;A monitoring dashboard displaying server metrics in real time.&lt;/p&gt;

&lt;p&gt;In these scenarios, repeatedly sending HTTP requests every second becomes inefficient.&lt;/p&gt;

&lt;p&gt;gRPC supports multiple communication models.&lt;/p&gt;

&lt;p&gt;A client can send one request and receive a continuous stream of responses.&lt;/p&gt;

&lt;p&gt;A server can continuously receive streamed requests.&lt;/p&gt;

&lt;p&gt;Or both sides can exchange messages simultaneously.&lt;/p&gt;

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

&lt;p&gt;This capability makes gRPC particularly attractive for applications involving live updates and continuous data exchange.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where gRPC Excels
&lt;/h2&gt;

&lt;p&gt;gRPC is particularly well suited for communication &lt;strong&gt;inside&lt;/strong&gt; distributed systems.&lt;/p&gt;

&lt;p&gt;When hundreds of microservices continuously exchange information, performance becomes increasingly important.&lt;/p&gt;

&lt;p&gt;The smaller payload sizes, efficient serialisation, persistent HTTP/2 connections, and automatic code generation all contribute to a communication model optimised for speed.&lt;/p&gt;

&lt;p&gt;This is why many organisations use gRPC internally while continuing to expose REST APIs to external clients.&lt;/p&gt;

&lt;p&gt;External developers appreciate REST because it is simple, human-readable, and easy to integrate.&lt;/p&gt;

&lt;p&gt;Internal services benefit from gRPC because efficiency matters more than human readability.&lt;/p&gt;

&lt;p&gt;Many modern architectures therefore combine both approaches.&lt;/p&gt;

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

&lt;p&gt;This hybrid architecture allows systems to take advantage of the strengths of each communication model.&lt;/p&gt;

&lt;h2&gt;
  
  
  gRPC Is Not Always the Right Choice
&lt;/h2&gt;

&lt;p&gt;Despite its impressive capabilities, gRPC is not intended to replace REST entirely.&lt;/p&gt;

&lt;p&gt;Because it uses binary Protocol Buffers, developers cannot simply open a browser and inspect responses as easily as they can with JSON.&lt;/p&gt;

&lt;p&gt;Debugging often requires specialised tooling.&lt;/p&gt;

&lt;p&gt;Public APIs also tend to favour REST because nearly every programming language, browser, and third-party integration platform already understands HTTP and JSON.&lt;/p&gt;

&lt;p&gt;REST therefore remains an excellent choice for communication between external clients and backend systems.&lt;/p&gt;

&lt;p&gt;gRPC shines when communication happens primarily between trusted internal services where performance, efficiency, and strong API contracts become more important than human readability.&lt;/p&gt;

&lt;p&gt;As with every architectural decision we have discussed throughout this series, neither approach is universally better.&lt;/p&gt;

&lt;p&gt;REST optimises for simplicity and interoperability.&lt;/p&gt;

&lt;p&gt;gRPC optimises for efficiency and performance.&lt;/p&gt;

&lt;p&gt;Understanding the requirements of the system is what determines the better choice.&lt;/p&gt;

&lt;p&gt;Up to this point, every communication model we have discussed has shared one common characteristic.&lt;/p&gt;

&lt;p&gt;Whether we were using REST or gRPC, one service directly contacted another service and waited for it to perform some work.&lt;/p&gt;

&lt;p&gt;The communication was immediate.&lt;/p&gt;

&lt;p&gt;The sender knew exactly who the receiver was.&lt;/p&gt;

&lt;p&gt;The receiver processed the request and returned a response.&lt;/p&gt;

&lt;p&gt;While this model works exceptionally well for many scenarios, it also creates an important dependency.&lt;/p&gt;

&lt;p&gt;If the receiving service is unavailable, the sender cannot continue.&lt;/p&gt;

&lt;p&gt;If the receiving service becomes slow, the sender also becomes slow.&lt;/p&gt;

&lt;p&gt;In other words, the health of one service directly affects another.&lt;/p&gt;

&lt;p&gt;As distributed systems become larger, these dependencies begin to accumulate.&lt;/p&gt;

&lt;p&gt;Imagine a modern e-commerce platform during a festival sale.&lt;/p&gt;

&lt;p&gt;A customer clicks the &lt;strong&gt;"Place Order"&lt;/strong&gt; button.&lt;/p&gt;

&lt;p&gt;At first glance, the operation seems simple.&lt;/p&gt;

&lt;p&gt;The order is created, payment is processed, inventory is updated, a confirmation email is sent, loyalty points are added, analytics are recorded, invoices are generated, warehouse systems are notified, and recommendation engines learn from the purchase.&lt;/p&gt;

&lt;p&gt;Although these activities are all triggered by the same user action, they do not all have the same urgency.&lt;/p&gt;

&lt;p&gt;The customer certainly expects payment to be processed immediately.&lt;/p&gt;

&lt;p&gt;However, the customer does not care whether analytics are updated within five milliseconds or five seconds.&lt;/p&gt;

&lt;p&gt;Similarly, recommendation engines can learn about the purchase later without affecting the shopping experience.&lt;/p&gt;

&lt;p&gt;This observation leads to one of the most important ideas in distributed systems:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Not every task needs to happen immediately.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Once engineers recognise this, a completely different communication model becomes possible.&lt;/p&gt;

&lt;p&gt;Instead of directly asking another service to perform work, a service can simply announce that something has happened.&lt;/p&gt;

&lt;p&gt;Any interested service can process that information whenever it is ready.&lt;/p&gt;

&lt;p&gt;This is the philosophy behind &lt;strong&gt;message queues&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Thinking in Events Instead of Requests
&lt;/h2&gt;

&lt;p&gt;Traditional APIs are request-driven.&lt;/p&gt;

&lt;p&gt;One service asks another service to act.&lt;/p&gt;

&lt;p&gt;Message queues are event-driven.&lt;/p&gt;

&lt;p&gt;Instead of saying,&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Please send an email."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;a service simply announces,&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"An order has been created."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The service publishing the event does not know who will consume it.&lt;/p&gt;

&lt;p&gt;It does not need to know.&lt;/p&gt;

&lt;p&gt;Its responsibility ends after successfully publishing the message.&lt;/p&gt;

&lt;p&gt;Other services independently decide whether that event is relevant to them.&lt;/p&gt;

&lt;p&gt;This subtle difference fundamentally changes the architecture.&lt;/p&gt;

&lt;p&gt;Instead of tightly coupling services together, communication becomes loosely coupled.&lt;/p&gt;

&lt;p&gt;Imagine dropping a letter into a mailbox.&lt;/p&gt;

&lt;p&gt;Your responsibility ends once the letter has been posted.&lt;/p&gt;

&lt;p&gt;You do not stand beside the mailbox waiting for the postal worker.&lt;/p&gt;

&lt;p&gt;You trust that the postal system will eventually deliver the message.&lt;/p&gt;

&lt;p&gt;Message queues operate in much the same way.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introducing the Message Broker
&lt;/h2&gt;

&lt;p&gt;A message queue introduces an intermediary known as a &lt;strong&gt;message broker&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Rather than communicating directly with one another, services communicate through this broker.&lt;/p&gt;

&lt;p&gt;The architecture now looks something like this:&lt;/p&gt;

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

&lt;p&gt;Notice what has changed.&lt;/p&gt;

&lt;p&gt;The Order Service no longer needs to know anything about the Notification Service.&lt;/p&gt;

&lt;p&gt;It does not know whether the Notification Service is running.&lt;/p&gt;

&lt;p&gt;It does not know whether analytics are temporarily unavailable.&lt;/p&gt;

&lt;p&gt;It simply publishes an event.&lt;/p&gt;

&lt;p&gt;The broker takes responsibility for delivering that message to interested consumers.&lt;/p&gt;

&lt;p&gt;This greatly reduces dependencies between services.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Real-World Example
&lt;/h2&gt;

&lt;p&gt;Let's revisit our e-commerce platform.&lt;/p&gt;

&lt;p&gt;A customer successfully places an order.&lt;/p&gt;

&lt;p&gt;Inside the Order Service, the business transaction completes successfully.&lt;/p&gt;

&lt;p&gt;Immediately afterwards, an event named &lt;strong&gt;OrderCreated&lt;/strong&gt; is published to the message broker.&lt;/p&gt;

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

&lt;p&gt;Notice something remarkable.&lt;/p&gt;

&lt;p&gt;The Order Service only performs one communication.&lt;/p&gt;

&lt;p&gt;The broker handles everything else.&lt;/p&gt;

&lt;p&gt;As additional services are introduced in the future—perhaps fraud detection, inventory forecasting, recommendation systems, or customer rewards—the Order Service remains unchanged.&lt;/p&gt;

&lt;p&gt;The architecture naturally supports growth.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Message Queues Improve Reliability
&lt;/h2&gt;

&lt;p&gt;Suppose the Notification Service suddenly crashes.&lt;/p&gt;

&lt;p&gt;What happens?&lt;/p&gt;

&lt;p&gt;In a synchronous REST-based system, the Order Service attempts to contact the Notification Service and receives an error.&lt;/p&gt;

&lt;p&gt;Depending on how the application is designed, this failure may delay or even fail the entire user request.&lt;/p&gt;

&lt;p&gt;With a message queue, the situation is very different.&lt;/p&gt;

&lt;p&gt;The Order Service publishes the event successfully.&lt;/p&gt;

&lt;p&gt;The broker safely stores the message.&lt;/p&gt;

&lt;p&gt;The Notification Service can process it later after recovering.&lt;/p&gt;

&lt;p&gt;The customer still receives a successful order confirmation because the critical business operation—the purchase itself—has already completed.&lt;/p&gt;

&lt;p&gt;This ability to temporarily decouple producers and consumers is one of the biggest reasons message queues are so widely adopted.&lt;/p&gt;

&lt;p&gt;Services no longer have to be available at exactly the same moment.&lt;/p&gt;

&lt;p&gt;The broker absorbs temporary failures and smooths communication between systems.&lt;/p&gt;

&lt;h2&gt;
  
  
  Handling Traffic Spikes
&lt;/h2&gt;

&lt;p&gt;Another major advantage of message queues appears during periods of unusually high traffic.&lt;/p&gt;

&lt;p&gt;Imagine an online retailer during Black Friday.&lt;/p&gt;

&lt;p&gt;Millions of customers begin placing orders simultaneously.&lt;/p&gt;

&lt;p&gt;The Order Service processes purchases as quickly as possible.&lt;/p&gt;

&lt;p&gt;However, sending emails, generating invoices, updating analytics, and notifying warehouse systems all require additional processing time.&lt;/p&gt;

&lt;p&gt;If every service attempted to perform all this work immediately, the entire platform could become overwhelmed.&lt;/p&gt;

&lt;p&gt;Message queues naturally absorb these spikes.&lt;/p&gt;

&lt;p&gt;Incoming events accumulate inside the queue.&lt;/p&gt;

&lt;p&gt;Consumers process them at a sustainable rate.&lt;/p&gt;

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

&lt;p&gt;This buffering effect prevents downstream services from becoming overloaded.&lt;/p&gt;

&lt;p&gt;Instead of rejecting requests, the system gracefully handles temporary bursts in demand.&lt;/p&gt;

&lt;p&gt;This is one reason message queues are often compared to waiting lines at supermarkets.&lt;/p&gt;

&lt;p&gt;Customers continue arriving.&lt;/p&gt;

&lt;p&gt;Some wait briefly.&lt;/p&gt;

&lt;p&gt;Cashiers process them one at a time.&lt;/p&gt;

&lt;p&gt;The line absorbs fluctuations in arrival rates.&lt;/p&gt;

&lt;h2&gt;
  
  
  Scaling Consumers Independently
&lt;/h2&gt;

&lt;p&gt;Suppose the Notification Service cannot keep up with incoming messages.&lt;/p&gt;

&lt;p&gt;Unlike synchronous communication, we do not necessarily need a faster server.&lt;/p&gt;

&lt;p&gt;Instead, we can simply start more consumer instances.&lt;/p&gt;

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

&lt;p&gt;Each consumer retrieves messages independently.&lt;/p&gt;

&lt;p&gt;The workload becomes distributed across multiple workers.&lt;/p&gt;

&lt;p&gt;As demand increases, additional consumers can be added.&lt;/p&gt;

&lt;p&gt;As traffic decreases, unnecessary consumers can be removed.&lt;/p&gt;

&lt;p&gt;This makes message queues naturally compatible with horizontal scaling, one of the concepts we explored earlier in this series.&lt;/p&gt;

&lt;p&gt;Rather than scaling the producer, we scale the workers responsible for processing queued tasks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Popular Message Queue Technologies
&lt;/h2&gt;

&lt;p&gt;Over the years, several technologies have become industry standards for asynchronous communication.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;RabbitMQ&lt;/strong&gt; is one of the most widely used traditional message brokers. It provides reliable message delivery, flexible routing, acknowledgements, retries, and mature tooling, making it an excellent choice for many business applications.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Apache Kafka&lt;/strong&gt; approaches the problem from a slightly different perspective. Rather than acting solely as a message queue, Kafka functions as a distributed event streaming platform capable of handling enormous volumes of events every second. Organisations use Kafka extensively for log aggregation, analytics pipelines, financial systems, IoT platforms, and real-time data processing.&lt;/p&gt;

&lt;p&gt;Cloud providers also offer managed messaging services such as &lt;strong&gt;Amazon SQS&lt;/strong&gt;, &lt;strong&gt;Google Cloud Pub/Sub&lt;/strong&gt;, and &lt;strong&gt;Azure Service Bus&lt;/strong&gt;, allowing teams to adopt asynchronous communication without managing broker infrastructure themselves.&lt;/p&gt;

&lt;p&gt;Although these technologies differ in implementation, they all pursue the same goal:&lt;/p&gt;

&lt;p&gt;Allow independent systems to communicate without requiring them to be available at exactly the same time.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Cost of Asynchronous Communication
&lt;/h2&gt;

&lt;p&gt;Message queues provide remarkable flexibility, but they also introduce new challenges.&lt;/p&gt;

&lt;p&gt;One obvious trade-off is that communication is no longer immediate.&lt;/p&gt;

&lt;p&gt;If an email service processes messages five seconds later, that delay is usually acceptable.&lt;/p&gt;

&lt;p&gt;If a payment confirmation arrives five seconds later, the customer may become concerned.&lt;/p&gt;

&lt;p&gt;Choosing asynchronous communication therefore requires understanding which operations are time-sensitive and which are not.&lt;/p&gt;

&lt;p&gt;Another challenge is debugging.&lt;/p&gt;

&lt;p&gt;In synchronous systems, following a request is relatively straightforward.&lt;/p&gt;

&lt;p&gt;With asynchronous systems, events may pass through brokers, retries, dead-letter queues, and multiple consumers before finally completing.&lt;/p&gt;

&lt;p&gt;Understanding the lifecycle of a single business operation becomes considerably more difficult.&lt;/p&gt;

&lt;p&gt;This is why mature event-driven systems rely heavily on distributed tracing, centralised logging, and observability tools.&lt;/p&gt;

&lt;p&gt;As systems become more asynchronous, visibility becomes just as important as functionality.&lt;/p&gt;

&lt;h2&gt;
  
  
  Asynchronous Communication Is About Independence
&lt;/h2&gt;

&lt;p&gt;Perhaps the most important lesson about message queues is that they are not simply another communication technology.&lt;/p&gt;

&lt;p&gt;They represent a different philosophy.&lt;/p&gt;

&lt;p&gt;REST asks another service to perform work immediately.&lt;/p&gt;

&lt;p&gt;gRPC performs the same idea more efficiently.&lt;/p&gt;

&lt;p&gt;Message queues remove the requirement for immediate cooperation altogether.&lt;/p&gt;

&lt;p&gt;Instead of saying,&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Do this now."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;they simply say,&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"This happened."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That small change dramatically reduces coupling, improves resilience, smooths traffic spikes, and allows systems to evolve independently.&lt;/p&gt;

&lt;p&gt;Throughout this article, we have explored three fundamentally different ways in which services communicate inside modern distributed systems.&lt;/p&gt;

&lt;p&gt;We began with REST, the communication style that powers much of today's internet. We then looked at gRPC, a high-performance framework designed specifically for efficient service-to-service communication. Finally, we explored message queues, which abandon direct conversations altogether in favor of asynchronous event-driven communication.&lt;/p&gt;

&lt;p&gt;At first, these technologies may appear to compete with one another.&lt;/p&gt;

&lt;p&gt;After all, they all allow one system to communicate with another.&lt;/p&gt;

&lt;p&gt;So a natural question arises:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Which one should we use?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Interestingly, experienced system designers rarely ask that question.&lt;/p&gt;

&lt;p&gt;Instead, they ask a different one.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;What kind of conversation are these services trying to have?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That subtle shift in thinking often leads to the correct architectural decision.&lt;/p&gt;

&lt;h2&gt;
  
  
  There Is No Universal Winner
&lt;/h2&gt;

&lt;p&gt;One of the biggest mistakes engineers make when learning system design is searching for the "best" technology.&lt;/p&gt;

&lt;p&gt;Should we always use gRPC because it is faster?&lt;/p&gt;

&lt;p&gt;Should we replace every REST API with Kafka?&lt;/p&gt;

&lt;p&gt;Should every microservice communicate asynchronously?&lt;/p&gt;

&lt;p&gt;The answer to all of these questions is no.&lt;/p&gt;

&lt;p&gt;Each communication model was designed to solve a different problem.&lt;/p&gt;

&lt;p&gt;Using the wrong one is similar to using a screwdriver to hammer a nail.&lt;/p&gt;

&lt;p&gt;The tool is not bad.&lt;/p&gt;

&lt;p&gt;It is simply solving a different problem.&lt;/p&gt;

&lt;p&gt;REST optimises for simplicity.&lt;/p&gt;

&lt;p&gt;gRPC optimises for efficiency.&lt;/p&gt;

&lt;p&gt;Message queues optimise for independence.&lt;/p&gt;

&lt;p&gt;Understanding those goals is far more valuable than memorising implementation details.&lt;/p&gt;

&lt;h2&gt;
  
  
  When REST Is the Right Choice
&lt;/h2&gt;

&lt;p&gt;REST remains the most appropriate choice whenever communication involves external clients.&lt;/p&gt;

&lt;p&gt;Browsers, mobile applications, desktop applications, and third-party developers all understand HTTP exceptionally well.&lt;/p&gt;

&lt;p&gt;If your application exposes a public API, REST is often the safest and most practical option.&lt;/p&gt;

&lt;p&gt;Imagine a food delivery application.&lt;/p&gt;

&lt;p&gt;A customer's mobile app needs to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;View nearby restaurants.&lt;/li&gt;
&lt;li&gt;Browse menus.&lt;/li&gt;
&lt;li&gt;Place an order.&lt;/li&gt;
&lt;li&gt;Track delivery status.&lt;/li&gt;
&lt;li&gt;View previous orders.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each of these actions follows a straightforward request-response pattern.&lt;/p&gt;

&lt;p&gt;The client asks for information.&lt;/p&gt;

&lt;p&gt;The server responds immediately.&lt;/p&gt;

&lt;p&gt;REST fits naturally into this style of interaction.&lt;/p&gt;

&lt;p&gt;It is also an excellent choice when readability and interoperability are more important than absolute performance.&lt;/p&gt;

&lt;p&gt;Because REST commonly uses JSON, developers can inspect requests with a browser, Postman, or &lt;code&gt;curl&lt;/code&gt;, making development and debugging remarkably convenient.&lt;/p&gt;

&lt;h2&gt;
  
  
  When gRPC Becomes a Better Choice
&lt;/h2&gt;

&lt;p&gt;Now consider the communication happening inside the backend.&lt;/p&gt;

&lt;p&gt;The Order Service may need to communicate with the Inventory Service dozens of times every second.&lt;/p&gt;

&lt;p&gt;The Recommendation Service may continuously exchange information with machine learning systems.&lt;/p&gt;

&lt;p&gt;A Search Service may call several ranking engines before returning results.&lt;/p&gt;

&lt;p&gt;These services are all controlled by the same organisation.&lt;/p&gt;

&lt;p&gt;There is no need for human-readable JSON.&lt;/p&gt;

&lt;p&gt;There is no requirement for browser compatibility.&lt;/p&gt;

&lt;p&gt;Performance becomes the primary concern.&lt;/p&gt;

&lt;p&gt;This is precisely where gRPC shines.&lt;/p&gt;

&lt;p&gt;Its binary serialisation, HTTP/2 transport, persistent connections, and strongly defined contracts make it ideal for internal communication between trusted services.&lt;/p&gt;

&lt;p&gt;The user never interacts with gRPC directly.&lt;/p&gt;

&lt;p&gt;Instead, it quietly enables fast communication behind the scenes.&lt;/p&gt;

&lt;p&gt;Many organisations therefore expose REST APIs publicly while using gRPC internally.&lt;/p&gt;

&lt;p&gt;This hybrid architecture combines the accessibility of REST with the efficiency of gRPC.&lt;/p&gt;

&lt;h2&gt;
  
  
  When Message Queues Are the Better Solution
&lt;/h2&gt;

&lt;p&gt;Some operations simply do not require immediate responses.&lt;/p&gt;

&lt;p&gt;Suppose a customer successfully purchases a product.&lt;/p&gt;

&lt;p&gt;Several additional activities may need to occur afterwards.&lt;/p&gt;

&lt;p&gt;A confirmation email must be sent.&lt;/p&gt;

&lt;p&gt;Analytics should record the purchase.&lt;/p&gt;

&lt;p&gt;Inventory forecasting should update demand predictions.&lt;/p&gt;

&lt;p&gt;Warehouse systems should prepare packaging.&lt;/p&gt;

&lt;p&gt;Recommendation engines should learn from customer behaviour.&lt;/p&gt;

&lt;p&gt;Notice that none of these tasks should delay the checkout experience.&lt;/p&gt;

&lt;p&gt;The customer only cares that the order has been placed successfully.&lt;/p&gt;

&lt;p&gt;Everything else can happen afterwards.&lt;/p&gt;

&lt;p&gt;This makes asynchronous communication a far better choice than synchronous requests.&lt;/p&gt;

&lt;p&gt;Instead of contacting every downstream service directly, the Order Service simply publishes an &lt;strong&gt;OrderCreated&lt;/strong&gt; event.&lt;/p&gt;

&lt;p&gt;Every interested service processes that event independently.&lt;/p&gt;

&lt;p&gt;The checkout experience remains fast.&lt;/p&gt;

&lt;p&gt;The architecture becomes more resilient.&lt;/p&gt;

&lt;p&gt;New services can subscribe to the event without modifying existing code.&lt;/p&gt;

&lt;p&gt;This ability to evolve naturally is one of the greatest strengths of event-driven architectures.&lt;/p&gt;

&lt;h2&gt;
  
  
  Modern Systems Rarely Choose Just One
&lt;/h2&gt;

&lt;p&gt;One of the most interesting observations about large technology companies is that they rarely commit to a single communication mechanism.&lt;/p&gt;

&lt;p&gt;Instead, they combine several approaches, allowing each to solve the problems it handles best.&lt;/p&gt;

&lt;p&gt;A typical architecture might resemble the following:&lt;/p&gt;

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

&lt;p&gt;Notice how each communication model has a clearly defined responsibility.&lt;/p&gt;

&lt;p&gt;The mobile application communicates with backend services using REST because HTTP and JSON are universally supported.&lt;/p&gt;

&lt;p&gt;Internal services communicate with one another using gRPC because efficiency matters more than readability.&lt;/p&gt;

&lt;p&gt;Business events are distributed through message queues because many downstream services do not require immediate responses.&lt;/p&gt;

&lt;p&gt;Rather than competing, these technologies complement one another.&lt;/p&gt;

&lt;h2&gt;
  
  
  Choosing the Right Communication Style
&lt;/h2&gt;

&lt;p&gt;Whenever designing communication between services, it is useful to begin by asking a series of simple questions.&lt;/p&gt;

&lt;p&gt;The first question is whether the caller requires an immediate response.&lt;/p&gt;

&lt;p&gt;If the answer is yes, synchronous communication such as REST or gRPC is usually appropriate.&lt;/p&gt;

&lt;p&gt;The second question concerns performance.&lt;/p&gt;

&lt;p&gt;If communication happens frequently between internal services and latency is critical, gRPC often provides significant advantages.&lt;/p&gt;

&lt;p&gt;The third question is whether the work must happen immediately.&lt;/p&gt;

&lt;p&gt;If the answer is no, asynchronous messaging usually results in a simpler and more resilient architecture.&lt;/p&gt;

&lt;p&gt;Finally, consider ownership.&lt;/p&gt;

&lt;p&gt;If the API will be consumed by external customers, partners, or public developers, REST remains the most approachable option because of its universal adoption and extensive tooling.&lt;/p&gt;

&lt;p&gt;Thinking about the nature of the conversation rather than the technology itself almost always leads to better architectural decisions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Communication Is About Trade-offs
&lt;/h2&gt;

&lt;p&gt;Throughout this System Design series, one theme has appeared repeatedly.&lt;/p&gt;

&lt;p&gt;There is rarely a perfect solution.&lt;/p&gt;

&lt;p&gt;Monoliths trade flexibility for simplicity.&lt;/p&gt;

&lt;p&gt;Distributed systems trade simplicity for scalability.&lt;/p&gt;

&lt;p&gt;Horizontal scaling trades hardware upgrades for coordination.&lt;/p&gt;

&lt;p&gt;Microservices trade organisational independence for operational complexity.&lt;/p&gt;

&lt;p&gt;Communication mechanisms follow the same pattern.&lt;/p&gt;

&lt;p&gt;REST is easy to understand but introduces additional overhead.&lt;/p&gt;

&lt;p&gt;gRPC improves efficiency but sacrifices some simplicity and requires specialised tooling.&lt;/p&gt;

&lt;p&gt;Message queues increase resilience and decoupling but introduce eventual consistency and make systems harder to observe and debug.&lt;/p&gt;

&lt;p&gt;Good system design is therefore not about selecting the newest technology.&lt;/p&gt;

&lt;p&gt;It is about selecting the technology whose trade-offs best match the problem you are trying to solve.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;As applications evolve from monoliths into distributed systems, communication becomes one of the most important architectural concerns.&lt;/p&gt;

&lt;p&gt;The quality of a distributed system is determined not only by how well individual services are implemented but also by how effectively those services cooperate.&lt;/p&gt;

&lt;p&gt;REST, gRPC, and message queues each represent a different philosophy of communication.&lt;/p&gt;

&lt;p&gt;REST emphasises simplicity and broad compatibility.&lt;/p&gt;

&lt;p&gt;gRPC emphasises speed, efficiency, and strongly defined contracts.&lt;/p&gt;

&lt;p&gt;Message queues emphasise independence, resilience, and asynchronous processing.&lt;/p&gt;

&lt;p&gt;The most successful systems are rarely built around just one of these approaches.&lt;/p&gt;

&lt;p&gt;Instead, they combine all three, allowing each communication model to solve the problems for which it was designed.&lt;/p&gt;

&lt;p&gt;Perhaps that is the most important lesson from this article.&lt;/p&gt;

&lt;p&gt;In system design, the goal is not to find a single technology that solves every problem.&lt;/p&gt;

&lt;p&gt;The goal is to understand the strengths and limitations of each tool well enough to know &lt;strong&gt;when&lt;/strong&gt; to use it.&lt;/p&gt;

&lt;p&gt;And that ability to choose the right tool for the right problem is what ultimately distinguishes a good software engineer from a great system designer.&lt;/p&gt;

</description>
      <category>systemdesign</category>
      <category>restapi</category>
      <category>architecture</category>
      <category>programming</category>
    </item>
    <item>
      <title>Microservices Architecture: Benefits, Challenges, and When to Use It</title>
      <dc:creator>Sushant Gaurav</dc:creator>
      <pubDate>Tue, 28 Jul 2026 05:41:00 +0000</pubDate>
      <link>https://dev.to/imsushant12/microservices-architecture-benefits-challenges-and-when-to-use-it-cad</link>
      <guid>https://dev.to/imsushant12/microservices-architecture-benefits-challenges-and-when-to-use-it-cad</guid>
      <description>&lt;p&gt;For many engineers, microservices are one of the first concepts that come to mind when discussing modern system design.&lt;/p&gt;

&lt;p&gt;Job descriptions mention them constantly. Conference talks celebrate them. Architecture diagrams often contain dozens or even hundreds of small services communicating with one another. It is easy to come away with the impression that microservices represent the final destination of software architecture - that every successful application eventually becomes a collection of independently deployed services.&lt;/p&gt;

&lt;p&gt;The reality is considerably more nuanced.&lt;/p&gt;

&lt;p&gt;Microservices are not the next version of monoliths in the same way that smartphones replaced feature phones. They are not universally better, nor are they the inevitable future of every application. Instead, microservices are an architectural response to a very specific set of problems that begin to appear as systems and organisations grow.&lt;/p&gt;

&lt;p&gt;To understand why microservices exist, we first need to understand the world before them.&lt;/p&gt;

&lt;p&gt;For a very long time, most applications were built as monoliths. User authentication, product management, payments, inventory, notifications, analytics, reporting, and administration all lived inside a single codebase and were deployed together as a single application.&lt;/p&gt;

&lt;p&gt;For small and medium-sized systems, this approach worked remarkably well.&lt;/p&gt;

&lt;p&gt;A developer could clone the repository, run the application locally, and understand the request flow from beginning to end. Debugging was relatively straightforward because everything lived in one place. Deployments involved building and releasing a single artefact. Transactions across modules were simple because all the code ran within the same process and often accessed the same database.&lt;/p&gt;

&lt;p&gt;This simplicity is one of the reasons monoliths continue to power a large percentage of software systems around the world.&lt;/p&gt;

&lt;p&gt;However, successful systems have a tendency to grow in ways that architecture diagrams rarely anticipate.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Teams become larger.&lt;/li&gt;
&lt;li&gt;Features become more numerous.&lt;/li&gt;
&lt;li&gt;Release cycles become more frequent.&lt;/li&gt;
&lt;li&gt;Different parts of the application begin evolving at different speeds.&lt;/li&gt;
&lt;li&gt;What started as a clean and elegant codebase slowly begins to feel heavier.&lt;/li&gt;
&lt;li&gt;A small change to one module unexpectedly affects another.&lt;/li&gt;
&lt;li&gt;Deployment times increase.&lt;/li&gt;
&lt;li&gt;Testing becomes slower.&lt;/li&gt;
&lt;li&gt;The number of developers working in the same repository continues growing until coordination itself becomes a challenge.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Eventually organizations discover that the problem is no longer computational complexity.&lt;/p&gt;

&lt;p&gt;It is organisational complexity.&lt;/p&gt;

&lt;p&gt;A payment team wants to deploy a new feature, but must wait for the inventory team to finish testing their changes.&lt;/p&gt;

&lt;p&gt;The recommendation engine requires additional compute resources during peak traffic periods, but scaling means scaling the entire application, including components that are barely being used.&lt;/p&gt;

&lt;p&gt;Different teams want to adopt different technologies, databases, and deployment strategies, yet the architecture forces everyone into the same decisions.&lt;/p&gt;

&lt;p&gt;The application begins behaving less like a product and more like a city that has grown without urban planning.&lt;/p&gt;

&lt;p&gt;This is the environment from which microservices emerged.&lt;/p&gt;

&lt;p&gt;Instead of treating the application as a single deployable unit, the system is divided into smaller services that each own a specific business capability.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The payment service owns payments.&lt;/li&gt;
&lt;li&gt;The inventory service owns inventory.&lt;/li&gt;
&lt;li&gt;The notification service owns notifications.&lt;/li&gt;
&lt;li&gt;The recommendation service owns recommendations.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each service becomes responsible for its own logic, data, deployment, and scaling requirements.&lt;/p&gt;

&lt;p&gt;Conceptually, the architecture starts looking something like this:&lt;/p&gt;

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

&lt;p&gt;The most important aspect of this diagram is not the number of services.&lt;/p&gt;

&lt;p&gt;It is ownership.&lt;/p&gt;

&lt;p&gt;Each service becomes a small system with clear responsibilities and well-defined boundaries. Teams can work independently because they no longer need to understand the entire application to make progress in their own domain.&lt;/p&gt;

&lt;p&gt;This shift introduces one of the biggest philosophical differences between monoliths and microservices.&lt;/p&gt;

&lt;p&gt;In a monolith, components communicate through function calls.&lt;br&gt;
In microservices, communication happens over a network.&lt;/p&gt;

&lt;p&gt;At first, this sounds insignificant.&lt;/p&gt;

&lt;p&gt;After all, a service call is just another request.&lt;/p&gt;

&lt;p&gt;In reality, this changes almost everything.&lt;/p&gt;

&lt;p&gt;A function call inside a monolith takes microseconds and rarely fails.&lt;/p&gt;

&lt;p&gt;A network request may take milliseconds, may experience congestion, may time out, may be retried, or may fail.&lt;/p&gt;

&lt;p&gt;What used to be a simple method invocation suddenly becomes a distributed systems problem involving latency, retries, availability, and fault tolerance.&lt;/p&gt;

&lt;p&gt;This is one of the reasons many engineers say that adopting microservices means adopting distributed systems.&lt;/p&gt;

&lt;p&gt;The complexity does not disappear.&lt;/p&gt;

&lt;p&gt;It simply moves.&lt;/p&gt;

&lt;p&gt;Instead of managing complexity inside a codebase, we begin managing complexity between services.&lt;/p&gt;

&lt;p&gt;This is neither good nor bad.&lt;/p&gt;

&lt;p&gt;It is a trade-off.&lt;/p&gt;

&lt;p&gt;And like every major architectural decision in system design, understanding those trade-offs is far more important than understanding the technology itself.&lt;/p&gt;

&lt;p&gt;Perhaps the greatest misconception surrounding microservices is the belief that they are primarily a scaling strategy.&lt;/p&gt;

&lt;p&gt;They are not.&lt;/p&gt;

&lt;p&gt;Companies rarely move to microservices because their servers cannot handle traffic.&lt;/p&gt;

&lt;p&gt;More often, they move because their teams cannot handle coordination.&lt;/p&gt;

&lt;p&gt;When hundreds or thousands of engineers are working on the same product, organisational scalability becomes just as important as technical scalability.&lt;/p&gt;

&lt;p&gt;Microservices allow teams to move independently, deploy independently, and evolve independently.&lt;/p&gt;

&lt;p&gt;This alignment between software architecture and team structure is so common that it is often summarised by Conway's Law:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Organisations tend to design systems that mirror their communication structures.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A company with ten independent teams often ends up building ten independent services.&lt;/p&gt;

&lt;p&gt;A company with a single tightly integrated team often builds a monolith.&lt;/p&gt;

&lt;p&gt;Architecture and organisational design are frequently reflections of one another.&lt;/p&gt;

&lt;p&gt;This is why the decision to adopt microservices is rarely just an engineering decision.&lt;/p&gt;

&lt;p&gt;It is often a business decision, a team decision, and an operational decision all at the same time.&lt;/p&gt;

&lt;p&gt;Understanding this context is essential because, without it, microservices can appear to be an obvious improvement over monoliths.&lt;/p&gt;

&lt;p&gt;They are not.&lt;/p&gt;

&lt;p&gt;They solve certain problems extremely well.&lt;/p&gt;

&lt;p&gt;They also create entirely new categories of problems that monoliths never had to worry about.&lt;/p&gt;

&lt;h2&gt;
  
  
  Independent Deployment Changes the Development Process
&lt;/h2&gt;

&lt;p&gt;One of the biggest advantages of microservices is that they allow different parts of the system to evolve independently.&lt;/p&gt;

&lt;p&gt;Consider an e-commerce platform built as a monolith.&lt;/p&gt;

&lt;p&gt;The payment team develops a new payment integration. At the same time, the recommendation team is experimenting with a new machine learning model, while the notification team is redesigning the email delivery pipeline.&lt;/p&gt;

&lt;p&gt;In a monolithic architecture, all these changes eventually converge into the same application deployment.&lt;/p&gt;

&lt;p&gt;Even though these teams are working on completely unrelated features, they still share release cycles, testing pipelines, deployment windows, and rollback procedures.&lt;/p&gt;

&lt;p&gt;This creates coordination overhead.&lt;/p&gt;

&lt;p&gt;A delay in one team may delay everyone else.&lt;/p&gt;

&lt;p&gt;A bug in one component may prevent unrelated features from reaching production.&lt;/p&gt;

&lt;p&gt;As organisations grow, these dependencies become increasingly painful.&lt;/p&gt;

&lt;p&gt;Microservices attempt to solve this by allowing services to be deployed independently.&lt;/p&gt;

&lt;p&gt;The payment team can deploy payment changes without waiting for the recommendation team.&lt;/p&gt;

&lt;p&gt;The notification service can release a new version without affecting inventory management.&lt;/p&gt;

&lt;p&gt;The recommendation service can experiment rapidly without introducing risk into unrelated parts of the application.&lt;/p&gt;

&lt;p&gt;The result is not necessarily faster code execution.&lt;/p&gt;

&lt;p&gt;The result is faster organisational movement.&lt;/p&gt;

&lt;h2&gt;
  
  
  Independent Scaling Allows Resources to Follow Demand
&lt;/h2&gt;

&lt;p&gt;Another significant advantage appears when different parts of the system experience different workloads.&lt;/p&gt;

&lt;p&gt;In most applications, traffic is rarely distributed evenly.&lt;/p&gt;

&lt;p&gt;An online marketplace may process millions of product searches every hour while receiving far fewer payment requests.&lt;/p&gt;

&lt;p&gt;A video streaming platform may generate enormous traffic for video delivery while user profile services remain relatively idle.&lt;/p&gt;

&lt;p&gt;A social network may receive vastly more feed requests than account creation requests.&lt;/p&gt;

&lt;p&gt;In a monolithic architecture, scaling one part of the application often means scaling everything.&lt;/p&gt;

&lt;p&gt;Even if only the search functionality is under pressure, additional instances of the entire application may need to be deployed.&lt;/p&gt;

&lt;p&gt;This increases infrastructure costs and wastes resources.&lt;/p&gt;

&lt;p&gt;Microservices allow organisations to scale individual services according to their own requirements.&lt;/p&gt;

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

&lt;p&gt;The search service may run on twenty instances while the payment service operates comfortably on three.&lt;/p&gt;

&lt;p&gt;This granularity allows infrastructure decisions to reflect actual usage patterns rather than architectural limitations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Technology Diversity Becomes Possible
&lt;/h2&gt;

&lt;p&gt;One of the less discussed advantages of microservices is technological flexibility.&lt;/p&gt;

&lt;p&gt;Different problems are often best solved using different tools.&lt;/p&gt;

&lt;p&gt;A recommendation engine performing machine learning inference may benefit from Python.&lt;/p&gt;

&lt;p&gt;A high-performance messaging system may be better suited to Go.&lt;/p&gt;

&lt;p&gt;A payment system requiring mature transactional guarantees may prefer Java and relational databases.&lt;/p&gt;

&lt;p&gt;An analytics pipeline may rely heavily on distributed data processing frameworks.&lt;/p&gt;

&lt;p&gt;In a monolith, these decisions are constrained by the technology choices of the entire application.&lt;/p&gt;

&lt;p&gt;Microservices make this separation possible because services communicate through APIs rather than internal language constructs.&lt;/p&gt;

&lt;p&gt;The recommendation service does not need to know how the payment service is implemented.&lt;/p&gt;

&lt;p&gt;It only needs to understand the contract exposed by its API.&lt;/p&gt;

&lt;p&gt;This flexibility is powerful, but as we will see shortly, it can also become dangerous if left uncontrolled.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fault Isolation Improves Resilience
&lt;/h2&gt;

&lt;p&gt;Failures are inevitable in software systems.&lt;/p&gt;

&lt;p&gt;Servers crash.&lt;/p&gt;

&lt;p&gt;Databases become unavailable.&lt;/p&gt;

&lt;p&gt;Network partitions occur.&lt;/p&gt;

&lt;p&gt;Dependency time out.&lt;/p&gt;

&lt;p&gt;The question is rarely whether failure will happen.&lt;/p&gt;

&lt;p&gt;The question is how much of the system fails when it does.&lt;/p&gt;

&lt;p&gt;In a tightly coupled monolith, failures can propagate rapidly.&lt;/p&gt;

&lt;p&gt;A memory leak in one component may exhaust resources for the entire application.&lt;/p&gt;

&lt;p&gt;A slow database query may impact unrelated functionality.&lt;/p&gt;

&lt;p&gt;An overloaded subsystem may cause widespread degradation.&lt;/p&gt;

&lt;p&gt;Microservices improve isolation by creating boundaries between components.&lt;/p&gt;

&lt;p&gt;If the recommendation service experiences problems, users may temporarily lose personalised recommendations while the rest of the platform continues operating normally.&lt;/p&gt;

&lt;p&gt;The application degrades gracefully rather than collapsing completely.&lt;/p&gt;

&lt;p&gt;This idea is often referred to as the &lt;strong&gt;blast radius&lt;/strong&gt; of failure.&lt;/p&gt;

&lt;p&gt;Microservices aim to reduce the blast radius.&lt;/p&gt;

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

&lt;p&gt;Reducing the impact of failures is one of the strongest arguments in favour of service decomposition.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Complexity That Replaces the Monolith
&lt;/h2&gt;

&lt;p&gt;At this point, microservices can sound almost ideal.&lt;/p&gt;

&lt;p&gt;Independent deployments.&lt;/p&gt;

&lt;p&gt;Independent scaling.&lt;/p&gt;

&lt;p&gt;Fault isolation.&lt;/p&gt;

&lt;p&gt;Technology flexibility.&lt;/p&gt;

&lt;p&gt;So why doesn't every company immediately move to microservices?&lt;/p&gt;

&lt;p&gt;Because microservices solve one type of complexity by introducing another.&lt;/p&gt;

&lt;p&gt;Remember the observation from the previous part:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Complexity does not disappear. It moves.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In a monolith, communication happens through local function calls.&lt;/p&gt;

&lt;p&gt;In microservices, communication happens through networks.&lt;/p&gt;

&lt;p&gt;And networks are fundamentally unreliable.&lt;/p&gt;

&lt;p&gt;A function call rarely fails.&lt;/p&gt;

&lt;p&gt;A network request can fail for dozens of reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Packet loss&lt;/li&gt;
&lt;li&gt;Timeouts&lt;/li&gt;
&lt;li&gt;Congestion&lt;/li&gt;
&lt;li&gt;DNS failures&lt;/li&gt;
&lt;li&gt;Load balancer failures&lt;/li&gt;
&lt;li&gt;Service crashes&lt;/li&gt;
&lt;li&gt;Partial outages&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Suddenly, developers must think about retries, circuit breakers, backoff strategies, and timeout management.&lt;/p&gt;

&lt;p&gt;The application is no longer just software.&lt;/p&gt;

&lt;p&gt;It is a distributed system.&lt;/p&gt;

&lt;h2&gt;
  
  
  Data Becomes One of the Hardest Problems
&lt;/h2&gt;

&lt;p&gt;Monoliths often enjoy a luxury that microservices lose:&lt;/p&gt;

&lt;p&gt;A shared database.&lt;/p&gt;

&lt;p&gt;A single transaction can update multiple tables atomically.&lt;/p&gt;

&lt;p&gt;Consistency is relatively easy to achieve.&lt;/p&gt;

&lt;p&gt;Microservices intentionally avoid this model because shared databases create coupling between services.&lt;/p&gt;

&lt;p&gt;Instead, each service typically owns its own data.&lt;/p&gt;

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

&lt;p&gt;This improves service independence but introduces difficult questions.&lt;/p&gt;

&lt;p&gt;What happens when a payment succeeds but order creation fails?&lt;/p&gt;

&lt;p&gt;How do we maintain consistency across multiple databases?&lt;/p&gt;

&lt;p&gt;How do we roll back distributed operations?&lt;/p&gt;

&lt;p&gt;How do services coordinate business workflows?&lt;/p&gt;

&lt;p&gt;These problems eventually lead engineers toward concepts such as event-driven architectures, sagas, outbox patterns, and distributed transactions.&lt;/p&gt;

&lt;p&gt;Problems that never existed inside a simple monolith suddenly become central architectural concerns.&lt;/p&gt;

&lt;h2&gt;
  
  
  Observability Stops Being Optional
&lt;/h2&gt;

&lt;p&gt;Debugging a monolith can often be as simple as following logs from a single application instance.&lt;/p&gt;

&lt;p&gt;Microservices remove that convenience.&lt;/p&gt;

&lt;p&gt;A single user request may travel through:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;API Gateway&lt;/li&gt;
&lt;li&gt;Authentication Service&lt;/li&gt;
&lt;li&gt;User Service&lt;/li&gt;
&lt;li&gt;Payment Service&lt;/li&gt;
&lt;li&gt;Inventory Service&lt;/li&gt;
&lt;li&gt;Notification Service&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;When something goes wrong, finding the source of the problem becomes significantly harder.&lt;/p&gt;

&lt;p&gt;This is why mature microservice architectures invest heavily in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Distributed tracing&lt;/li&gt;
&lt;li&gt;Centralised logging&lt;/li&gt;
&lt;li&gt;Metrics collection&lt;/li&gt;
&lt;li&gt;Monitoring systems&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Observability evolves from a useful feature into a critical requirement.&lt;/p&gt;

&lt;p&gt;By this point, microservices can feel both exciting and intimidating at the same time.&lt;/p&gt;

&lt;p&gt;On one hand, they offer independent deployments, independent scaling, fault isolation, and organisational flexibility. On the other hand, they introduce distributed systems complexity, operational overhead, and entirely new categories of failure.&lt;/p&gt;

&lt;p&gt;This naturally leads to the most important question in the entire discussion:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;When should you actually use microservices?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Interestingly, the answer is not "as early as possible."&lt;/p&gt;

&lt;p&gt;In fact, for many systems, that answer would be actively harmful.&lt;/p&gt;

&lt;p&gt;One of the biggest misconceptions in modern software engineering is the belief that successful companies started with microservices and scaled effortlessly from day one.&lt;/p&gt;

&lt;p&gt;That is not what happened.&lt;/p&gt;

&lt;p&gt;Many of today's largest technology companies began with monolithic architectures.&lt;/p&gt;

&lt;p&gt;The early versions of companies like Amazon, Netflix, and Facebook were significantly more monolithic than many engineers realise.&lt;/p&gt;

&lt;p&gt;This was not because the engineers lacked knowledge.&lt;/p&gt;

&lt;p&gt;It was because monoliths optimise for something that startups desperately need:&lt;/p&gt;

&lt;p&gt;speed.&lt;/p&gt;

&lt;p&gt;When a company is trying to validate an idea, acquire users, and find product-market fit, the biggest risk is rarely scalability.&lt;/p&gt;

&lt;p&gt;The biggest risk is building the wrong product.&lt;/p&gt;

&lt;p&gt;During this stage, simplicity is a competitive advantage.&lt;/p&gt;

&lt;p&gt;A monolith allows teams to move quickly. Features can be built without worrying about service boundaries, network contracts, distributed tracing, or inter-service communication protocols.&lt;/p&gt;

&lt;p&gt;Developers can change database schemas quickly.&lt;/p&gt;

&lt;p&gt;Refactoring is easier.&lt;/p&gt;

&lt;p&gt;Testing is simpler.&lt;/p&gt;

&lt;p&gt;Deployment pipelines are smaller.&lt;/p&gt;

&lt;p&gt;Operational costs are lower.&lt;/p&gt;

&lt;p&gt;Most importantly, the engineering team can spend its energy solving business problems instead of infrastructure problems.&lt;/p&gt;

&lt;p&gt;This is why one of the most common pieces of advice in software architecture is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Start with a monolith and earn your microservices.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That statement is not a criticism of microservices.&lt;/p&gt;

&lt;p&gt;It is recognition that complexity should arrive only when it solves a real problem.&lt;/p&gt;

&lt;p&gt;Microservices are not free.&lt;/p&gt;

&lt;p&gt;Every service introduces additional deployment pipelines, monitoring requirements, infrastructure costs, API contracts, and operational responsibilities.&lt;/p&gt;

&lt;p&gt;A system with fifty microservices is not managing one application.&lt;/p&gt;

&lt;p&gt;It is managing fifty applications.&lt;/p&gt;

&lt;p&gt;That distinction becomes incredibly important as organisations grow.&lt;/p&gt;

&lt;h2&gt;
  
  
  Signs That a Team May Be Ready for Microservices
&lt;/h2&gt;

&lt;p&gt;While there is no universal threshold, certain patterns appear repeatedly in organisations that successfully adopt microservices.&lt;/p&gt;

&lt;p&gt;One common signal is organisational growth.&lt;/p&gt;

&lt;p&gt;When dozens or hundreds of engineers are contributing to the same codebase, coordination begins to slow development. Teams start stepping on each other's changes. Releases become increasingly risky because every deployment contains modifications from many unrelated teams.&lt;/p&gt;

&lt;p&gt;At some point, the bottleneck is no longer technical architecture.&lt;/p&gt;

&lt;p&gt;It is communication.&lt;/p&gt;

&lt;p&gt;Microservices can reduce this friction by allowing teams to own individual services and deploy independently.&lt;/p&gt;

&lt;p&gt;Another signal appears when different parts of the application have drastically different scaling requirements.&lt;/p&gt;

&lt;p&gt;Consider a streaming platform.&lt;/p&gt;

&lt;p&gt;The video processing pipeline may require enormous compute resources while account management requires comparatively little infrastructure.&lt;/p&gt;

&lt;p&gt;Scaling both components together becomes inefficient.&lt;/p&gt;

&lt;p&gt;Microservices allow resources to follow actual demand.&lt;/p&gt;

&lt;p&gt;The same pattern appears in machine learning systems, recommendation engines, search platforms, and analytics pipelines.&lt;/p&gt;

&lt;p&gt;Some components naturally become much larger than others.&lt;/p&gt;

&lt;p&gt;Independent scaling starts becoming valuable.&lt;/p&gt;

&lt;p&gt;A third signal appears when release velocity becomes a problem.&lt;/p&gt;

&lt;p&gt;If a minor update to the notification system requires coordination across multiple teams and weeks of testing for unrelated components, the deployment process itself becomes an obstacle to business growth.&lt;/p&gt;

&lt;p&gt;Independent deployments can dramatically improve development speed in these environments.&lt;/p&gt;

&lt;h2&gt;
  
  
  Signs That a Team Probably Should Not Use Microservices
&lt;/h2&gt;

&lt;p&gt;Interestingly, identifying situations where microservices are unnecessary is often easier.&lt;/p&gt;

&lt;p&gt;A small engineering team working on a relatively straightforward application rarely benefits from distributed complexity.&lt;/p&gt;

&lt;p&gt;If five developers are building an internal business application with moderate traffic, microservices often create more problems than they solve.&lt;/p&gt;

&lt;p&gt;The team now needs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Service discovery&lt;/li&gt;
&lt;li&gt;Monitoring infrastructure&lt;/li&gt;
&lt;li&gt;Centralised logging&lt;/li&gt;
&lt;li&gt;API versioning&lt;/li&gt;
&lt;li&gt;Deployment orchestration&lt;/li&gt;
&lt;li&gt;Network security policies&lt;/li&gt;
&lt;li&gt;Inter-service authentication&lt;/li&gt;
&lt;li&gt;Distributed tracing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of these problems existed before.&lt;/p&gt;

&lt;p&gt;The architecture becomes more sophisticated while the business problem remains the same.&lt;/p&gt;

&lt;p&gt;This is one of the reasons many organisations accidentally build what engineers jokingly call:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;a distributed monolith.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A distributed monolith has all the operational complexity of microservices but none of their advantages.&lt;/p&gt;

&lt;p&gt;Services are tightly coupled.&lt;/p&gt;

&lt;p&gt;Deployments still require coordination.&lt;/p&gt;

&lt;p&gt;Failures cascade between systems.&lt;/p&gt;

&lt;p&gt;Scaling remains difficult.&lt;/p&gt;

&lt;p&gt;The architecture becomes harder to understand without becoming more flexible.&lt;/p&gt;

&lt;p&gt;This is often considered one of the most painful outcomes of premature microservice adoption.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Hybrid Reality of Modern Systems
&lt;/h2&gt;

&lt;p&gt;The discussion is often framed as a choice between monoliths and microservices.&lt;/p&gt;

&lt;p&gt;Real systems are usually far more nuanced.&lt;/p&gt;

&lt;p&gt;Many organisations operate somewhere in the middle.&lt;/p&gt;

&lt;p&gt;A company may begin with a monolith and gradually extract services as scaling requirements emerge.&lt;/p&gt;

&lt;p&gt;Certain domains may remain inside the monolith for years while others become independent services.&lt;/p&gt;

&lt;p&gt;A recommendation engine may become a standalone service because it has unique computational requirements.&lt;/p&gt;

&lt;p&gt;Payment processing may become isolated because it has strict security and compliance requirements.&lt;/p&gt;

&lt;p&gt;Analytics pipelines may move into separate services because they require entirely different storage and processing technologies.&lt;/p&gt;

&lt;p&gt;Meanwhile, user management and administration may continue living inside the monolith.&lt;/p&gt;

&lt;p&gt;The result is neither a pure monolith nor a pure microservice architecture.&lt;/p&gt;

&lt;p&gt;It is a pragmatic architecture shaped by business needs rather than ideology.&lt;/p&gt;

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

&lt;p&gt;This gradual evolution is far more common than complete rewrites.&lt;/p&gt;

&lt;p&gt;In fact, many experienced architects prefer incremental extraction because it allows systems to evolve naturally rather than forcing large architectural migrations.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Most Important Lesson About Microservices
&lt;/h2&gt;

&lt;p&gt;Perhaps the most valuable lesson in this entire discussion is that architecture is ultimately a tool for managing complexity.&lt;/p&gt;

&lt;p&gt;Monoliths manage complexity by keeping everything together.&lt;/p&gt;

&lt;p&gt;Microservices manage complexity by separating things apart.&lt;/p&gt;

&lt;p&gt;Neither approach eliminates complexity.&lt;/p&gt;

&lt;p&gt;They simply decide where it lives.&lt;/p&gt;

&lt;p&gt;A small system with microservices may end up more complicated than necessary.&lt;/p&gt;

&lt;p&gt;A massive global platform with a monolith may eventually become impossible to maintain.&lt;/p&gt;

&lt;p&gt;Good architecture is rarely about following trends.&lt;/p&gt;

&lt;p&gt;It is about understanding trade-offs.&lt;/p&gt;

&lt;p&gt;The best architects are not the ones who always choose microservices.&lt;/p&gt;

&lt;p&gt;They are the ones who know when not to.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Microservices changed the software industry because they allowed systems and organisations to grow beyond the limits of a single application and a single team.&lt;/p&gt;

&lt;p&gt;They enabled independent deployment, independent scaling, and independent ownership.&lt;/p&gt;

&lt;p&gt;But they achieved these benefits by embracing the realities of distributed systems: unreliable networks, partial failures, eventual consistency, and operational complexity.&lt;/p&gt;

&lt;p&gt;That trade-off is the essence of microservices.&lt;/p&gt;

&lt;p&gt;They are not an upgrade from monoliths.&lt;/p&gt;

&lt;p&gt;They are a different answer to a different problem.&lt;/p&gt;

&lt;p&gt;And understanding the problem is far more important than understanding the technology.&lt;/p&gt;

</description>
      <category>systemdesign</category>
      <category>architecture</category>
      <category>programming</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Data Partitioning and Sharding: How Systems Scale Data</title>
      <dc:creator>Sushant Gaurav</dc:creator>
      <pubDate>Tue, 14 Jul 2026 05:41:00 +0000</pubDate>
      <link>https://dev.to/imsushant12/data-partitioning-and-sharding-how-systems-scale-data-m41</link>
      <guid>https://dev.to/imsushant12/data-partitioning-and-sharding-how-systems-scale-data-m41</guid>
      <description>&lt;p&gt;When engineers first learn about scalability, the conversation usually revolves around application servers.&lt;/p&gt;

&lt;p&gt;If traffic increases, add more servers. If requests increase, add a load balancer. If latency increases, introduce caching. For a while, this works remarkably well.&lt;/p&gt;

&lt;p&gt;Application servers are relatively easy to scale because they are typically stateless. If one server becomes overloaded, another can be added behind the load balancer, and traffic can simply be distributed between them.&lt;/p&gt;

&lt;p&gt;Databases are different.&lt;/p&gt;

&lt;p&gt;Unlike application servers, databases hold state. They contain user information, transactions, product catalogues, messages, orders, and every other piece of information that gives an application meaning. They are the memory of the system.&lt;/p&gt;

&lt;p&gt;And because databases hold state, scaling them becomes significantly harder.&lt;/p&gt;

&lt;p&gt;Eventually, almost every growing system encounters the same problem:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The application can still handle more traffic, but the database cannot.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is where data partitioning enters the picture.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Bigger Databases Are Not Always the Answer
&lt;/h2&gt;

&lt;p&gt;The first response to a struggling database is usually straightforward.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Increase the machine size.&lt;/li&gt;
&lt;li&gt;Add more CPU cores.&lt;/li&gt;
&lt;li&gt;Add more memory.&lt;/li&gt;
&lt;li&gt;Upgrade to faster SSDs.&lt;/li&gt;
&lt;li&gt;Move to a more powerful server.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This approach is known as &lt;strong&gt;vertical scaling&lt;/strong&gt;, and just like application servers, databases can benefit from it for a surprisingly long time.&lt;/p&gt;

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

&lt;p&gt;For many startups and medium-sized applications, vertical scaling is often enough.&lt;/p&gt;

&lt;p&gt;However, every machine eventually reaches physical and financial limits.&lt;/p&gt;

&lt;p&gt;There is always a larger server available—until there isn't.&lt;/p&gt;

&lt;p&gt;At some point, upgrading hardware stops providing meaningful improvements. Even worse, the entire system becomes dependent on a single machine.&lt;/p&gt;

&lt;p&gt;No matter how powerful that machine becomes, it is still only one machine.&lt;/p&gt;

&lt;p&gt;If it fails, the database fails. If the database fails, the application fails.&lt;/p&gt;

&lt;p&gt;This creates both a scalability problem and an availability problem.&lt;/p&gt;

&lt;p&gt;The question therefore, changes from:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"How do we make this database bigger?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;to:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"How do we distribute the database itself?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Understanding Data Partitioning
&lt;/h2&gt;

&lt;p&gt;Data partitioning is the process of dividing a large dataset into smaller and more manageable pieces.&lt;/p&gt;

&lt;p&gt;Instead of storing all users, all products, and all orders on a single database server, the data is split into multiple partitions and distributed across several machines.&lt;/p&gt;

&lt;p&gt;The idea itself is surprisingly intuitive.&lt;/p&gt;

&lt;p&gt;Imagine a library containing one hundred million books.&lt;/p&gt;

&lt;p&gt;Storing every book inside a single building would eventually create problems. The building would become too large, too expensive, and too difficult to maintain.&lt;/p&gt;

&lt;p&gt;A more practical solution would be to divide the books among multiple buildings.&lt;/p&gt;

&lt;p&gt;Each building stores only a subset of the collection. Together, the buildings form a complete library system. Individually, each building only manages a portion of the data.&lt;/p&gt;

&lt;p&gt;Databases use the same principle.&lt;/p&gt;

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

&lt;p&gt;From the perspective of the application, the database may still appear to be a single logical system.&lt;/p&gt;

&lt;p&gt;Behind the scenes, however, the data is physically distributed across multiple machines.&lt;/p&gt;

&lt;p&gt;This separation between logical simplicity and physical complexity is one of the defining characteristics of modern distributed systems.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is Sharding?
&lt;/h2&gt;

&lt;p&gt;The terms &lt;em&gt;partitioning&lt;/em&gt; and &lt;em&gt;sharding&lt;/em&gt; are often used interchangeably, and in many practical discussions they effectively mean the same thing.&lt;/p&gt;

&lt;p&gt;Strictly speaking, partitioning refers to the broader concept of splitting data into smaller pieces.&lt;/p&gt;

&lt;p&gt;Sharding is a specific type of partitioning in which those pieces are distributed across different physical machines.&lt;/p&gt;

&lt;p&gt;You can think of sharding as horizontal partitioning of data.&lt;/p&gt;

&lt;p&gt;Instead of making a single database server larger, we make the database wider by adding more machines.&lt;/p&gt;

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

&lt;p&gt;Each shard becomes responsible for storing a subset of the overall dataset.&lt;/p&gt;

&lt;p&gt;The application no longer talks to a single database server.&lt;/p&gt;

&lt;p&gt;Instead, it communicates with a routing layer that determines which shard owns the requested data.&lt;/p&gt;

&lt;p&gt;This may sound like a small architectural change.&lt;/p&gt;

&lt;p&gt;In reality, it changes everything.&lt;/p&gt;

&lt;p&gt;Because the moment data exists in multiple locations, entirely new problems begin to emerge.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Replication Alone Cannot Solve This Problem
&lt;/h2&gt;

&lt;p&gt;When discussing database scaling, many engineers initially assume replication can solve everything.&lt;/p&gt;

&lt;p&gt;After all, if one database becomes overloaded, why not simply create additional copies of it?&lt;/p&gt;

&lt;p&gt;Replication certainly helps, but it solves a very different problem.&lt;/p&gt;

&lt;p&gt;Replication creates multiple copies of the same data.&lt;/p&gt;

&lt;p&gt;Sharding divides the data into different pieces.&lt;/p&gt;

&lt;p&gt;Consider an application with one hundred million users.&lt;/p&gt;

&lt;p&gt;With replication, every replica contains all one hundred million users.&lt;/p&gt;

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

&lt;p&gt;This approach improves read scalability because read requests can be distributed across multiple replicas.&lt;/p&gt;

&lt;p&gt;It also improves availability because the system can continue operating if one replica fails.&lt;/p&gt;

&lt;p&gt;However, the primary database still receives every write request.&lt;/p&gt;

&lt;p&gt;Every new user registration, every order creation, and every transaction still goes to the same machine.&lt;/p&gt;

&lt;p&gt;Eventually, that machine becomes the bottleneck.&lt;/p&gt;

&lt;p&gt;Sharding addresses a completely different dimension of scalability.&lt;/p&gt;

&lt;p&gt;Instead of asking:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"How do we serve more readers?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It asks:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"How do we store and write more data?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Why Large Internet Systems Depend on Sharding
&lt;/h2&gt;

&lt;p&gt;Modern internet companies operate at scales that simply cannot be supported by a single database server.&lt;/p&gt;

&lt;p&gt;A social media platform may store billions of posts.&lt;/p&gt;

&lt;p&gt;An e-commerce platform may process millions of transactions every day.&lt;/p&gt;

&lt;p&gt;A ride-sharing platform may continuously ingest location updates from millions of devices.&lt;/p&gt;

&lt;p&gt;The volume of data alone makes single-node databases impractical.&lt;/p&gt;

&lt;p&gt;Sharding allows these systems to continue growing incrementally.&lt;/p&gt;

&lt;p&gt;When storage requirements increase, additional shards can be introduced.&lt;/p&gt;

&lt;p&gt;When write throughput increases, new shards can absorb part of the workload.&lt;/p&gt;

&lt;p&gt;Instead of upgrading to increasingly expensive hardware, capacity can be expanded horizontally.&lt;/p&gt;

&lt;p&gt;This is one of the reasons why sharding is often described as bringing horizontal scaling to databases.&lt;/p&gt;

&lt;p&gt;The philosophy is the same as horizontal scaling for application servers.&lt;/p&gt;

&lt;p&gt;Rather than building larger machines, we build larger systems.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Hidden Complexity of Sharding
&lt;/h2&gt;

&lt;p&gt;At this point, sharding may sound almost too good to be true.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;More storage.&lt;/li&gt;
&lt;li&gt;More throughput.&lt;/li&gt;
&lt;li&gt;Better scalability.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So why doesn't every application use it from day one?&lt;/p&gt;

&lt;p&gt;Because sharding introduces complexity that simply does not exist in single-database systems.&lt;/p&gt;

&lt;p&gt;The system must now answer difficult questions.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How does the application know which shard contains a particular user's data?&lt;/li&gt;
&lt;li&gt;What happens when one shard becomes significantly larger than the others?&lt;/li&gt;
&lt;li&gt;How are transactions handled when data spans multiple shards?&lt;/li&gt;
&lt;li&gt;What happens if a shard fails?&lt;/li&gt;
&lt;li&gt;How are backups managed?&lt;/li&gt;
&lt;li&gt;How are joins performed across shards?&lt;/li&gt;
&lt;li&gt;These problems are not implementation details.&lt;/li&gt;
&lt;li&gt;They are some of the hardest challenges in distributed systems.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And solving them requires entirely new techniques and architectural patterns.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Fundamental Question of Sharding
&lt;/h2&gt;

&lt;p&gt;The moment a system decides to split its data across multiple database servers, a surprisingly simple question becomes one of the most important architectural decisions in the entire system:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;How do we decide which shard stores which data?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A single database never has to think about this problem. Every query goes to the same machine. Every user record lives in the same place. Every order, product, message, and transaction can be found by asking a single database server.&lt;/p&gt;

&lt;p&gt;Sharding changes this completely.&lt;/p&gt;

&lt;p&gt;Now the system must determine where data belongs before it can even execute a query.&lt;/p&gt;

&lt;p&gt;If a user with ID &lt;code&gt;125847&lt;/code&gt; logs into the application, the system first needs to answer:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Which shard owns user 125847?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Only then can the actual database query begin.&lt;/p&gt;

&lt;p&gt;This process is known as a &lt;strong&gt;sharding strategy&lt;/strong&gt;, and the choice of strategy has enormous implications for scalability, performance, and operational complexity.&lt;/p&gt;

&lt;h2&gt;
  
  
  Range-Based Sharding
&lt;/h2&gt;

&lt;p&gt;One of the earliest and most intuitive approaches is range-based sharding.&lt;/p&gt;

&lt;p&gt;The idea is simple.&lt;/p&gt;

&lt;p&gt;Each database server becomes responsible for a specific range of values.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Shard 1 stores users with IDs from 1 to 1 million.&lt;/li&gt;
&lt;li&gt;Shard 2 stores users with IDs from 1 million to 2 million.&lt;/li&gt;
&lt;li&gt;Shard 3 stores users with IDs from 2 million to 3 million.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Visually, the architecture looks something like this:&lt;/p&gt;

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

&lt;p&gt;At first glance, this approach seems almost perfect.&lt;/p&gt;

&lt;p&gt;It is easy to understand. It is easy to implement. It is easy to debug. If someone asks where user 2,345,678 lives, the answer is immediately obvious.&lt;/p&gt;

&lt;p&gt;The problem is that real-world data is rarely distributed evenly.&lt;/p&gt;

&lt;p&gt;Imagine a social media platform where new users are constantly signing up.&lt;/p&gt;

&lt;p&gt;Most new users will have the latest IDs.&lt;/p&gt;

&lt;p&gt;This means almost all write traffic ends up hitting the newest shard while older shards remain relatively idle.&lt;/p&gt;

&lt;p&gt;One database server becomes overloaded while others sit underutilised.&lt;/p&gt;

&lt;p&gt;This phenomenon is known as a &lt;strong&gt;hotspot&lt;/strong&gt;, and it is one of the biggest challenges in distributed databases.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding Hotspots
&lt;/h2&gt;

&lt;p&gt;Hotspots occur when certain shards receive significantly more traffic than others.&lt;/p&gt;

&lt;p&gt;The issue may arise from user growth patterns, geographical concentration, or uneven business activity.&lt;/p&gt;

&lt;p&gt;Consider an e-commerce platform during a flash sale.&lt;/p&gt;

&lt;p&gt;If products are partitioned based on category and electronics happens to be the most popular category, the shard responsible for electronics suddenly receives an overwhelming amount of traffic.&lt;/p&gt;

&lt;p&gt;Meanwhile, other shards continue operating normally.&lt;/p&gt;

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

&lt;p&gt;The irony is that the system may have dozens of database servers available, yet performance still suffers because the load distribution itself is uneven.&lt;/p&gt;

&lt;p&gt;This is one of the reasons engineers started looking for more balanced approaches.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hash-Based Sharding
&lt;/h2&gt;

&lt;p&gt;Hash-based sharding attempts to solve this problem by distributing data more evenly across servers.&lt;/p&gt;

&lt;p&gt;Instead of storing data according to ranges, the system applies a mathematical hash function to the shard key.&lt;/p&gt;

&lt;p&gt;The result of the hash determines where the data will live.&lt;/p&gt;

&lt;p&gt;Conceptually, it works like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;hash(user_id) % number_of_shards
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Suppose the system currently has four shards.&lt;/p&gt;

&lt;p&gt;If the hash value of a user ID results in &lt;code&gt;2&lt;/code&gt;, that user is stored on shard two.&lt;/p&gt;

&lt;p&gt;If the result is &lt;code&gt;3&lt;/code&gt;, the user belongs to shard three.&lt;/p&gt;

&lt;p&gt;The actual values are less important than the outcome:&lt;/p&gt;

&lt;p&gt;The distribution becomes much more uniform.&lt;/p&gt;

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

&lt;p&gt;Unlike range-based sharding, newly created users are unlikely to end up on the same shard.&lt;/p&gt;

&lt;p&gt;Writes become naturally distributed across the cluster.&lt;/p&gt;

&lt;p&gt;This significantly reduces hotspots and improves scalability.&lt;/p&gt;

&lt;p&gt;However, hash-based sharding introduces a new problem.&lt;/p&gt;

&lt;p&gt;Humans lose predictability.&lt;/p&gt;

&lt;p&gt;With range sharding, engineers immediately know where a user lives.&lt;/p&gt;

&lt;p&gt;With hash sharding, finding the location of a record requires executing the hashing algorithm.&lt;/p&gt;

&lt;p&gt;The routing layer becomes mandatory.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem of Growth
&lt;/h2&gt;

&lt;p&gt;Eventually, every successful system encounters another difficult question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What happens when four shards are no longer enough?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The obvious answer seems simple:&lt;/p&gt;

&lt;p&gt;Add a fifth shard.&lt;/p&gt;

&lt;p&gt;Unfortunately, hash-based systems make this surprisingly painful.&lt;/p&gt;

&lt;p&gt;Consider the following example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;hash(user_id) % 4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now suppose we add a fifth shard:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;hash(user_id) % 5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Suddenly, almost every user maps to a different shard than before.&lt;/p&gt;

&lt;p&gt;Data that previously belonged to shard one may now belong to shard three.&lt;/p&gt;

&lt;p&gt;Data from shard three may move to shard five.&lt;/p&gt;

&lt;p&gt;A huge percentage of the database needs to be migrated.&lt;/p&gt;

&lt;p&gt;For systems containing billions of records, this migration can become extraordinarily expensive and risky.&lt;/p&gt;

&lt;p&gt;This challenge led to one of the most elegant ideas in distributed systems.&lt;/p&gt;

&lt;h2&gt;
  
  
  Consistent Hashing
&lt;/h2&gt;

&lt;p&gt;Consistent hashing was developed specifically to minimise data movement when infrastructure changes.&lt;/p&gt;

&lt;p&gt;Instead of mapping data directly to servers, both servers and data are placed on a logical ring.&lt;/p&gt;

&lt;p&gt;Each piece of data is assigned to the next available server in the ring.&lt;/p&gt;

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

&lt;p&gt;Now imagine adding a new server.&lt;/p&gt;

&lt;p&gt;Instead of redistributing the entire dataset, only a small portion of the data moves to the new machine.&lt;/p&gt;

&lt;p&gt;Most records remain exactly where they were.&lt;/p&gt;

&lt;p&gt;This dramatically reduces migration costs and makes scaling much safer.&lt;/p&gt;

&lt;p&gt;Consistent hashing is widely used in distributed systems because infrastructure growth becomes a normal operational activity rather than a major migration project.&lt;/p&gt;

&lt;p&gt;Systems such as distributed caches, distributed databases, and object storage platforms frequently rely on this technique.&lt;/p&gt;

&lt;h2&gt;
  
  
  Choosing the Right Shard Key
&lt;/h2&gt;

&lt;p&gt;Interestingly, one of the most important decisions in sharding is often overlooked:&lt;/p&gt;

&lt;p&gt;choosing the shard key.&lt;/p&gt;

&lt;p&gt;The shard key is the attribute used to determine where data lives.&lt;/p&gt;

&lt;p&gt;Examples include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;User ID&lt;/li&gt;
&lt;li&gt;Customer ID&lt;/li&gt;
&lt;li&gt;Geographic region&lt;/li&gt;
&lt;li&gt;Product category&lt;/li&gt;
&lt;li&gt;Organisation ID&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Choosing the wrong shard key can create a severe imbalance in the system.&lt;/p&gt;

&lt;p&gt;Suppose a ride-sharing platform partitions data by city.&lt;/p&gt;

&lt;p&gt;This may work well initially.&lt;/p&gt;

&lt;p&gt;But if one city suddenly becomes ten times larger than every other city, that shard becomes a permanent hotspot.&lt;/p&gt;

&lt;p&gt;Similarly, partitioning social media users by country may appear reasonable until a handful of countries dominate global traffic.&lt;/p&gt;

&lt;p&gt;A good shard key distributes data evenly while still allowing efficient queries.&lt;/p&gt;

&lt;p&gt;Finding that balance is often one of the hardest design decisions in large systems.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Cross-Shard Queries Become Expensive
&lt;/h2&gt;

&lt;p&gt;In a traditional database, a query can freely join tables because all the data lives on the same machine.&lt;/p&gt;

&lt;p&gt;Sharding changes this assumption.&lt;/p&gt;

&lt;p&gt;Imagine a query asking for information that spans multiple shards.&lt;/p&gt;

&lt;p&gt;The database can no longer answer the question locally.&lt;/p&gt;

&lt;p&gt;Instead, the system must:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Send requests to multiple shards.&lt;/li&gt;
&lt;li&gt;Wait for responses from each server.&lt;/li&gt;
&lt;li&gt;Merge the results.&lt;/li&gt;
&lt;li&gt;Return the final response.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;A query that once required a single machine now becomes a distributed operation involving network communication and coordination.&lt;/p&gt;

&lt;p&gt;This is why sharding often forces teams to rethink their data models and access patterns.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Reality of Modern Systems
&lt;/h2&gt;

&lt;p&gt;The truth is that most large internet companies use a combination of techniques rather than relying on a single strategy.&lt;/p&gt;

&lt;p&gt;Sharding is combined with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Replication for availability.&lt;/li&gt;
&lt;li&gt;Caching for performance.&lt;/li&gt;
&lt;li&gt;Load balancing for traffic distribution.&lt;/li&gt;
&lt;li&gt;CDNs for global content delivery.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Modern distributed systems are rarely built from one idea alone.&lt;/p&gt;

&lt;p&gt;They are ecosystems of complementary techniques working together.&lt;/p&gt;

&lt;p&gt;A shard may contain replicas.&lt;/p&gt;

&lt;p&gt;Those replicas may sit behind load balancers.&lt;/p&gt;

&lt;p&gt;Frequently accessed data may never reach the database at all because it is served from a cache.&lt;/p&gt;

&lt;p&gt;This layered architecture is what allows modern systems to operate at a global scale.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Sharding is often introduced as a database optimisation technique.&lt;/p&gt;

&lt;p&gt;In reality, it is much more than that.&lt;/p&gt;

&lt;p&gt;It represents the moment when data itself becomes distributed.&lt;/p&gt;

&lt;p&gt;And once data becomes distributed, the system enters an entirely new world of trade-offs involving routing, coordination, consistency, and fault tolerance.&lt;/p&gt;

&lt;p&gt;Scaling application servers is relatively straightforward.&lt;/p&gt;

&lt;p&gt;Scaling data is where distributed systems become truly interesting.&lt;/p&gt;

&lt;p&gt;Because at the internet scale, the challenge is no longer simply storing information.&lt;/p&gt;

&lt;p&gt;The challenge is knowing where that information lives, how to find it quickly, and how to keep the entire system functioning while millions of users are trying to access it simultaneously.&lt;/p&gt;

</description>
      <category>systemdesign</category>
      <category>architecture</category>
      <category>programming</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Databases in System Design - SQL vs NoSQL (When and Why)</title>
      <dc:creator>Sushant Gaurav</dc:creator>
      <pubDate>Tue, 30 Jun 2026 05:41:00 +0000</pubDate>
      <link>https://dev.to/imsushant12/databases-in-system-design-sql-vs-nosql-when-and-why-3lf4</link>
      <guid>https://dev.to/imsushant12/databases-in-system-design-sql-vs-nosql-when-and-why-3lf4</guid>
      <description>&lt;p&gt;Every system, no matter how simple or complex, eventually converges to a single fundamental need: it must remember things.&lt;/p&gt;

&lt;p&gt;Users sign up, data gets generated, transactions happen, content is created, relationships form, and all of this needs to be stored, retrieved, and updated reliably. At a small scale, this seems trivial. You pick a database, store your data, and move on.&lt;/p&gt;

&lt;p&gt;But as systems grow, data stops being passive.&lt;/p&gt;

&lt;p&gt;It becomes the &lt;strong&gt;centre of gravity&lt;/strong&gt; around which everything else revolves.&lt;/p&gt;

&lt;p&gt;Performance depends on it. Scalability depends on it. Consistency, availability, and even user experience are shaped by how data is stored and accessed.&lt;/p&gt;

&lt;p&gt;And this is where one of the most important decisions in system design emerges:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Should you use a relational database (SQL), or a non-relational database (NoSQL)?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;At first glance, this appears to be a technology choice. But in reality, it is a &lt;strong&gt;design philosophy decision&lt;/strong&gt;; one that reflects how your system models the world.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Structured World of SQL
&lt;/h2&gt;

&lt;p&gt;Relational databases, often referred to as SQL databases, are built on a simple but powerful idea: data should be organised into structured tables with clearly defined relationships.&lt;/p&gt;

&lt;p&gt;This model has been around for decades and is grounded in mathematical principles. Each piece of data fits into a predefined schema. Tables are connected through relationships, and queries allow you to retrieve and combine data in flexible ways.&lt;/p&gt;

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

&lt;p&gt;This structure brings clarity.&lt;/p&gt;

&lt;p&gt;When you design a relational schema, you are effectively defining the shape of your data upfront. You decide:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What entities exist&lt;/li&gt;
&lt;li&gt;What attributes do they have&lt;/li&gt;
&lt;li&gt;How they relate to each other&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once defined, this structure is enforced strictly. Every piece of data must conform to it.&lt;/p&gt;

&lt;p&gt;This may feel restrictive at first, but it provides a powerful guarantee:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The data in the system is consistent, predictable, and reliable.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is why relational databases are widely used in systems where correctness is critical. Financial systems, transactional platforms, and enterprise applications rely on the guarantees provided by SQL databases to maintain integrity.&lt;/p&gt;

&lt;p&gt;For example, systems within companies like Oracle and Microsoft have long relied on relational databases to manage structured, high-integrity data.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Power of Relationships
&lt;/h2&gt;

&lt;p&gt;One of the defining strengths of SQL databases is their ability to model relationships between data.&lt;/p&gt;

&lt;p&gt;Consider a simple scenario:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A user places an order&lt;/li&gt;
&lt;li&gt;An order contains multiple items&lt;/li&gt;
&lt;li&gt;Each item belongs to a product&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In a relational database, these relationships are explicitly defined. You can join tables together and retrieve complex, interconnected data with a single query.&lt;/p&gt;

&lt;p&gt;This ability to perform joins allows systems to answer rich questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What products has a user purchased?&lt;/li&gt;
&lt;li&gt;Which items are most frequently bought together?&lt;/li&gt;
&lt;li&gt;What is the total value of all orders in a given time period?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This expressiveness is one of the reasons SQL remains dominant in many domains.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Consistency
&lt;/h2&gt;

&lt;p&gt;Relational databases are designed with strong consistency in mind.&lt;/p&gt;

&lt;p&gt;They follow properties often referred to as ACID:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Atomicity&lt;/li&gt;
&lt;li&gt;Consistency&lt;/li&gt;
&lt;li&gt;Isolation&lt;/li&gt;
&lt;li&gt;Durability&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While these terms may sound theoretical, their impact is very real.&lt;/p&gt;

&lt;p&gt;They ensure that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Transactions either complete fully or not at all&lt;/li&gt;
&lt;li&gt;The database remains in a valid state&lt;/li&gt;
&lt;li&gt;Concurrent operations do not interfere in harmful ways&lt;/li&gt;
&lt;li&gt;Data is not lost, even in the event of failure&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This makes SQL databases particularly well-suited for systems where correctness cannot be compromised.&lt;/p&gt;

&lt;p&gt;Think of banking systems. If money is deducted from one account but not credited to another due to a failure, the system becomes unreliable. SQL databases are designed to prevent such scenarios.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Limits Begin to Appear
&lt;/h2&gt;

&lt;p&gt;Despite their strengths, relational databases begin to show limitations as systems scale.&lt;/p&gt;

&lt;p&gt;The first challenge is scalability.&lt;/p&gt;

&lt;p&gt;SQL databases are traditionally designed to scale vertically. You increase the power of a single machine to handle more load. But as we explored earlier, vertical scaling has limits, both in terms of hardware and cost.&lt;/p&gt;

&lt;p&gt;The second challenge is flexibility.&lt;/p&gt;

&lt;p&gt;Because the schema is predefined, making changes to the structure of data can be complex. Adding new fields, modifying relationships, or evolving the data model often requires careful migrations.&lt;/p&gt;

&lt;p&gt;In rapidly evolving systems, this rigidity can slow down development.&lt;/p&gt;

&lt;p&gt;The third challenge is distribution.&lt;/p&gt;

&lt;p&gt;Distributing relational databases across multiple nodes while maintaining strong consistency is difficult. It introduces coordination overhead, which can impact performance and availability.&lt;/p&gt;

&lt;p&gt;These challenges do not make SQL obsolete, but they create space for a different approach.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Enter NoSQL - A Different Philosophy
&lt;/h2&gt;

&lt;p&gt;NoSQL databases emerged not as a replacement for SQL, but as a response to the challenges of scale, flexibility, and distribution.&lt;/p&gt;

&lt;p&gt;Instead of enforcing a rigid schema, NoSQL systems embrace a more flexible approach to data modelling.&lt;/p&gt;

&lt;p&gt;Data is often stored in formats that closely resemble how it is used in applications:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Documents&lt;/li&gt;
&lt;li&gt;Key-value pairs&lt;/li&gt;
&lt;li&gt;Wide-column structures&lt;/li&gt;
&lt;li&gt;Graphs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This flexibility allows developers to evolve data models quickly without being constrained by predefined schemas.&lt;/p&gt;

&lt;p&gt;But more importantly, NoSQL databases are designed with &lt;strong&gt;distribution as a first principle&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;From the ground up, they assume:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Data will be spread across multiple machines&lt;/li&gt;
&lt;li&gt;Systems will operate across regions&lt;/li&gt;
&lt;li&gt;Failures will occur&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This makes them naturally suited for horizontally scaled systems.&lt;/p&gt;

&lt;p&gt;Companies like Amazon and Netflix have leveraged NoSQL databases to handle massive amounts of distributed data with high availability.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  A Shift in Trade-offs
&lt;/h2&gt;

&lt;p&gt;With NoSQL, the trade-offs begin to shift.&lt;/p&gt;

&lt;p&gt;Instead of strict consistency, many NoSQL systems embrace eventual consistency.&lt;/p&gt;

&lt;p&gt;Instead of rigid schemas, they offer flexibility.&lt;/p&gt;

&lt;p&gt;Instead of centralised control, they enable distributed scalability.&lt;/p&gt;

&lt;p&gt;But these benefits come at a cost:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;More responsibility on the application to manage data integrity&lt;/li&gt;
&lt;li&gt;Reduced ability to perform complex joins&lt;/li&gt;
&lt;li&gt;Increased complexity in ensuring consistency when needed&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is not a drawback; it is a design choice.&lt;/p&gt;

&lt;p&gt;And understanding this shift is key to choosing the right database.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where This Is Heading
&lt;/h2&gt;

&lt;p&gt;At this point, we have two distinct worlds:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SQL: structured, consistent, relationship-driven&lt;/li&gt;
&lt;li&gt;NoSQL: flexible, scalable, distribution-friendly&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But the real question is not which one is better.&lt;/p&gt;

&lt;p&gt;It is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;When should you use each?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is where database selection moves from theory to &lt;strong&gt;system design strategy&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Many Faces of NoSQL
&lt;/h2&gt;

&lt;p&gt;When people say NoSQL, they often imagine a single alternative to relational databases. In reality, NoSQL databases vary significantly in how they store and retrieve data.&lt;/p&gt;

&lt;p&gt;Each type exists because different applications have different needs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Document Databases - Modelling Data as It Is Used
&lt;/h3&gt;

&lt;p&gt;Document databases store data in a format similar to JSON. Instead of splitting data across multiple tables, related information is often stored together in a single document.&lt;/p&gt;

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

&lt;p&gt;This structure mirrors how applications actually consume data.&lt;/p&gt;

&lt;p&gt;Instead of performing multiple joins to assemble related information, everything is already grouped together. This reduces query complexity and improves performance for read-heavy workloads.&lt;/p&gt;

&lt;p&gt;This model is widely used in systems where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Data structures evolve frequently&lt;/li&gt;
&lt;li&gt;Relationships are hierarchical&lt;/li&gt;
&lt;li&gt;Fast reads are more important than complex joins&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Key-Value Stores
&lt;/h3&gt;

&lt;p&gt;Key-value databases are the simplest form of NoSQL.&lt;/p&gt;

&lt;p&gt;Data is stored as a collection of key-value pairs. You provide a key, and the system returns the associated value.&lt;/p&gt;

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

&lt;p&gt;This simplicity allows for extremely fast lookups and high scalability.&lt;/p&gt;

&lt;p&gt;However, it comes with limitations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No support for complex queries&lt;/li&gt;
&lt;li&gt;No inherent relationships between data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These databases are often used for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Caching layers&lt;/li&gt;
&lt;li&gt;Session storage&lt;/li&gt;
&lt;li&gt;Simple lookup services&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Wide-Column Databases
&lt;/h3&gt;

&lt;p&gt;Wide-column databases organise data into rows and columns, but unlike SQL, each row can have a different set of columns.&lt;/p&gt;

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

&lt;p&gt;This flexibility allows systems to handle large-scale, sparse datasets efficiently.&lt;/p&gt;

&lt;p&gt;These databases are designed for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;High write throughput&lt;/li&gt;
&lt;li&gt;Distributed storage across many nodes&lt;/li&gt;
&lt;li&gt;Analytical workloads at scale&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Graph Databases
&lt;/h3&gt;

&lt;p&gt;While SQL can model relationships, graph databases treat them as the core of the system.&lt;/p&gt;

&lt;p&gt;Data is stored as nodes and edges, making it ideal for highly connected data.&lt;/p&gt;

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

&lt;p&gt;This model excels in scenarios where relationships are complex and deeply interconnected, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Social networks&lt;/li&gt;
&lt;li&gt;Recommendation systems&lt;/li&gt;
&lt;li&gt;Fraud detection&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Where SQL Still Shines
&lt;/h2&gt;

&lt;p&gt;Despite the rise of NoSQL, relational databases remain dominant in many critical systems.&lt;/p&gt;

&lt;p&gt;This is not by accident.&lt;/p&gt;

&lt;p&gt;SQL databases are still the best choice when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Data relationships are complex and require joins&lt;/li&gt;
&lt;li&gt;Transactions must be strongly consistent&lt;/li&gt;
&lt;li&gt;Data integrity is critical&lt;/li&gt;
&lt;li&gt;The schema is stable and well-defined&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, financial systems and transactional platforms within companies like Microsoft continue to rely heavily on relational databases.&lt;/p&gt;

&lt;p&gt;Because in these systems, correctness is not negotiable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where NoSQL Excels
&lt;/h2&gt;

&lt;p&gt;NoSQL systems shine in environments where scale and flexibility are more important than strict consistency.&lt;/p&gt;

&lt;p&gt;They are particularly effective when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The system needs to scale horizontally&lt;/li&gt;
&lt;li&gt;Data models change frequently&lt;/li&gt;
&lt;li&gt;High availability is required&lt;/li&gt;
&lt;li&gt;Workloads are distributed globally&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Platforms like Netflix use NoSQL databases to handle massive volumes of user activity, content metadata, and streaming data.&lt;/p&gt;

&lt;p&gt;In such systems, slight inconsistencies are acceptable if they enable better performance and availability.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Hybrid Reality
&lt;/h2&gt;

&lt;p&gt;At this point, it might seem like you must choose one approach over the other.&lt;/p&gt;

&lt;p&gt;But in modern system design, that is rarely the case.&lt;/p&gt;

&lt;p&gt;Most large-scale systems use a &lt;strong&gt;combination of SQL and NoSQL databases&lt;/strong&gt;, depending on the requirements of each component.&lt;/p&gt;

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

&lt;p&gt;For example, a system might:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use SQL for payments and transactions&lt;/li&gt;
&lt;li&gt;Use NoSQL for user activity and analytics&lt;/li&gt;
&lt;li&gt;Use caching for performance&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This approach allows systems to utilise the strengths of each model while minimising their weaknesses.&lt;/p&gt;

&lt;p&gt;Companies like Amazon follow this strategy extensively, using different databases for different parts of their architecture.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Real Decision Framework
&lt;/h2&gt;

&lt;p&gt;Choosing between SQL and NoSQL is not about trends or popularity.&lt;/p&gt;

&lt;p&gt;It comes down to understanding your system’s priorities.&lt;/p&gt;

&lt;p&gt;Ask yourself:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Do I need strict consistency or can I tolerate eventual consistency?&lt;/li&gt;
&lt;li&gt;Is my data highly structured or flexible?&lt;/li&gt;
&lt;li&gt;Will my system scale vertically or horizontally?&lt;/li&gt;
&lt;li&gt;Are relationships central to my queries?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These questions guide the decision more than any feature comparison ever could.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thought
&lt;/h2&gt;

&lt;p&gt;Databases are not just storage systems.&lt;/p&gt;

&lt;p&gt;They define how your system thinks about data, how it evolves, and how it scales.&lt;/p&gt;

&lt;p&gt;Choosing the right database is not about picking the most powerful tool:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It is about choosing the tool that aligns with your system’s reality.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Because in system design, the best solutions are not the most sophisticated ones.&lt;/p&gt;

&lt;p&gt;They are the ones that fit the problem.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Caching in System Design - The Secret to High Performance</title>
      <dc:creator>Sushant Gaurav</dc:creator>
      <pubDate>Tue, 16 Jun 2026 05:41:00 +0000</pubDate>
      <link>https://dev.to/imsushant12/caching-in-system-design-the-secret-to-high-performance-1pj1</link>
      <guid>https://dev.to/imsushant12/caching-in-system-design-the-secret-to-high-performance-1pj1</guid>
      <description>&lt;p&gt;There is a point in every system’s growth where adding more servers stops being enough.&lt;/p&gt;

&lt;p&gt;You scale horizontally. You introduce load balancers. You distribute traffic efficiently. And yet, something still feels off.&lt;/p&gt;

&lt;p&gt;Requests are slower than expected. Databases are under constant pressure. Systems that should scale effortlessly begin to struggle under repeated work.&lt;/p&gt;

&lt;p&gt;And then you realise something fundamental:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The system is doing the same work again and again.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The same queries.&lt;br&gt;
The same computations.&lt;br&gt;
The same responses.&lt;/p&gt;

&lt;p&gt;Over and over.&lt;/p&gt;

&lt;p&gt;This is not a scaling problem.&lt;/p&gt;

&lt;p&gt;It is a &lt;strong&gt;redundancy problem&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;And the solution to this problem is one of the most powerful ideas in system design:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Caching&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What Is Caching, Really?
&lt;/h2&gt;

&lt;p&gt;At a surface level, caching is often defined as storing frequently accessed data in a faster storage layer so it can be retrieved quickly.&lt;/p&gt;

&lt;p&gt;But this definition, while correct, does not capture its true significance.&lt;/p&gt;

&lt;p&gt;Caching is not just a performance optimisation.&lt;/p&gt;

&lt;p&gt;It is a &lt;strong&gt;shift in how systems think about work&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Instead of asking:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Can we compute this quickly?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Caching asks:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Do we need to compute this at all?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That shift from computation to reuse is what makes caching so powerful.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Cost of Repeated Work
&lt;/h2&gt;

&lt;p&gt;To understand why caching matters, we need to look at what happens without it.&lt;/p&gt;

&lt;p&gt;Imagine a system where every user request requires:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fetching data from a database&lt;/li&gt;
&lt;li&gt;Performing business logic&lt;/li&gt;
&lt;li&gt;Formatting a response&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This process may take only a few milliseconds per request. But at scale, those milliseconds add up.&lt;/p&gt;

&lt;p&gt;When thousands or millions of users request the same data, the system is forced to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Execute identical database queries repeatedly&lt;/li&gt;
&lt;li&gt;Perform the same computations&lt;/li&gt;
&lt;li&gt;Generate the same responses&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This creates unnecessary load on the system, especially on components like databases, which are often the most expensive and limited resources.&lt;/p&gt;

&lt;p&gt;Over time, this repeated work becomes the bottleneck.&lt;/p&gt;

&lt;p&gt;Caching addresses this by &lt;strong&gt;eliminating redundant effort&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Core Idea - Store Once, Serve Many
&lt;/h2&gt;

&lt;p&gt;At its heart, caching is simple.&lt;/p&gt;

&lt;p&gt;When a request is processed, instead of discarding the result, the system stores it in a cache. The next time the same request arrives, the system can return the cached result instead of recomputing it.&lt;/p&gt;

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

&lt;p&gt;This introduces two fundamental concepts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cache Hit&lt;/strong&gt; - The data is found in the cache and returned immediately&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cache Miss&lt;/strong&gt; - The data is not in the cache, so it must be computed and then stored&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The effectiveness of a caching system is often measured by its &lt;strong&gt;cache hit rate&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Higher hit rate → fewer expensive operations → better performance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Caching Changes Everything
&lt;/h2&gt;

&lt;p&gt;Caching has a profound impact on system behaviour.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reduced Latency
&lt;/h3&gt;

&lt;p&gt;Fetching data from memory is significantly faster than querying a database or calling an external service.&lt;/p&gt;

&lt;h3&gt;
  
  
  Increased Throughput
&lt;/h3&gt;

&lt;p&gt;By reducing the load on core systems, caching allows more requests to be handled simultaneously.&lt;/p&gt;

&lt;h3&gt;
  
  
  Lower System Load
&lt;/h3&gt;

&lt;p&gt;Databases, APIs, and backend services experience less pressure, improving overall system stability.&lt;/p&gt;

&lt;h3&gt;
  
  
  Better Scalability
&lt;/h3&gt;

&lt;p&gt;Systems can handle larger traffic without proportionally increasing infrastructure.&lt;/p&gt;

&lt;p&gt;This is why caching is used extensively in large-scale systems.&lt;/p&gt;

&lt;p&gt;Platforms like Netflix and Google rely heavily on caching at multiple layers to serve massive amounts of data efficiently.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where Does the Cache Live?
&lt;/h2&gt;

&lt;p&gt;One of the most important design decisions in caching is &lt;strong&gt;where to place the cache&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Because caching is not a single layer, it can exist at multiple points in the system.&lt;/p&gt;

&lt;h3&gt;
  
  
  Application-Level Cache
&lt;/h3&gt;

&lt;p&gt;The simplest form of caching happens within the application itself.&lt;/p&gt;

&lt;p&gt;Data is stored in memory inside the server process.&lt;/p&gt;

&lt;p&gt;This is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Extremely fast&lt;/li&gt;
&lt;li&gt;Easy to implement&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But it has limitations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Not shared across servers&lt;/li&gt;
&lt;li&gt;Lost when the server restarts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This works well for small-scale systems or single-node setups.&lt;/p&gt;

&lt;h3&gt;
  
  
  Distributed Cache
&lt;/h3&gt;

&lt;p&gt;As systems scale horizontally, caching must also scale.&lt;/p&gt;

&lt;p&gt;Instead of storing cache locally, systems use distributed caching systems that are shared across multiple servers.&lt;/p&gt;

&lt;p&gt;This allows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Consistent access to cached data&lt;/li&gt;
&lt;li&gt;Better cache utilisation&lt;/li&gt;
&lt;li&gt;Scalability across nodes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However, it introduces:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Network overhead&lt;/li&gt;
&lt;li&gt;Cache synchronisation challenges&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Edge Cache (CDN)
&lt;/h3&gt;

&lt;p&gt;At the highest level, caching can move closer to the user.&lt;/p&gt;

&lt;p&gt;Content Delivery Networks (CDNs) store cached data in geographically distributed locations.&lt;/p&gt;

&lt;p&gt;When a user requests content, it is served from the nearest location rather than the origin server.&lt;/p&gt;

&lt;p&gt;This drastically reduces latency and server load.&lt;/p&gt;

&lt;p&gt;This is how platforms like Amazon and Netflix deliver content globally with high performance.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Trade-off Begins
&lt;/h2&gt;

&lt;p&gt;At this point, caching may seem like a perfect solution.&lt;/p&gt;

&lt;p&gt;Faster responses.&lt;br&gt;
Lower load.&lt;br&gt;
Better scalability.&lt;/p&gt;

&lt;p&gt;So why not cache everything?&lt;/p&gt;

&lt;p&gt;Because caching introduces a new and unavoidable challenge:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Data can become stale&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When the underlying data changes, cached data may no longer be accurate.&lt;/p&gt;

&lt;p&gt;And this leads us to one of the hardest problems in system design:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Cache invalidation&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But as systems grow, a deeper and more uncomfortable truth begins to emerge:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Caching is easy to add… but very hard to get right&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Because the moment you introduce a cache, you are no longer just optimising performance, you are managing &lt;strong&gt;two versions of reality&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The source of truth (database)&lt;/li&gt;
&lt;li&gt;The cached copy (fast, but potentially outdated)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And keeping these two in sync is where the real challenge begins.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cache Invalidation - The Hardest Problem
&lt;/h2&gt;

&lt;p&gt;There’s a well-known saying in system design:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;There are only two hard things in Computer Science: cache invalidation and naming things.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It sounds like a joke, but it isn’t.&lt;/p&gt;

&lt;p&gt;Cache invalidation is the process of ensuring that cached data remains accurate when the underlying data changes.&lt;/p&gt;

&lt;p&gt;Let’s say a product’s price changes in the database. If the old price is still stored in the cache, users may see outdated information.&lt;/p&gt;

&lt;p&gt;So the system must decide:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When should the cache be updated?&lt;/li&gt;
&lt;li&gt;Should it be updated immediately or later?&lt;/li&gt;
&lt;li&gt;Should it be removed entirely?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each choice comes with trade-offs between &lt;strong&gt;consistency, performance, and complexity&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Approaches to Cache Invalidation
&lt;/h2&gt;

&lt;p&gt;There is no single correct way to handle cache invalidation. Instead, systems use different strategies depending on their requirements.&lt;/p&gt;

&lt;h3&gt;
  
  
  Time-Based Expiration (TTL)
&lt;/h3&gt;

&lt;p&gt;One of the simplest approaches is to assign a &lt;strong&gt;time-to-live (TTL)&lt;/strong&gt; to cached data.&lt;/p&gt;

&lt;p&gt;After a fixed duration, the cache entry expires and is removed.&lt;/p&gt;

&lt;p&gt;This approach is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Easy to implement&lt;/li&gt;
&lt;li&gt;Predictable&lt;/li&gt;
&lt;li&gt;Widely used&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But it has limitations.&lt;/p&gt;

&lt;p&gt;If the TTL is too long:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Data may remain stale for too long&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the TTL is too short:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cache effectiveness decreases (more misses)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So choosing the right TTL becomes a balancing act.&lt;/p&gt;

&lt;h3&gt;
  
  
  Write-Based Invalidation
&lt;/h3&gt;

&lt;p&gt;Another approach is to update or invalidate the cache &lt;strong&gt;whenever data changes&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When a product is updated → update or delete its cache entry&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This ensures better consistency, but introduces complexity:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Every write operation must handle cache updates&lt;/li&gt;
&lt;li&gt;Failures in cache updates can lead to inconsistencies&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This approach works well when accuracy is critical.&lt;/p&gt;

&lt;h3&gt;
  
  
  Explicit Invalidation
&lt;/h3&gt;

&lt;p&gt;Sometimes, systems explicitly remove cache entries when they know data has changed.&lt;/p&gt;

&lt;p&gt;Instead of updating the cache, they simply delete it, forcing the next request to fetch fresh data.&lt;/p&gt;

&lt;p&gt;This is simple and safe, but may temporarily increase load due to cache misses.&lt;/p&gt;

&lt;h2&gt;
  
  
  Caching Strategies - When to Read and Write
&lt;/h2&gt;

&lt;p&gt;Beyond invalidation, another important question is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;When should the system interact with the cache?&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This leads to different caching strategies.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cache-Aside (Lazy Loading)
&lt;/h3&gt;

&lt;p&gt;This is the most commonly used strategy.&lt;/p&gt;

&lt;p&gt;When a request arrives:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Check the cache&lt;/li&gt;
&lt;li&gt;If data exists → return it (cache hit)&lt;/li&gt;
&lt;li&gt;If not → fetch from database, store in cache, then return&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;This approach is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Simple&lt;/li&gt;
&lt;li&gt;Flexible&lt;/li&gt;
&lt;li&gt;Widely adopted&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But it can lead to stale data if not invalidated properly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Write-Through Cache
&lt;/h3&gt;

&lt;p&gt;In this strategy, data is written to both:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cache&lt;/li&gt;
&lt;li&gt;Database&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;simultaneously.&lt;/p&gt;

&lt;p&gt;This ensures that the cache is always up-to-date.&lt;/p&gt;

&lt;p&gt;However:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Writing becomes slower&lt;/li&gt;
&lt;li&gt;More coordination is required&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Write-Back (Write-Behind)
&lt;/h3&gt;

&lt;p&gt;Here, data is first written to the cache, and the database is updated later.&lt;/p&gt;

&lt;p&gt;This improves write performance but introduces risk:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If the cache fails before writing to the database, data may be lost&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This strategy is used when performance is prioritised over immediate consistency.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cache Eviction - Making Space for New Data
&lt;/h2&gt;

&lt;p&gt;Caches are not infinite.&lt;/p&gt;

&lt;p&gt;At some point, they run out of space.&lt;/p&gt;

&lt;p&gt;So the system must decide:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Which data should be removed to make room for new data&lt;/em&gt;?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is handled through &lt;strong&gt;eviction policies&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  LRU (Least Recently Used)
&lt;/h3&gt;

&lt;p&gt;Removes data that has not been accessed recently.&lt;/p&gt;

&lt;p&gt;This works well because frequently accessed data tends to remain in the cache.&lt;/p&gt;

&lt;h3&gt;
  
  
  LFU (Least Frequently Used)
&lt;/h3&gt;

&lt;p&gt;Removes data that is accessed the least often.&lt;/p&gt;

&lt;p&gt;This is useful when certain data is consistently popular.&lt;/p&gt;

&lt;h3&gt;
  
  
  TTL-Based Eviction
&lt;/h3&gt;

&lt;p&gt;Data is removed after a fixed time, regardless of usage.&lt;/p&gt;

&lt;p&gt;Each policy reflects a different assumption about how users interact with data.&lt;/p&gt;

&lt;p&gt;Choosing the right one depends on your access patterns.&lt;/p&gt;

&lt;h2&gt;
  
  
  When Caching Goes Wrong
&lt;/h2&gt;

&lt;p&gt;Caching is powerful, but when misused, it can create serious problems.&lt;/p&gt;

&lt;h3&gt;
  
  
  Stale Data Issues
&lt;/h3&gt;

&lt;p&gt;Users see outdated information, leading to inconsistencies.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cache Stampede
&lt;/h3&gt;

&lt;p&gt;When a popular cache entry expires, many requests hit the database simultaneously, overwhelming it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Increased Complexity
&lt;/h3&gt;

&lt;p&gt;Managing cache logic, invalidation, and consistency adds significant engineering overhead.&lt;/p&gt;

&lt;h3&gt;
  
  
  Hidden Bugs
&lt;/h3&gt;

&lt;p&gt;Caching can mask underlying issues, making debugging harder.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Deeper Insight
&lt;/h2&gt;

&lt;p&gt;At this point, caching should no longer feel like a simple optimisation.&lt;/p&gt;

&lt;p&gt;It is a &lt;strong&gt;trade-off system&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;You trade:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Freshness for speed&lt;/li&gt;
&lt;li&gt;Simplicity for performance&lt;/li&gt;
&lt;li&gt;Consistency for scalability&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And like everything in system design, there is no perfect choice.&lt;/p&gt;

&lt;p&gt;Only the choice that best fits your requirements.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thought
&lt;/h2&gt;

&lt;p&gt;The most important thing to understand about caching is this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Caching does not make your system faster; it makes your system do less work&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And at scale, doing less work is the only way to survive.&lt;/p&gt;

&lt;p&gt;Because the systems that scale are not the ones that compute faster:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;They are the ones that avoid unnecessary computation altogether.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>systemdesign</category>
      <category>programming</category>
      <category>architecture</category>
      <category>software</category>
    </item>
    <item>
      <title>Load Balancing Explained - How Systems Handle Millions of Requests</title>
      <dc:creator>Sushant Gaurav</dc:creator>
      <pubDate>Tue, 02 Jun 2026 05:41:00 +0000</pubDate>
      <link>https://dev.to/imsushant12/load-balancing-explained-how-systems-handle-millions-of-requests-33hd</link>
      <guid>https://dev.to/imsushant12/load-balancing-explained-how-systems-handle-millions-of-requests-33hd</guid>
      <description>&lt;p&gt;There is a moment in the life of every growing system when a single server quietly becomes a bottleneck.&lt;/p&gt;

&lt;p&gt;At first, the system works exactly as expected. Users send requests, the server processes them, and responses are returned almost instantly. Everything feels smooth, predictable, and under control.&lt;/p&gt;

&lt;p&gt;But as usage grows, something subtle begins to change.&lt;/p&gt;

&lt;p&gt;Requests start arriving faster than they can be processed. The server becomes overloaded. Response times increase. Eventually, some requests begin to fail, not because the logic is incorrect, but because the system simply cannot keep up.&lt;/p&gt;

&lt;p&gt;This is not a bug.&lt;/p&gt;

&lt;p&gt;It is a limitation.&lt;/p&gt;

&lt;p&gt;And this is the moment when adding more servers becomes necessary.&lt;/p&gt;

&lt;p&gt;But adding more servers introduces a new challenge:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;How do you decide which server should handle which request?&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Because without coordination, adding more machines does not solve the problem; it just spreads the chaos.&lt;/p&gt;

&lt;p&gt;This is where load balancing enters the picture.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is Load Balancing, Really?
&lt;/h2&gt;

&lt;p&gt;At its core, load balancing is the process of &lt;strong&gt;distributing incoming requests across multiple servers&lt;/strong&gt; so that no single machine becomes overwhelmed.&lt;/p&gt;

&lt;p&gt;But that definition, while correct, does not capture the full picture.&lt;/p&gt;

&lt;p&gt;Load balancing is not just about distribution.&lt;/p&gt;

&lt;p&gt;It is about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Maximising resource utilisation&lt;/li&gt;
&lt;li&gt;Minimising response time&lt;/li&gt;
&lt;li&gt;Ensuring high availability&lt;/li&gt;
&lt;li&gt;Preventing system overload&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It acts as the invisible layer that allows systems to scale horizontally without collapsing under pressure.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Role of a Load Balancer
&lt;/h2&gt;

&lt;p&gt;A load balancer sits between users and your servers.&lt;/p&gt;

&lt;p&gt;Instead of users directly interacting with a specific machine, they send requests to the load balancer, which then decides where those requests should go.&lt;/p&gt;

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

&lt;p&gt;From the user’s perspective, the system still appears as a single entity.&lt;/p&gt;

&lt;p&gt;But behind the scenes, requests are being intelligently distributed across multiple machines.&lt;/p&gt;

&lt;p&gt;This abstraction is powerful.&lt;/p&gt;

&lt;p&gt;It allows you to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add or remove servers without affecting users&lt;/li&gt;
&lt;li&gt;Handle traffic spikes dynamically&lt;/li&gt;
&lt;li&gt;Improve fault tolerance&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But the real complexity lies in &lt;em&gt;how&lt;/em&gt; the load balancer makes decisions.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Simplest Approach - Equal Distribution
&lt;/h2&gt;

&lt;p&gt;The most intuitive way to distribute requests is to spread them evenly across all servers.&lt;/p&gt;

&lt;p&gt;Each incoming request is sent to the next server in line.&lt;/p&gt;

&lt;p&gt;This is known as &lt;strong&gt;round-robin distribution&lt;/strong&gt;.&lt;/p&gt;

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

&lt;p&gt;At first glance, this seems perfectly fair.&lt;/p&gt;

&lt;p&gt;Every server gets an equal share of requests.&lt;/p&gt;

&lt;p&gt;But real systems are rarely that simple.&lt;/p&gt;

&lt;p&gt;Because not all requests are equal.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem with Equal Distribution
&lt;/h2&gt;

&lt;p&gt;In practice, different requests require different amounts of work.&lt;/p&gt;

&lt;p&gt;Some requests might:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Query large datasets&lt;/li&gt;
&lt;li&gt;Perform complex computations&lt;/li&gt;
&lt;li&gt;Call multiple downstream services&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While others may be simple and lightweight.&lt;/p&gt;

&lt;p&gt;If all requests are distributed equally without considering their complexity, some servers may become overloaded while others remain underutilised.&lt;/p&gt;

&lt;p&gt;This is where more intelligent load-balancing strategies come into play.&lt;/p&gt;

&lt;h2&gt;
  
  
  Smarter Distribution - Load-Aware Routing
&lt;/h2&gt;

&lt;p&gt;Instead of blindly distributing requests, load balancers can make decisions based on the current state of each server.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Send requests to the server with the &lt;strong&gt;least number of active connections&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Route traffic to the server with the &lt;strong&gt;lowest response time&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Avoid servers that are showing signs of stress&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This allows the system to adapt dynamically to changing conditions.&lt;/p&gt;

&lt;p&gt;But this introduces a new requirement:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The load balancer must constantly monitor the health and performance of servers.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Health Checks - Knowing When a Server Is Failing
&lt;/h2&gt;

&lt;p&gt;One of the most critical responsibilities of a load balancer is detecting when a server is no longer able to handle requests.&lt;/p&gt;

&lt;p&gt;This is done through &lt;strong&gt;health checks&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The load balancer periodically sends requests to each server to verify:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Is the server responding?&lt;/li&gt;
&lt;li&gt;Is it responding within an acceptable time?&lt;/li&gt;
&lt;li&gt;Is it returning correct responses?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If a server fails these checks, it is temporarily removed from the pool.&lt;/p&gt;

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

&lt;p&gt;This ensures that user requests are only sent to healthy servers, improving reliability and user experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  Load Balancing and Availability
&lt;/h2&gt;

&lt;p&gt;Load balancing plays a crucial role in achieving high availability.&lt;/p&gt;

&lt;p&gt;Without it, even a horizontally scaled system can fail.&lt;/p&gt;

&lt;p&gt;Imagine having multiple servers, but users are directly connected to just one of them. If that server goes down, the system becomes unavailable, even though other servers are perfectly functional.&lt;/p&gt;

&lt;p&gt;A load balancer prevents this by acting as a &lt;strong&gt;single entry point&lt;/strong&gt;, ensuring that traffic is always routed to available resources.&lt;/p&gt;

&lt;p&gt;This is one of the reasons why large-scale systems, including those built by Netflix, rely heavily on load balancing at multiple layers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where This Is Heading
&lt;/h2&gt;

&lt;p&gt;So far, we’ve explored:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Why load balancing is necessary&lt;/li&gt;
&lt;li&gt;How it distributes traffic&lt;/li&gt;
&lt;li&gt;Why simple strategies are not enough&lt;/li&gt;
&lt;li&gt;How health checks ensure reliability&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But as systems grow more complex, the role of a load balancer expands beyond simple request routing.&lt;/p&gt;

&lt;p&gt;Because not all requests are the same.&lt;br&gt;
Not all servers behave the same.&lt;br&gt;
And not all failures look the same.&lt;/p&gt;

&lt;p&gt;To handle real-world traffic at scale, load balancing itself evolves into a &lt;strong&gt;multi-layered system with different levels of intelligence&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Layer 4 vs Layer 7 - Two Ways to Think About Traffic
&lt;/h2&gt;

&lt;p&gt;To understand modern load balancing, we need to look at the &lt;strong&gt;network stack&lt;/strong&gt;; specifically, how requests move through it.&lt;/p&gt;

&lt;p&gt;At a high level, load balancers operate at two common layers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Layer 4 (Transport Layer)&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Layer 7 (Application Layer)&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are not just technical distinctions; they define &lt;em&gt;how much the load balancer understands about the request&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Layer 4 Load Balancing - Fast and Blind
&lt;/h3&gt;

&lt;p&gt;A Layer 4 load balancer operates at the transport level (TCP/UDP). It does not inspect the content of the request. Instead, it makes decisions based on basic network information like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;IP address&lt;/li&gt;
&lt;li&gt;Port number&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;From its perspective, a request is just a stream of packets.&lt;/p&gt;

&lt;p&gt;This makes Layer 4 load balancing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Extremely fast&lt;/li&gt;
&lt;li&gt;Low overhead&lt;/li&gt;
&lt;li&gt;Highly efficient for raw traffic distribution&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But it also means it lacks context.&lt;/p&gt;

&lt;p&gt;It cannot differentiate between:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;/login&lt;/code&gt; vs &lt;code&gt;/checkout&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;API calls vs static content&lt;/li&gt;
&lt;li&gt;High-cost vs low-cost operations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It simply forwards traffic.&lt;/p&gt;

&lt;h3&gt;
  
  
  Layer 7 Load Balancing - Intelligent Routing
&lt;/h3&gt;

&lt;p&gt;Layer 7 load balancers operate at the application level (HTTP/HTTPS). They can inspect the actual content of the request:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;URL paths&lt;/li&gt;
&lt;li&gt;Headers&lt;/li&gt;
&lt;li&gt;Cookies&lt;/li&gt;
&lt;li&gt;Request types&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This allows for much smarter routing decisions.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Send &lt;code&gt;/images&lt;/code&gt; requests to a caching server&lt;/li&gt;
&lt;li&gt;Route &lt;code&gt;/api/payments&lt;/code&gt; to a specific service&lt;/li&gt;
&lt;li&gt;Direct mobile users to a different backend&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;This level of control is powerful, but it comes with trade-offs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Higher latency than Layer 4&lt;/li&gt;
&lt;li&gt;More computational overhead&lt;/li&gt;
&lt;li&gt;Increased complexity&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This leads to a common pattern in real systems:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Use Layer 4 for speed, Layer 7 for intelligence, often together.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Sticky Sessions - When State Gets in the Way
&lt;/h2&gt;

&lt;p&gt;Earlier, we discussed how scalable systems aim to be stateless. But in practice, not all systems achieve this immediately.&lt;/p&gt;

&lt;p&gt;Some applications rely on &lt;strong&gt;session state stored on individual servers&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This creates a problem.&lt;/p&gt;

&lt;p&gt;If a user’s first request goes to Server 1, and their session data is stored there, sending their next request to Server 3 may break the experience.&lt;/p&gt;

&lt;p&gt;To handle this, systems sometimes use &lt;strong&gt;sticky sessions&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Sticky sessions ensure that requests from the same user are always routed to the same server.&lt;/p&gt;

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

&lt;p&gt;While this solves the immediate problem, it introduces new challenges:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Uneven load distribution&lt;/li&gt;
&lt;li&gt;Reduced fault tolerance (if the server fails, the session is lost)&lt;/li&gt;
&lt;li&gt;Difficulty scaling dynamically&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is why modern systems try to avoid sticky sessions and instead externalise state into shared systems like distributed caches.&lt;/p&gt;

&lt;h2&gt;
  
  
  Global Load Balancing - Scaling Across Regions
&lt;/h2&gt;

&lt;p&gt;So far, we’ve discussed load balancing within a single region. But large-scale systems operate globally.&lt;/p&gt;

&lt;p&gt;Users from different parts of the world expect fast response times. Sending every request to a single data centre is not practical.&lt;/p&gt;

&lt;p&gt;This is where &lt;strong&gt;global load balancing&lt;/strong&gt; comes into play.&lt;/p&gt;

&lt;p&gt;Instead of routing traffic between servers, global load balancing routes traffic between &lt;strong&gt;regions&lt;/strong&gt;.&lt;/p&gt;

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

&lt;p&gt;The system decides:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which region is closest to the user&lt;/li&gt;
&lt;li&gt;Which region is currently healthy&lt;/li&gt;
&lt;li&gt;Which region has capacity&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This reduces latency and improves availability.&lt;/p&gt;

&lt;p&gt;If one region goes down, traffic can be redirected to another.&lt;/p&gt;

&lt;p&gt;This is how companies like Google and Amazon maintain global-scale systems that remain responsive even under failures.&lt;/p&gt;

&lt;h2&gt;
  
  
  Load Balancing Meets Caching and CDNs
&lt;/h2&gt;

&lt;p&gt;As systems scale further, load balancing does not operate in isolation.&lt;/p&gt;

&lt;p&gt;It works alongside:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Caching layers&lt;/li&gt;
&lt;li&gt;CDNs (Content Delivery Networks)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A CDN can serve requests directly from edge locations, reducing the load on origin servers.&lt;/p&gt;

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

&lt;p&gt;This introduces a powerful optimisation:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The best request is the one that never reaches your server.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;By serving content closer to users, CDNs reduce latency, decrease server load, and improve scalability.&lt;/p&gt;

&lt;p&gt;Load balancers then handle the remaining dynamic traffic efficiently.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Deeper Insight
&lt;/h2&gt;

&lt;p&gt;At this point, load balancing should no longer feel like a simple routing mechanism.&lt;/p&gt;

&lt;p&gt;It is a &lt;strong&gt;control system&lt;/strong&gt; that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Distributes load&lt;/li&gt;
&lt;li&gt;Detects failures&lt;/li&gt;
&lt;li&gt;Optimises performance&lt;/li&gt;
&lt;li&gt;Enables scalability&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And more importantly, it connects multiple system design concepts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Horizontal scaling&lt;/li&gt;
&lt;li&gt;Availability&lt;/li&gt;
&lt;li&gt;Latency optimization&lt;/li&gt;
&lt;li&gt;Fault tolerance&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is why load balancing is often one of the first components introduced when systems begin to scale.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thought
&lt;/h2&gt;

&lt;p&gt;When systems are small, you think in terms of servers.&lt;/p&gt;

&lt;p&gt;When systems grow, you think in terms of clusters.&lt;/p&gt;

&lt;p&gt;But when systems reach scale, you think in terms of &lt;strong&gt;traffic flow&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Where requests come from, how they move, and where they are handled become the defining factors of system performance and reliability.&lt;/p&gt;

&lt;p&gt;And at the centre of that flow is the load balancer.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Not just distributing requests, but shaping how the system behaves under pressure.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>systemdesign</category>
      <category>programming</category>
      <category>software</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Redis Essentials: Architecture, Caching, and Setup</title>
      <dc:creator>Sushant Gaurav</dc:creator>
      <pubDate>Tue, 26 May 2026 05:41:00 +0000</pubDate>
      <link>https://dev.to/imsushant12/redis-essentials-architecture-caching-and-setup-46eg</link>
      <guid>https://dev.to/imsushant12/redis-essentials-architecture-caching-and-setup-46eg</guid>
      <description>&lt;p&gt;Redis is often a misunderstood tool in the backend developer's arsenal. While many view it simply as a "topic" to be covered in an hour, its role in modern system design is pivotal for building high-performance, scalable applications. This article explores what Redis is, why it is used, and how to set it up locally for development.&lt;/p&gt;

&lt;h3&gt;
  
  
  Understanding Redis: The In-Memory Powerhouse
&lt;/h3&gt;

&lt;p&gt;At its core, &lt;strong&gt;Redis is an in-memory data store&lt;/strong&gt;, often referred to as a "lightning-fast" hash map or key-value store. Unlike traditional databases like MongoDB or PostgreSQL that primarily store data on a hard disk (SSD or HDD), Redis keeps its state in the &lt;strong&gt;RAM (Random Access Memory)&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Core Concept: The In-Memory Advantage
&lt;/h3&gt;

&lt;p&gt;The fundamental difference between Redis and traditional databases (like MongoDB or PostgreSQL) is where they store data. While standard databases primarily use disk storage (SSDs/HDDs), &lt;strong&gt;Redis keeps its state in RAM (Random Access Memory)&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Because RAM access is significantly faster than mechanical or electronic disk reads, Redis is often described as &lt;strong&gt;"lightning fast"&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Architecture: The Caching Layer
&lt;/h3&gt;

&lt;p&gt;In a typical application, Redis acts as an intermediary between the backend application and the primary database. This setup creates two primary scenarios:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Cache Hit:&lt;/strong&gt; The backend finds the required data in Redis and returns it immediately to the user, bypassing the slower database.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cache Miss:&lt;/strong&gt; If the data isn't in Redis, the backend queries the primary database. It then stores a copy of this &lt;strong&gt;"hot record"&lt;/strong&gt; in Redis for future requests before responding to the user.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This architecture dramatically &lt;strong&gt;reduces "read pressure"&lt;/strong&gt; on the primary database, which should remain the &lt;strong&gt;"Source of Truth"&lt;/strong&gt; for permanent records.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Features and Data Management
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Persistence:&lt;/strong&gt; Contrary to the myth that in-memory data is always lost on restart, Redis offers persistence features. It can load data from saved files back into memory upon a server reboot.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Key-Value Pairs:&lt;/strong&gt; Redis stores data in simple pairs. Developers are encouraged to use &lt;strong&gt;human-readable, colon-separated keys&lt;/strong&gt; (for example, &lt;code&gt;user:session:123&lt;/code&gt; or &lt;code&gt;product:all&lt;/code&gt;) to avoid collisions and simplify debugging.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TTL (Time to Live):&lt;/strong&gt; This is one of Redis's most powerful features. You can set an expiration time on a key (for example, 90 seconds). Once the time expires, Redis &lt;strong&gt;automatically deletes the record&lt;/strong&gt;, ensuring the memory remains uncluttered.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Advanced Use Cases
&lt;/h3&gt;

&lt;p&gt;Beyond simple data caching, Redis is used for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Session Management:&lt;/strong&gt; Storing user login states (Active/Inactive) across multiple distributed servers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OTP Management:&lt;/strong&gt; Holding temporary One-Time Passwords for a few minutes, they are valid.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rate Limiting:&lt;/strong&gt; Tracking IP addresses or user IDs to prevent abuse (for example, blocking a user for 10 minutes after too many failed login attempts).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Job Queues:&lt;/strong&gt; Maintaining lists of background tasks. &lt;strong&gt;"Workers"&lt;/strong&gt; (secondary backend applications) pull jobs from Redis to process time-consuming tasks like sending emails in batches.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Shared Counters:&lt;/strong&gt; Tracking live metrics like page views or "likes" across various application instances.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;h3&gt;
  
  
  Strategic Local Setup
&lt;/h3&gt;

&lt;p&gt;For development, the sources recommend using &lt;strong&gt;Docker&lt;/strong&gt; and &lt;strong&gt;Docker Compose&lt;/strong&gt; to spin up a local environment. A standard configuration involves:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Redis Image:&lt;/strong&gt; Using &lt;code&gt;redis:7-alpine&lt;/code&gt; for a lightweight footprint.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Port Mapping:&lt;/strong&gt; Binding the default Redis port &lt;strong&gt;6379&lt;/strong&gt; to the host machine.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Persistence Command:&lt;/strong&gt; Running the server with &lt;code&gt;--appendonly yes&lt;/code&gt; to ensure data is written to a log.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In a &lt;strong&gt;Node.js&lt;/strong&gt; environment, the &lt;strong&gt;&lt;code&gt;ioredis&lt;/code&gt;&lt;/strong&gt; library is the industry-standard package for communication. A basic connection is established by creating a new Redis client using the local URL: &lt;code&gt;redis://localhost:6379&lt;/code&gt;. Developers can test the connection using the &lt;strong&gt;&lt;code&gt;PING&lt;/code&gt;&lt;/strong&gt; command, which should return a &lt;strong&gt;&lt;code&gt;PONG&lt;/code&gt;&lt;/strong&gt; response from the server.&lt;/p&gt;

&lt;h3&gt;
  
  
  When to Use Redis
&lt;/h3&gt;

&lt;p&gt;Redis is not a solution for every problem. Use it if your application needs to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Remove read pressure from the primary DB.&lt;/li&gt;
&lt;li&gt;Manage rapidly expiring temporary data.&lt;/li&gt;
&lt;li&gt;Handle background job queues or shared counters.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However, it is &lt;strong&gt;not a replacement for a primary database&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  When NOT to use Redis
&lt;/h3&gt;

&lt;p&gt;Redis is not a "magic bullet". It should not be used if you don't have a clear bottleneck or if your data doesn't fit the patterns described above. If you have a write-heavy application where data doesn't need to be read frequently, or if you are trying to use it as a primary database for complex relational data, Redis may not be the right solution.&lt;/p&gt;

</description>
      <category>redis</category>
      <category>systemdesign</category>
      <category>architecture</category>
      <category>programming</category>
    </item>
    <item>
      <title>Scalability in System Design - Vertical vs Horizontal Scaling</title>
      <dc:creator>Sushant Gaurav</dc:creator>
      <pubDate>Tue, 19 May 2026 05:41:00 +0000</pubDate>
      <link>https://dev.to/imsushant12/scalability-in-system-design-vertical-vs-horizontal-scaling-4nmp</link>
      <guid>https://dev.to/imsushant12/scalability-in-system-design-vertical-vs-horizontal-scaling-4nmp</guid>
      <description>&lt;p&gt;There comes a point in every system’s life where things start to break; not because the system is poorly designed, but because it is being used more than it was ever intended to handle.&lt;/p&gt;

&lt;p&gt;At first, everything feels smooth. Requests are processed quickly, users are satisfied, and the system behaves predictably. But as usage grows, subtle changes begin to appear. Pages take longer to load. APIs respond more slowly. Databases struggle to keep up. Eventually, what once worked effortlessly starts becoming unreliable.&lt;/p&gt;

&lt;p&gt;This is not a failure of design.&lt;/p&gt;

&lt;p&gt;It is a signal.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The system has reached the limits of its current capacity.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And this is where scalability enters the conversation.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Does Scalability Really Mean?
&lt;/h2&gt;

&lt;p&gt;Scalability is often misunderstood as simply handling more users. But that definition is incomplete.&lt;/p&gt;

&lt;p&gt;A system is considered scalable if it can &lt;strong&gt;handle increasing load without a proportional drop in performance or reliability&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Notice the nuance here.&lt;/p&gt;

&lt;p&gt;It is not just about handling more requests - it is about doing so &lt;strong&gt;efficiently&lt;/strong&gt;. A system that doubles its resources every time the load increases is not truly scalable; it is simply brute-forcing the problem.&lt;/p&gt;

&lt;p&gt;True scalability is about &lt;strong&gt;growing intelligently&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;And to achieve that, systems typically rely on two fundamental approaches:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Scaling &lt;strong&gt;up&lt;/strong&gt; (vertical scaling)&lt;/li&gt;
&lt;li&gt;Scaling &lt;strong&gt;out&lt;/strong&gt; (horizontal scaling)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At a high level, both aim to solve the same problem: increasing capacity. But the way they approach it, and the consequences of those choices, are fundamentally different.&lt;/p&gt;

&lt;h2&gt;
  
  
  Vertical Scaling - Growing Taller
&lt;/h2&gt;

&lt;p&gt;Vertical scaling, often referred to as &lt;em&gt;scaling up&lt;/em&gt;, is the simpler and more intuitive approach.&lt;/p&gt;

&lt;p&gt;Instead of changing the structure of the system, you make the existing machine more powerful.&lt;/p&gt;

&lt;p&gt;You increase:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CPU&lt;/li&gt;
&lt;li&gt;RAM&lt;/li&gt;
&lt;li&gt;Disk capacity&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In essence, you are upgrading the machine so it can handle more work.&lt;/p&gt;

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

&lt;p&gt;From an engineering perspective, vertical scaling feels natural.&lt;/p&gt;

&lt;p&gt;There is no need to redesign the system. The application continues to run as it always has, just on better hardware. Databases remain centralised. Communication patterns remain unchanged. There is no need to think about distribution, coordination, or synchronisation.&lt;/p&gt;

&lt;p&gt;This simplicity is incredibly valuable - especially in the early stages of a system.&lt;/p&gt;

&lt;p&gt;It allows teams to focus on building features rather than solving infrastructure complexity.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Vertical Scaling Works So Well (Initially)
&lt;/h2&gt;

&lt;p&gt;In the early lifecycle of a product, vertical scaling often provides the fastest path to growth.&lt;/p&gt;

&lt;p&gt;If your database is slowing down, you can upgrade it to a machine with more memory. If your application server is under load, you can increase its CPU capacity.&lt;/p&gt;

&lt;p&gt;The system continues to function exactly as before, just with more headroom.&lt;/p&gt;

&lt;p&gt;This is why many systems, including those built by companies like Instagram in their early days, start with vertically scaled architectures.&lt;/p&gt;

&lt;p&gt;The benefits are clear:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Minimal architectural changes&lt;/li&gt;
&lt;li&gt;Lower operational complexity&lt;/li&gt;
&lt;li&gt;Faster implementation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For a small team trying to move quickly, this is often the most practical choice.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Limits of Vertical Scaling
&lt;/h2&gt;

&lt;p&gt;But like everything in system design, vertical scaling has limits.&lt;/p&gt;

&lt;p&gt;The first limitation is physical.&lt;/p&gt;

&lt;p&gt;A machine can only be upgraded to a certain extent. There is a maximum amount of CPU, memory, and storage you can add. Beyond that point, scaling up is no longer possible.&lt;/p&gt;

&lt;p&gt;The second limitation is cost.&lt;/p&gt;

&lt;p&gt;As machines become more powerful, their cost increases disproportionately. A machine that is twice as powerful is often significantly more than twice as expensive.&lt;/p&gt;

&lt;p&gt;This leads to diminishing returns.&lt;/p&gt;

&lt;p&gt;The third and perhaps most critical limitation is &lt;strong&gt;risk&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;When your entire system depends on a single machine, that machine becomes a &lt;strong&gt;single point of failure&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If it goes down:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The entire system goes down&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No matter how powerful the machine is, it cannot protect you from hardware failures, network issues, or unexpected crashes.&lt;/p&gt;

&lt;p&gt;This is where the need for a different approach begins to emerge.&lt;/p&gt;

&lt;h2&gt;
  
  
  Horizontal Scaling - Growing Wider
&lt;/h2&gt;

&lt;p&gt;Horizontal scaling, or &lt;em&gt;scaling out&lt;/em&gt;, takes a fundamentally different approach.&lt;/p&gt;

&lt;p&gt;Instead of making a single machine more powerful, you &lt;strong&gt;add more machines&lt;/strong&gt; and distribute the workload among them.&lt;/p&gt;

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

&lt;p&gt;Now, instead of relying on one powerful server, the system relies on multiple smaller servers working together.&lt;/p&gt;

&lt;p&gt;This introduces a new concept: &lt;strong&gt;distribution of work&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Requests are no longer handled by a single machine. They are spread across multiple nodes, often using a load balancer that decides where each request should go.&lt;/p&gt;

&lt;p&gt;At first, this might seem like a straightforward extension of vertical scaling. But in reality, it changes the nature of the system entirely.&lt;/p&gt;

&lt;p&gt;Because the moment you introduce multiple machines, you introduce:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Network communication&lt;/li&gt;
&lt;li&gt;Data synchronisation&lt;/li&gt;
&lt;li&gt;Failure handling across nodes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In other words, you are stepping into the world of distributed systems.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Shift in Complexity
&lt;/h2&gt;

&lt;p&gt;Vertical scaling keeps complexity low but limits growth.&lt;/p&gt;

&lt;p&gt;Horizontal scaling removes those limits but introduces a new kind of complexity.&lt;/p&gt;

&lt;p&gt;This is not just an implementation detail; it is a fundamental shift in how systems are designed and reasoned about.&lt;/p&gt;

&lt;p&gt;In a vertically scaled system:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;There is one source of truth&lt;/li&gt;
&lt;li&gt;Communication is local&lt;/li&gt;
&lt;li&gt;Failures are simpler to reason about&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In a horizontally scaled system:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Data may exist in multiple places&lt;/li&gt;
&lt;li&gt;Communication happens over networks&lt;/li&gt;
&lt;li&gt;Failures become partial and unpredictable&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is the same shift we saw earlier when moving from monolithic to distributed systems.&lt;/p&gt;

&lt;p&gt;Because in many ways, &lt;strong&gt;horizontal scaling is what forces systems to become distributed&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where This Is Heading
&lt;/h2&gt;

&lt;p&gt;At this point, we’ve built the intuition:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Vertical scaling is simple, powerful, and limited&lt;/li&gt;
&lt;li&gt;Horizontal scaling is flexible, scalable, and complex&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But this is only the surface. To truly understand horizontal scaling, we need to answer a deeper question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;What actually happens to data and traffic when a system scales horizontally?&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Because adding more machines is easy.&lt;/p&gt;

&lt;p&gt;Making them work &lt;strong&gt;together correctly and efficiently&lt;/strong&gt; is the real challenge.&lt;/p&gt;

&lt;h2&gt;
  
  
  Distributing Traffic - The Role of Load Balancing
&lt;/h2&gt;

&lt;p&gt;The moment you introduce multiple servers, you need a way to decide:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Which request goes to which machine?&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is the job of a load balancer.&lt;/p&gt;

&lt;p&gt;A load balancer sits between users and your servers, acting as a traffic controller. Instead of users directly hitting a specific server, their requests are routed through the load balancer, which distributes them across available machines.&lt;/p&gt;

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

&lt;p&gt;At a surface level, this seems simple—just spread requests evenly. But in practice, it involves subtle decisions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Should requests be distributed round-robin?&lt;/li&gt;
&lt;li&gt;Should they go to the least loaded server?&lt;/li&gt;
&lt;li&gt;Should user sessions stick to the same server?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These choices affect both &lt;strong&gt;performance and correctness&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;And more importantly, they introduce a critical requirement:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Each server should be able to handle requests independently.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This leads to a key design principle in scalable systems:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Statelessness&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Stateless vs Stateful Systems
&lt;/h2&gt;

&lt;p&gt;In a vertically scaled system, state is easy to manage. Since everything runs on a single machine, user sessions, data, and temporary state can be stored locally.&lt;/p&gt;

&lt;p&gt;But in a horizontally scaled system, this approach breaks down.&lt;/p&gt;

&lt;p&gt;If a user’s request goes to Server 1, and their next request goes to Server 3, that second server must still understand the user’s context.&lt;/p&gt;

&lt;p&gt;This is why scalable systems aim to make application servers &lt;strong&gt;stateless&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Instead of storing session data locally, they store it in shared systems such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Databases&lt;/li&gt;
&lt;li&gt;Distributed caches&lt;/li&gt;
&lt;li&gt;External storage systems&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This allows any server to handle any request, making load balancing effective.&lt;/p&gt;

&lt;p&gt;But this shift pushes complexity elsewhere, into how data is stored and accessed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Scaling Data - The Real Challenge
&lt;/h2&gt;

&lt;p&gt;Handling more requests is only part of the problem.&lt;/p&gt;

&lt;p&gt;The bigger challenge is handling &lt;strong&gt;more data&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In a vertically scaled system, data typically lives in a single database. As the load increases, you upgrade the database server. But just like application servers, databases have limits.&lt;/p&gt;

&lt;p&gt;This is where horizontal scaling forces a fundamental shift in data strategy.&lt;/p&gt;

&lt;p&gt;Two major approaches emerge:&lt;/p&gt;

&lt;h3&gt;
  
  
  Replication - Copying Data Across Nodes
&lt;/h3&gt;

&lt;p&gt;Replication involves creating multiple copies of the same data across different machines.&lt;/p&gt;

&lt;p&gt;This allows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Multiple servers to read data simultaneously&lt;/li&gt;
&lt;li&gt;Improved availability if one node fails&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, one database node may handle writes, while multiple replicas handle read requests.&lt;/p&gt;

&lt;p&gt;This improves throughput, but introduces consistency challenges—something we explored earlier in CAP.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sharding - Splitting Data Across Nodes
&lt;/h3&gt;

&lt;p&gt;Sharding takes a different approach.&lt;/p&gt;

&lt;p&gt;Instead of copying data, it &lt;strong&gt;divides it&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Each server is responsible for a subset of the data:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;User A–M on one server&lt;/li&gt;
&lt;li&gt;User N–Z on another&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;This allows the system to scale almost indefinitely by adding more shards.&lt;/p&gt;

&lt;p&gt;But it introduces new complexity:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How do you decide which shard stores which data?&lt;/li&gt;
&lt;li&gt;What happens when data needs to move between shards?&lt;/li&gt;
&lt;li&gt;How do you handle queries that span multiple shards?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sharding improves scalability dramatically, but at the cost of &lt;strong&gt;operational and architectural complexity&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Availability - Why Horizontal Scaling Wins
&lt;/h2&gt;

&lt;p&gt;One of the most powerful advantages of horizontal scaling is &lt;strong&gt;fault tolerance&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In a vertically scaled system, everything depends on a single machine. If it fails, the system goes down.&lt;/p&gt;

&lt;p&gt;In a horizontally scaled system, failure becomes &lt;strong&gt;partial&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If one server crashes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Other servers continue handling requests&lt;/li&gt;
&lt;li&gt;The system degrades, but does not collapse&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is the foundation of high-availability systems.&lt;/p&gt;

&lt;p&gt;It is also why companies like Netflix design their systems to run across multiple machines, zones, and even regions.&lt;/p&gt;

&lt;p&gt;They assume failure will happen—and design systems that survive it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cost, Complexity, and Trade-offs
&lt;/h2&gt;

&lt;p&gt;At this point, horizontal scaling may seem like the obvious choice.&lt;/p&gt;

&lt;p&gt;But it comes with trade-offs that cannot be ignored.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cost Dynamics
&lt;/h3&gt;

&lt;p&gt;While horizontal scaling can start with cheaper machines, the total cost can grow quickly as you add more infrastructure, networking, and operational overhead.&lt;/p&gt;

&lt;h3&gt;
  
  
  Engineering Complexity
&lt;/h3&gt;

&lt;p&gt;You now need to handle:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Distributed communication&lt;/li&gt;
&lt;li&gt;Data consistency&lt;/li&gt;
&lt;li&gt;Failures across nodes&lt;/li&gt;
&lt;li&gt;Monitoring and observability&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Debugging Challenges
&lt;/h3&gt;

&lt;p&gt;A single request may pass through multiple machines. Debugging issues becomes significantly harder compared to a single-node system.&lt;/p&gt;

&lt;p&gt;This leads to a critical insight:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Horizontal scaling solves scalability problems by introducing distributed systems complexity.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The Hybrid Reality
&lt;/h2&gt;

&lt;p&gt;In practice, most systems do not rely purely on vertical or horizontal scaling.&lt;/p&gt;

&lt;p&gt;They combine both.&lt;/p&gt;

&lt;p&gt;A common approach is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Scale vertically first (quick wins, low complexity)&lt;/li&gt;
&lt;li&gt;Introduce horizontal scaling as limits are reached&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Start with a powerful database server&lt;/li&gt;
&lt;li&gt;Add read replicas as traffic grows&lt;/li&gt;
&lt;li&gt;Eventually introduce sharding when needed&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This gradual evolution allows systems to grow without unnecessary complexity early on.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Deeper Insight
&lt;/h2&gt;

&lt;p&gt;At its core, scalability is not about choosing between vertical and horizontal scaling.&lt;/p&gt;

&lt;p&gt;It is about understanding &lt;strong&gt;when each approach makes sense&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Vertical scaling is about simplicity and speed.&lt;br&gt;
Horizontal scaling is about resilience and long-term growth.&lt;/p&gt;

&lt;p&gt;And the transition between them is one of the most important decisions in system design.&lt;/p&gt;

&lt;p&gt;Because once you move toward horizontal scaling, you are no longer just scaling a system:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You are designing a distributed system.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Final Thought
&lt;/h2&gt;

&lt;p&gt;Scalability is often seen as a technical challenge.&lt;/p&gt;

&lt;p&gt;But in reality, it is a reflection of success.&lt;/p&gt;

&lt;p&gt;Systems only need to scale when they are being used, when they are growing, when they matter.&lt;/p&gt;

&lt;p&gt;And the way you scale them defines:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Their performance&lt;/li&gt;
&lt;li&gt;Their reliability&lt;/li&gt;
&lt;li&gt;Their future evolution&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because in the end, scalability is not just about handling more users:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It is about building systems that can grow without breaking.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>systemdesign</category>
      <category>programming</category>
      <category>architecture</category>
      <category>software</category>
    </item>
    <item>
      <title>CAP Theorem Explained Simply (And Why It Matters in Real Systems)</title>
      <dc:creator>Sushant Gaurav</dc:creator>
      <pubDate>Tue, 05 May 2026 05:41:00 +0000</pubDate>
      <link>https://dev.to/imsushant12/cap-theorem-explained-simply-and-why-it-matters-in-real-systems-2amn</link>
      <guid>https://dev.to/imsushant12/cap-theorem-explained-simply-and-why-it-matters-in-real-systems-2amn</guid>
      <description>&lt;p&gt;There is a moment in every system design journey where things stop feeling simple.&lt;/p&gt;

&lt;p&gt;Until that point, systems seem manageable. You think in terms of databases, APIs, scaling strategies, maybe even caching layers. But then you encounter distributed systems in their true form—data spread across machines, services communicating over unreliable networks, failures happening in unpredictable ways.&lt;/p&gt;

&lt;p&gt;And suddenly, a question emerges that is far more difficult than it first appears:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;How do we ensure that all parts of a system behave correctly when they are no longer in the same place?&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is the question that gave rise to the CAP Theorem.&lt;/p&gt;

&lt;p&gt;At first glance, CAP is often presented as a rule - something to memorize:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A distributed system can only guarantee two out of three: Consistency, Availability, and Partition Tolerance.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But this simplified statement, while technically correct, hides the deeper truth.&lt;/p&gt;

&lt;p&gt;CAP is not just a rule.&lt;/p&gt;

&lt;p&gt;It is a &lt;strong&gt;constraint imposed by reality&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;To truly understand it, we need to go beyond definitions and step into the world where distributed systems actually operate. &lt;/p&gt;

&lt;h2&gt;
  
  
  The Reality of Distribution
&lt;/h2&gt;

&lt;p&gt;In a monolithic system, everything runs within a single environment. Data is stored in one place, and operations happen in a predictable sequence. If you update a value, every part of the system immediately sees that update.&lt;/p&gt;

&lt;p&gt;But in a distributed system, things are fundamentally different.&lt;/p&gt;

&lt;p&gt;Data is no longer centralized. It is spread across multiple nodes—possibly across regions, continents, or even different cloud providers. These nodes communicate over a network, and that network is not perfect.&lt;/p&gt;

&lt;p&gt;Messages can be delayed.&lt;br&gt;
Packets can be lost.&lt;br&gt;
Connections can break.&lt;/p&gt;

&lt;p&gt;And when that happens, parts of the system can no longer talk to each other.&lt;/p&gt;

&lt;p&gt;This situation is known as a &lt;strong&gt;network partition&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Partition Tolerance — The Unavoidable Reality
&lt;/h2&gt;

&lt;p&gt;Partition tolerance refers to a system’s ability to continue functioning even when communication between nodes is disrupted.&lt;/p&gt;

&lt;p&gt;And here’s the critical insight:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In distributed systems, partitions are not optional—they are inevitable.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You cannot design a real-world distributed system and assume that the network will always be reliable. Sooner or later, something will fail.&lt;/p&gt;

&lt;p&gt;This means that partition tolerance is not a choice you make.&lt;/p&gt;

&lt;p&gt;It is a condition you must accept.&lt;/p&gt;

&lt;p&gt;Once you accept this, the CAP theorem becomes much clearer.&lt;/p&gt;

&lt;p&gt;Because now the real question is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;When a partition happens, what do you prioritize - consistency or availability?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Consistency — One Truth Across the System
&lt;/h2&gt;

&lt;p&gt;Consistency, in the context of CAP, means that all nodes see the same data at the same time.&lt;/p&gt;

&lt;p&gt;If a user updates a piece of data, any subsequent read—no matter which node it comes from—should return that updated value.&lt;/p&gt;

&lt;p&gt;There is a single, unified truth.&lt;/p&gt;

&lt;p&gt;This is straightforward in a centralized system. But in a distributed system, maintaining this guarantee requires coordination between nodes.&lt;/p&gt;

&lt;p&gt;When a write happens, all replicas must agree on the updated value before it is considered complete.&lt;/p&gt;

&lt;p&gt;This coordination takes time. And during a network partition, it may not be possible at all.&lt;/p&gt;

&lt;p&gt;So if you insist on strong consistency, the system must sometimes &lt;strong&gt;refuse to respond&lt;/strong&gt; rather than risk returning incorrect data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Availability — Always Responding
&lt;/h2&gt;

&lt;p&gt;Availability means that every request to the system receives a response.&lt;/p&gt;

&lt;p&gt;It does not necessarily mean the response is correct or up-to-date—only that the system does not fail to respond.&lt;/p&gt;

&lt;p&gt;In highly available systems, the priority is to keep the system operational, even under failure conditions.&lt;/p&gt;

&lt;p&gt;This often means allowing different nodes to respond independently, even if they do not have the latest data.&lt;/p&gt;

&lt;p&gt;The system continues to function, but it may temporarily serve inconsistent data.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Core Trade-off
&lt;/h2&gt;

&lt;p&gt;Now we arrive at the heart of CAP.&lt;/p&gt;

&lt;p&gt;When a network partition occurs, you are forced to make a decision:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you choose &lt;strong&gt;consistency&lt;/strong&gt;, you may have to reject requests to ensure correctness.&lt;/li&gt;
&lt;li&gt;If you choose &lt;strong&gt;availability&lt;/strong&gt;, you may return outdated or inconsistent data.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You cannot guarantee both at the same time.&lt;/p&gt;

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

&lt;p&gt;This is the essence of the CAP theorem.&lt;/p&gt;

&lt;p&gt;It is not about picking any two out of three in general conditions. It is about what happens &lt;strong&gt;during a partition&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;And since partitions are inevitable, this trade-off is unavoidable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Matters More Than You Think
&lt;/h2&gt;

&lt;p&gt;At this point, CAP might seem like an abstract concept. But in reality, it influences almost every large-scale system you interact with.&lt;/p&gt;

&lt;p&gt;When you see slightly outdated data on a social media feed, that is a system choosing availability over strict consistency.&lt;/p&gt;

&lt;p&gt;When a payment system refuses to process a transaction until it confirms the latest state, that is a system prioritizing consistency over availability.&lt;/p&gt;

&lt;p&gt;These are not accidental behaviours. They are deliberate design choices shaped by CAP.&lt;/p&gt;

&lt;p&gt;Companies like Amazon often design different parts of their systems with different priorities. For example, product catalogues may favour availability, while payment systems enforce strict consistency.&lt;/p&gt;

&lt;p&gt;This highlights an important idea:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;CAP is not applied to an entire system uniformly; it is applied at the level of individual components.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now the natural question becomes:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;What kinds of systems make which choices? And how do real-world architectures actually deal with this trade-off?&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To answer that, we need to look at how CAP is commonly categorized in practice.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Three CAP Categories (And the Truth Behind Them)
&lt;/h2&gt;

&lt;p&gt;CAP is often explained using three system types:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;CP (Consistency + Partition Tolerance)&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AP (Availability + Partition Tolerance)&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CA (Consistency + Availability)&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At first glance, this looks like a clean classification. But there is a subtle—and very important—truth hidden here.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In real distributed systems, &lt;strong&gt;CA is not actually achievable&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Why?&lt;/p&gt;

&lt;p&gt;Because partition tolerance is not optional.&lt;/p&gt;

&lt;p&gt;If your system is distributed, you cannot ignore the possibility of network failures. And the moment you accept partitions as inevitable, you are always operating in the world of &lt;strong&gt;P (Partition Tolerance)&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;So in practice, the real trade-off is always:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;CP vs AP&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  CP Systems — Choosing Consistency Over Availability
&lt;/h2&gt;

&lt;p&gt;A CP system prioritizes correctness above all else.&lt;/p&gt;

&lt;p&gt;When a partition occurs, and nodes cannot communicate reliably, the system chooses to &lt;strong&gt;reject or delay requests&lt;/strong&gt; rather than risk returning inconsistent data.&lt;/p&gt;

&lt;p&gt;This often means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Some parts of the system become temporarily unavailable&lt;/li&gt;
&lt;li&gt;Users may experience errors or delays&lt;/li&gt;
&lt;li&gt;But the data remains correct and trustworthy&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This approach is critical in systems where correctness is non-negotiable.&lt;/p&gt;

&lt;p&gt;Think about financial transactions. If your bank shows two different balances depending on which server you hit, the system is fundamentally broken.&lt;/p&gt;

&lt;p&gt;This is why systems dealing with payments, inventory management, or critical state often lean toward CP.&lt;/p&gt;

&lt;p&gt;For example, services within Google that require strict coordination (like distributed databases with strong guarantees) are designed to favor consistency, even if it means temporarily sacrificing availability.&lt;/p&gt;

&lt;h2&gt;
  
  
  AP Systems — Choosing Availability Over Consistency
&lt;/h2&gt;

&lt;p&gt;AP systems take the opposite approach.&lt;/p&gt;

&lt;p&gt;When a partition occurs, they continue to &lt;strong&gt;serve requests no matter what&lt;/strong&gt;, even if that means returning stale or inconsistent data.&lt;/p&gt;

&lt;p&gt;This results in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;High availability&lt;/li&gt;
&lt;li&gt;Faster response times during failures&lt;/li&gt;
&lt;li&gt;Temporary inconsistencies across nodes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But here’s the key: these inconsistencies are not permanent.&lt;/p&gt;

&lt;p&gt;AP systems rely on a concept called &lt;strong&gt;eventual consistency&lt;/strong&gt;, where all nodes will converge to the same state once the network stabilizes.&lt;/p&gt;

&lt;p&gt;This model works well for systems where perfect accuracy at every moment is not required.&lt;/p&gt;

&lt;p&gt;For example, platforms like Facebook prioritize keeping the platform responsive. If your feed shows a slightly outdated like count for a few seconds, it does not break the user experience.&lt;/p&gt;

&lt;p&gt;The system favours &lt;strong&gt;availability and responsiveness&lt;/strong&gt; over strict consistency.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why CA Systems Don’t Really Exist
&lt;/h2&gt;

&lt;p&gt;It is tempting to think that some systems can achieve both consistency and availability.&lt;/p&gt;

&lt;p&gt;And technically, in systems that are &lt;strong&gt;not distributed&lt;/strong&gt;, this is true.&lt;/p&gt;

&lt;p&gt;A single-node database can provide both:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Immediate consistency&lt;/li&gt;
&lt;li&gt;Always-available responses (as long as the node is up)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But the moment you distribute the system across multiple nodes, the network becomes a factor.&lt;/p&gt;

&lt;p&gt;And once the network becomes a factor, partitions become inevitable.&lt;/p&gt;

&lt;p&gt;So any system that claims to be CA is either:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Not truly distributed&lt;/li&gt;
&lt;li&gt;Or quietly sacrificing partition tolerance (which is unrealistic in real-world systems)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Real Systems Don’t Pick One Side Completely
&lt;/h2&gt;

&lt;p&gt;Here’s where things get even more interesting.&lt;/p&gt;

&lt;p&gt;Real-world systems rarely choose to be purely CP or purely AP.&lt;/p&gt;

&lt;p&gt;Instead, they &lt;strong&gt;mix and match&lt;/strong&gt; based on the needs of different components.&lt;/p&gt;

&lt;p&gt;For example, in a large system like Amazon:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The &lt;strong&gt;shopping cart&lt;/strong&gt; might be AP&lt;br&gt;
(you can still add items even if some nodes are out of sync)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;strong&gt;payment system&lt;/strong&gt; is CP&lt;br&gt;
(transactions must be accurate and consistent)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;strong&gt;product catalog&lt;/strong&gt; might lean toward AP&lt;br&gt;
(slight delays in updates are acceptable)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This layered approach allows systems to optimize for different trade-offs depending on the context.&lt;/p&gt;

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

&lt;p&gt;This is a critical mindset shift:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;CAP is not a system-wide decision. It is a per-component design choice&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  How Modern Systems Soften the Trade-off
&lt;/h2&gt;

&lt;p&gt;While CAP defines a hard constraint, modern systems use clever techniques to &lt;em&gt;reduce the pain&lt;/em&gt; of the trade-off.&lt;/p&gt;

&lt;p&gt;They cannot eliminate it—but they can make it less noticeable.&lt;/p&gt;

&lt;h3&gt;
  
  
  Eventual Consistency with Conflict Resolution
&lt;/h3&gt;

&lt;p&gt;AP systems often allow temporary inconsistencies but resolve them later using strategies like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Last write wins&lt;/li&gt;
&lt;li&gt;Version vectors&lt;/li&gt;
&lt;li&gt;Conflict-free data structures&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Retries and Idempotency
&lt;/h3&gt;

&lt;p&gt;Systems retry failed requests intelligently, ensuring that operations can be safely repeated without corrupting data.&lt;/p&gt;

&lt;h3&gt;
  
  
  Graceful Degradation
&lt;/h3&gt;

&lt;p&gt;Instead of failing completely, systems reduce functionality under stress:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Showing cached data&lt;/li&gt;
&lt;li&gt;Disabling non-critical features&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Geo-Partitioning
&lt;/h3&gt;

&lt;p&gt;Data is partitioned geographically so that most operations happen locally, reducing the impact of global partitions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Misconceptions About CAP
&lt;/h2&gt;

&lt;p&gt;Even experienced engineers sometimes misunderstand CAP. Let’s clear up a few common myths.&lt;/p&gt;

&lt;h3&gt;
  
  
  You can choose any two at any time
&lt;/h3&gt;

&lt;p&gt;No — the trade-off only matters &lt;strong&gt;during a partition&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  AP systems don’t care about consistency
&lt;/h3&gt;

&lt;p&gt;They do — they just relax &lt;em&gt;when&lt;/em&gt; consistency is achieved.&lt;/p&gt;

&lt;h3&gt;
  
  
  CP systems are always better
&lt;/h3&gt;

&lt;p&gt;Not necessarily — they can lead to poor user experience during failures.&lt;/p&gt;

&lt;h3&gt;
  
  
  CAP is outdated
&lt;/h3&gt;

&lt;p&gt;Not at all — it is still one of the most fundamental constraints in distributed systems.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Real Lesson of CAP
&lt;/h2&gt;

&lt;p&gt;CAP is not about memorizing three letters.&lt;/p&gt;

&lt;p&gt;It is about understanding this deeper truth:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;In distributed systems, failure forces you to make trade-offs&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And those trade-offs are not bugs.&lt;/p&gt;

&lt;p&gt;They are design decisions.&lt;/p&gt;

&lt;p&gt;The best system designers are not the ones who avoid trade-offs—they are the ones who &lt;strong&gt;choose them wisely&lt;/strong&gt;, based on the needs of the system.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thought
&lt;/h2&gt;

&lt;p&gt;If you truly understand CAP, you start seeing systems differently.&lt;/p&gt;

&lt;p&gt;You begin to ask better questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What happens when this service cannot reach another service?&lt;/li&gt;
&lt;li&gt;Is it better to fail or return stale data?&lt;/li&gt;
&lt;li&gt;Where can we tolerate inconsistency, and where can we not?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And those questions lead to better designs.&lt;/p&gt;

&lt;p&gt;Because at scale, systems are not defined by how they behave when everything works—&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;They are defined by how they behave when things break.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>systemdesign</category>
      <category>programming</category>
      <category>software</category>
      <category>architecture</category>
    </item>
  </channel>
</rss>
