<?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: Gouranga Das Samrat</title>
    <description>The latest articles on DEV Community by Gouranga Das Samrat (@gouranga-das-khulna).</description>
    <link>https://dev.to/gouranga-das-khulna</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%2F2193879%2F834a1499-2027-4355-87be-bb678e90ae5c.jpg</url>
      <title>DEV Community: Gouranga Das Samrat</title>
      <link>https://dev.to/gouranga-das-khulna</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/gouranga-das-khulna"/>
    <language>en</language>
    <item>
      <title>Message Queues (SQS)</title>
      <dc:creator>Gouranga Das Samrat</dc:creator>
      <pubDate>Sun, 12 Jul 2026 02:00:00 +0000</pubDate>
      <link>https://dev.to/gouranga-das-khulna/message-queues-sqs-nj7</link>
      <guid>https://dev.to/gouranga-das-khulna/message-queues-sqs-nj7</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;One-liner:&lt;/strong&gt; A message queue decouples services by letting a producer drop messages into a queue, where consumers pick them up asynchronously — neither needs to be available at the same time.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  📌 The Problem: Tight Coupling
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User places order →
  [Order Service] → calls [Payment Service] → waits →
                  → calls [Email Service] → waits →
                  → calls [Inventory Service] → waits →
  All done! (3s total, 3 failure points)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Problems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;High latency&lt;/strong&gt; — user waits for every downstream service&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cascading failure&lt;/strong&gt; — if Email service is down, order fails&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tight coupling&lt;/strong&gt; — Order service knows about all downstream services&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No retry logic&lt;/strong&gt; — failures are permanent&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  💡 The Solution: Message Queue
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User places order → [Order Service] → DROP message in queue → RESPOND (fast!)
                                              ↓
                                   [Queue]
                                   /    |    \
                          [Payment] [Email] [Inventory]  ← process at their own pace
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Decoupling&lt;/strong&gt; — services don't know about each other&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resilience&lt;/strong&gt; — downstream service can be down; message waits in queue&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Load leveling&lt;/strong&gt; — queue absorbs traffic spikes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Retry&lt;/strong&gt; — failed processing retried automatically&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🔄 Queue Concepts
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Producer &amp;amp; Consumer
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Producer] → push message → [Queue] → pull message → [Consumer]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Producer&lt;/strong&gt;: Creates and sends messages&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consumer&lt;/strong&gt;: Reads and processes messages&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Queue&lt;/strong&gt;: Durable buffer between them&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Message Lifecycle
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. Producer sends message → Queue stores it
2. Consumer polls queue → Queue marks message as "in-flight" (invisible to others)
3. Consumer processes → Success: Consumer deletes message
                     → Failure: After visibility timeout, message reappears
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Visibility Timeout
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Consumer pulls message → message hidden for 30 seconds
If consumer crashes → 30 seconds later, message reappears → another consumer picks it up
If consumer succeeds → consumer deletes message → gone forever
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  ☁️ AWS SQS (Simple Queue Service)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Standard Queue
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Unlimited throughput&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;At-least-once delivery&lt;/strong&gt; — message may be delivered more than once!&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best-effort ordering&lt;/strong&gt; — no strict FIFO&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  FIFO Queue
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Exactly-once processing&lt;/strong&gt; — deduplication&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Strict ordering&lt;/strong&gt; — first in, first out&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Limited throughput&lt;/strong&gt; — 300 msg/sec (or 3000 with batching)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  SQS Key Concepts
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Message retention:  Up to 14 days (default: 4 days)
Visibility timeout: How long consumer has to process (default: 30s)
Dead Letter Queue:  Where failed messages go after N retries
Max message size:   256 KB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  SQS + Lambda (Serverless Consumer)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[SQS Queue] ──triggers──► [Lambda Function]
                           (auto-scales to process backlog)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🔀 Queue Patterns
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Work Queue (Task Distribution)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Producer] → [Queue] → [Worker 1]
                     → [Worker 2]
                     → [Worker 3]

Each message processed by exactly ONE worker
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use case: Image resizing, email sending, PDF generation&lt;/p&gt;

&lt;h3&gt;
  
  
  Fan-out via Multiple Queues
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Event] → [SNS Topic] → [Queue A] → [Consumer A]
                      → [Queue B] → [Consumer B]
                      → [Queue C] → [Consumer C]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each consumer gets a copy of the message. (See: SNS/Pub-Sub)&lt;/p&gt;

&lt;h3&gt;
  
  
  Priority Queue
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;High priority queue → processed first by consumers
Low priority queue  → processed when high is empty
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  ♻️ Dead Letter Queue (DLQ)
&lt;/h2&gt;

&lt;p&gt;When a message fails to process after N retries → move to DLQ:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Queue] → [Consumer fails 3 times] → [DLQ]
                                          ↑
                                    Ops team inspects,
                                    fixes bug, redrives
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;SQS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Redrive&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Policy&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;span class="nl"&gt;"deadLetterTargetArn"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:sqs:us-east-1:123:my-dlq"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"maxReceiveCount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;after&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;failures&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;move&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;DLQ&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;h2&gt;
  
  
  ⚠️ Idempotency — Critical Requirement
&lt;/h2&gt;

&lt;p&gt;Standard queues deliver &lt;strong&gt;at-least-once&lt;/strong&gt;. Your consumer MUST be idempotent:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Message: "charge user 42 for $99"

❌ Non-idempotent: Just run the charge every time → user charged twice!
✅ Idempotent: Check if orderId already processed → skip if yes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;processPayment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;orderId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;amount&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// Check idempotency key&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;alreadyProcessed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`payment:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;orderId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;alreadyProcessed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// skip duplicate&lt;/span&gt;

  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;chargeUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`payment:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;orderId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;86400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// mark done&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  📊 SQS vs Other Queues
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;AWS SQS&lt;/th&gt;
&lt;th&gt;RabbitMQ&lt;/th&gt;
&lt;th&gt;Apache Kafka&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Type&lt;/td&gt;
&lt;td&gt;Managed cloud&lt;/td&gt;
&lt;td&gt;Self-hosted broker&lt;/td&gt;
&lt;td&gt;Distributed log&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Retention&lt;/td&gt;
&lt;td&gt;14 days&lt;/td&gt;
&lt;td&gt;Until consumed&lt;/td&gt;
&lt;td&gt;Configurable (forever)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ordering&lt;/td&gt;
&lt;td&gt;Best-effort/FIFO&lt;/td&gt;
&lt;td&gt;Per-queue&lt;/td&gt;
&lt;td&gt;Per-partition&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Replay&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅ (replay from offset)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Throughput&lt;/td&gt;
&lt;td&gt;Very high&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;Very high&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Use case&lt;/td&gt;
&lt;td&gt;Decoupling tasks&lt;/td&gt;
&lt;td&gt;Complex routing&lt;/td&gt;
&lt;td&gt;Event streaming&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  🎨 Diagram
&lt;/h2&gt;

&lt;p&gt;The diagram shows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Producer → Queue → Multiple consumers&lt;/li&gt;
&lt;li&gt;Visibility timeout flow (in-flight → reappear)&lt;/li&gt;
&lt;li&gt;Dead Letter Queue after max retries&lt;/li&gt;
&lt;li&gt;Fan-out via SNS → multiple queues&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🔑 Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Queues &lt;strong&gt;decouple&lt;/strong&gt; services and absorb traffic spikes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Visibility timeout&lt;/strong&gt; ensures messages aren't lost if a consumer crashes&lt;/li&gt;
&lt;li&gt;Always implement &lt;strong&gt;idempotent consumers&lt;/strong&gt; with SQS Standard&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DLQ&lt;/strong&gt; is essential for debugging failed messages&lt;/li&gt;
&lt;li&gt;Use &lt;strong&gt;FIFO&lt;/strong&gt; when order matters; Standard when throughput matters&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>systemdesign</category>
      <category>devops</category>
      <category>backend</category>
      <category>aws</category>
    </item>
    <item>
      <title>Redis</title>
      <dc:creator>Gouranga Das Samrat</dc:creator>
      <pubDate>Sat, 11 Jul 2026 02:00:00 +0000</pubDate>
      <link>https://dev.to/gouranga-das-khulna/redis-3l06</link>
      <guid>https://dev.to/gouranga-das-khulna/redis-3l06</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;One-liner:&lt;/strong&gt; An in-memory data structure store used as a cache, message broker, session store, rate limiter, and much more — blazing fast because everything lives in RAM.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  📌 Why Redis?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Speed:&lt;/strong&gt; In-memory → sub-millisecond latency (&amp;lt; 1ms)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rich data types:&lt;/strong&gt; Not just key-value — lists, sets, hashes, sorted sets, streams&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Persistence:&lt;/strong&gt; Optional — can snapshot to disk (RDB) or log every write (AOF)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pub/Sub:&lt;/strong&gt; Built-in message broker&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Expiry:&lt;/strong&gt; TTL on any key&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Atomic operations:&lt;/strong&gt; All commands are atomic&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🗃️ Redis Data Types
&lt;/h2&gt;

&lt;h3&gt;
  
  
  String — The Basic Type
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SET user:42:name "Rahul"
GET user:42:name      → "Rahul"
INCR page:views       → 1, 2, 3 (atomic counter)
SETEX session:abc 3600 "userId=42"  (with TTL)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Hash — Object/Map
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HSET user:42 name "Rahul" age 25 city "Delhi"
HGET user:42 name      → "Rahul"
HGETALL user:42        → { name: Rahul, age: 25, city: Delhi }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Best for: User profiles, product data, config&lt;/p&gt;

&lt;h3&gt;
  
  
  List — Ordered, Allows Duplicates
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;LPUSH notifications:42 "You got a like!"  (push to left)
RPUSH notifications:42 "New follower!"    (push to right)
LRANGE notifications:42 0 9               (get first 10)
LPOP notifications:42                     (remove from left)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Best for: Activity feeds, queues (FIFO/LIFO), recent items&lt;/p&gt;

&lt;h3&gt;
  
  
  Set — Unordered, Unique Values
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SADD followers:42 101 102 103
SMEMBERS followers:42    → {101, 102, 103}
SISMEMBER followers:42 102 → 1 (yes)
SCARD followers:42          → 3 (count)
SINTER followers:42 followers:99  → mutual followers (intersection)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Best for: Tags, unique visitors, friend lists&lt;/p&gt;

&lt;h3&gt;
  
  
  Sorted Set (ZSet) — Ranked/Scored Set
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ZADD leaderboard 9500 "player_alice"
ZADD leaderboard 8700 "player_bob"
ZADD leaderboard 9900 "player_charlie"
ZRANGE leaderboard 0 2 WITHSCORES REV  → charlie(9900), alice(9500), bob(8700)
ZRANK leaderboard "player_alice"         → 1 (0-indexed rank)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Best for: &lt;strong&gt;Leaderboards&lt;/strong&gt;, rate limiting, priority queues, trending topics&lt;/p&gt;

&lt;h3&gt;
  
  
  Stream — Append-only Log
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;XADD events * userId 42 action "purchase" amount 999
XREAD COUNT 10 STREAMS events 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Best for: Event sourcing, activity logs, message queues (like Kafka-lite)&lt;/p&gt;




&lt;h2&gt;
  
  
  🏗️ Common Redis Use Cases
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Session Store
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Login&lt;/span&gt;
&lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`session:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3600&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt; &lt;span class="p"&gt;}));&lt;/span&gt;

&lt;span class="c1"&gt;// Per-request auth&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`session:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Cache (Cache-Aside)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cached&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`user:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;cached&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`user:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Rate Limiting (Sliding Window)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`rate:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;60000&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;incr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;expire&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Rate limit exceeded&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Pub/Sub Messaging
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Publisher&lt;/span&gt;
&lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;publish&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;notifications&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;New order!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Subscriber&lt;/span&gt;
&lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;notifications&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;msg&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;sendPushNotification&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5. Distributed Lock
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;lock&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;lock:resource&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;NX&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;EX&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Resource locked by another process&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// ... do work ...&lt;/span&gt;
&lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;del&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;lock:resource&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;NX&lt;/code&gt; = set only if Not eXists | &lt;code&gt;EX 10&lt;/code&gt; = expire in 10 seconds&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Leaderboard
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Add/update score&lt;/span&gt;
&lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;zadd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;game:leaderboard&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;score&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Top 10&lt;/span&gt;
&lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;zrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;game:leaderboard&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;REV&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;WITHSCORES&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// User's rank&lt;/span&gt;
&lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;zrevrank&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;game:leaderboard&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🔄 Redis Persistence
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mode&lt;/th&gt;
&lt;th&gt;How&lt;/th&gt;
&lt;th&gt;Data Safety&lt;/th&gt;
&lt;th&gt;Performance&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;No persistence&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Pure in-memory&lt;/td&gt;
&lt;td&gt;Data lost on restart&lt;/td&gt;
&lt;td&gt;Fastest&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;RDB (Snapshot)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Periodic snapshot to disk&lt;/td&gt;
&lt;td&gt;Up to minutes of data loss&lt;/td&gt;
&lt;td&gt;Fast&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;AOF (Append Only File)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Log every write to disk&lt;/td&gt;
&lt;td&gt;Nearly no data loss&lt;/td&gt;
&lt;td&gt;Slower&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;RDB + AOF&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Both&lt;/td&gt;
&lt;td&gt;Best safety&lt;/td&gt;
&lt;td&gt;Moderate&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# redis.conf
save 900 1      # Save if 1 key changed in 900 seconds
save 300 10     # Save if 10 keys changed in 300 seconds
appendonly yes  # Enable AOF
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🏗️ Redis Cluster vs Sentinel
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Redis Sentinel (High Availability)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Sentinel 1] [Sentinel 2] [Sentinel 3]  ← monitors
      │
[Primary] ──replicates──► [Replica 1]
                         [Replica 2]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Automatic failover — promotes replica to primary&lt;/li&gt;
&lt;li&gt;No sharding — all data on primary&lt;/li&gt;
&lt;li&gt;Use for: HA without massive scale&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Redis Cluster (Scale + HA)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Node 1: slots 0-5460]     [Replica 1a] [Replica 1b]
[Node 2: slots 5461-10922] [Replica 2a] [Replica 2b]
[Node 3: slots 10923-16383][Replica 3a] [Replica 3b]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;16,384 hash slots distributed across nodes&lt;/li&gt;
&lt;li&gt;Built-in sharding + HA&lt;/li&gt;
&lt;li&gt;Use for: Data larger than single machine's RAM&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🎨 Diagram
&lt;/h2&gt;

&lt;p&gt;The diagram shows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Redis data types illustrated with examples&lt;/li&gt;
&lt;li&gt;Cache-aside pattern&lt;/li&gt;
&lt;li&gt;Redis Sentinel failover&lt;/li&gt;
&lt;li&gt;Redis Cluster slot distribution&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🔑 Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Redis is not just a cache — it's a &lt;strong&gt;data structure server&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Sorted Sets for leaderboards/rankings are a killer feature&lt;/li&gt;
&lt;li&gt;Always set TTLs — unbounded memory growth will kill your Redis&lt;/li&gt;
&lt;li&gt;Use Sentinel for HA, Cluster for scale beyond single-machine RAM&lt;/li&gt;
&lt;/ul&gt;




</description>
      <category>systemdesign</category>
      <category>devops</category>
      <category>backend</category>
      <category>redis</category>
    </item>
    <item>
      <title>Caching Strategies</title>
      <dc:creator>Gouranga Das Samrat</dc:creator>
      <pubDate>Sun, 05 Jul 2026 02:00:00 +0000</pubDate>
      <link>https://dev.to/gouranga-das-khulna/caching-strategies-187h</link>
      <guid>https://dev.to/gouranga-das-khulna/caching-strategies-187h</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;One-liner:&lt;/strong&gt; Caching stores the result of expensive operations (DB queries, API calls, computations) so future requests can be served instantly from fast memory instead of recomputing.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  📌 Why Cache?
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Without cache:
GET /user/42 → DB query (50ms) → response

With cache:
GET /user/42 → Redis lookup (1ms) → response  ← 50x faster!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Rule of thumb: &lt;strong&gt;RAM is ~100x faster than SSD, ~1000x faster than network DB calls.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  🗺️ Caching Layers (From Client to DB)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Browser Cache]          ← HTTP Cache-Control headers
      ↓ miss
[CDN Edge Cache]         ← Cloudflare, CloudFront
      ↓ miss
[Server-side Cache]      ← Redis, Memcached (in-memory)
      ↓ miss
[Database Query Cache]   ← MySQL query cache, Postgres
      ↓ miss
[Database Storage]       ← Actual data on disk
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🔄 Cache Reading Strategies
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Cache-Aside (Lazy Loading) — Most Common
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Read:
1. Check cache → HIT → return data
2. If MISS → query DB → store in cache → return data

Write:
1. Write to DB
2. Invalidate (delete) cache entry
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;cached&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user:&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cached&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cached&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;     &lt;span class="c1"&gt;# cache hit ✅
&lt;/span&gt;
    &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SELECT * FROM users WHERE id = ?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user:&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3600&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;  &lt;span class="c1"&gt;# cache for 1hr
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;✅ Only caches data that's actually requested&lt;br&gt;
✅ Cache failure is tolerable — fall back to DB&lt;br&gt;
❌ Cache miss penalty: 2 trips (cache + DB)&lt;br&gt;
❌ Stale data possible after writes (until TTL or invalidation)&lt;/p&gt;
&lt;h3&gt;
  
  
  Read-Through
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;App → [Cache Layer] → [DB]
       (cache handles the DB lookup on miss)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The cache itself fetches from DB on miss. App only talks to cache.&lt;/p&gt;

&lt;p&gt;✅ Simplified app code&lt;br&gt;
❌ First request is always slow (cold start)&lt;/p&gt;
&lt;h3&gt;
  
  
  Write-Through
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Write → Cache → DB (synchronously)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;On every write, update &lt;strong&gt;both&lt;/strong&gt; cache and DB synchronously.&lt;/p&gt;

&lt;p&gt;✅ Cache always fresh&lt;br&gt;
❌ Higher write latency (must write both)&lt;br&gt;
❌ Writes cache entries that may never be read&lt;/p&gt;
&lt;h3&gt;
  
  
  Write-Behind (Write-Back)
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Write → Cache → ACK to client
                     ↓ (async, later)
                    DB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Write to cache first, asynchronously flush to DB.&lt;/p&gt;

&lt;p&gt;✅ Very fast writes&lt;br&gt;
❌ Risk of data loss if cache crashes before flush&lt;br&gt;
Use case: Analytics counters, view counts, likes&lt;/p&gt;
&lt;h3&gt;
  
  
  Write-Around
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Write → DB (skip cache)
Read  → Cache → if MISS → DB → store in cache
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Writes go directly to DB, bypassing cache. Cache is populated on read.&lt;/p&gt;

&lt;p&gt;✅ Good for write-once, read-many data&lt;br&gt;
❌ First read after write will miss cache&lt;/p&gt;


&lt;h2&gt;
  
  
  ⚠️ Cache Eviction Policies
&lt;/h2&gt;

&lt;p&gt;When cache is full, which items to remove?&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Policy&lt;/th&gt;
&lt;th&gt;How It Works&lt;/th&gt;
&lt;th&gt;Best For&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;LRU&lt;/strong&gt; (Least Recently Used)&lt;/td&gt;
&lt;td&gt;Remove item not accessed for longest&lt;/td&gt;
&lt;td&gt;General purpose (Redis default)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;LFU&lt;/strong&gt; (Least Frequently Used)&lt;/td&gt;
&lt;td&gt;Remove least accessed item&lt;/td&gt;
&lt;td&gt;When access frequency matters&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;FIFO&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Remove oldest inserted item&lt;/td&gt;
&lt;td&gt;Simple use cases&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Random&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Remove random item&lt;/td&gt;
&lt;td&gt;When access pattern is uniform&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;TTL&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Remove items past their expiry&lt;/td&gt;
&lt;td&gt;Time-sensitive data&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;


&lt;h2&gt;
  
  
  🕐 TTL (Time to Live)
&lt;/h2&gt;

&lt;p&gt;Every cache entry should have a TTL — or you risk stale data forever.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Data Type&lt;/th&gt;
&lt;th&gt;Suggested TTL&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;User session&lt;/td&gt;
&lt;td&gt;30 minutes (sliding)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;User profile&lt;/td&gt;
&lt;td&gt;1–5 minutes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Product details&lt;/td&gt;
&lt;td&gt;5–30 minutes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Search results&lt;/td&gt;
&lt;td&gt;1–5 minutes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Homepage content&lt;/td&gt;
&lt;td&gt;1–10 minutes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Static config/flags&lt;/td&gt;
&lt;td&gt;1–24 hours&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rarely changing data&lt;/td&gt;
&lt;td&gt;Days&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;


&lt;h2&gt;
  
  
  💥 Cache Problems
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Cache Stampede (Thundering Herd)
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Popular cache key expires at exactly same time
→ 10,000 concurrent requests all miss cache
→ All hit the DB simultaneously
→ DB crashes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; Probabilistic Early Expiration — randomly refresh before TTL expires:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;remaining_ttl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ttl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;remaining_ttl&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="nf"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;refresh_cache&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# Only 10% of requests refresh early
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or: &lt;strong&gt;Mutex/Lock&lt;/strong&gt; — only one request fetches from DB on miss.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cache Penetration
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Requests for non-existent keys (e.g., userId=-999)
→ Always miss cache
→ Always hit DB
→ DB hammered with useless queries
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; Cache the null result too! &lt;code&gt;redis.setex("user:-999", 60, "NULL")&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Also: &lt;strong&gt;Bloom Filter&lt;/strong&gt; — check if key exists before hitting DB.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cache Avalanche
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Many cache entries expire at the same time
→ Flood of DB queries simultaneously
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; Add jitter (random variation) to TTLs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;ttl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3600&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;randint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# 3600 ± 5 minutes
&lt;/span&gt;&lt;span class="n"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ttl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🔑 Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Default to &lt;strong&gt;Cache-Aside&lt;/strong&gt; for reads — it's the most flexible&lt;/li&gt;
&lt;li&gt;Always set a &lt;strong&gt;TTL&lt;/strong&gt; — never cache indefinitely&lt;/li&gt;
&lt;li&gt;Handle &lt;strong&gt;thundering herd, penetration, and avalanche&lt;/strong&gt; in production&lt;/li&gt;
&lt;li&gt;Cache only data that changes slowly and is read frequently&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>systemdesign</category>
      <category>devops</category>
      <category>backend</category>
      <category>redis</category>
    </item>
    <item>
      <title>Reverse Proxy</title>
      <dc:creator>Gouranga Das Samrat</dc:creator>
      <pubDate>Sat, 04 Jul 2026 02:00:00 +0000</pubDate>
      <link>https://dev.to/gouranga-das-khulna/reverse-proxy-1o0j</link>
      <guid>https://dev.to/gouranga-das-khulna/reverse-proxy-1o0j</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;One-liner:&lt;/strong&gt; A reverse proxy sits in front of your servers, accepting client requests and forwarding them — hiding your actual server infrastructure.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  📌 Forward Proxy vs Reverse Proxy
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Forward Proxy: Client → [Proxy] → Internet
  (client uses proxy to reach internet — hides client)

Reverse Proxy: Client → [Reverse Proxy] → Servers
  (sits in front of servers — hides servers)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🛠️ What Reverse Proxies Do
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Hide internal servers&lt;/strong&gt; — clients never see real IPs&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SSL termination&lt;/strong&gt; — handle HTTPS, pass HTTP internally&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Load balancing&lt;/strong&gt; — distribute across backend servers&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Caching&lt;/strong&gt; — cache responses at proxy level&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compression&lt;/strong&gt; — gzip responses&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Static file serving&lt;/strong&gt; — serve images/CSS/JS directly&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rate limiting&lt;/strong&gt; — basic traffic control&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🆚 Reverse Proxy vs API Gateway vs Load Balancer
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Load Balancer: Distribute traffic (L4 or L7)
Reverse Proxy: Hide servers + SSL + static files + basic routing
API Gateway:   All of above + auth + rate limiting + transformation + monitoring

(In practice: Nginx can do all three)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  📝 Nginx as Reverse Proxy
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;listen&lt;/span&gt; &lt;span class="mi"&gt;443&lt;/span&gt; &lt;span class="s"&gt;ssl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;server_name&lt;/span&gt; &lt;span class="s"&gt;api.myapp.com&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kn"&gt;ssl_certificate&lt;/span&gt; &lt;span class="n"&gt;/etc/ssl/cert.pem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;ssl_certificate_key&lt;/span&gt; &lt;span class="n"&gt;/etc/ssl/key.pem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;# Reverse proxy to Node.js app&lt;/span&gt;
    &lt;span class="kn"&gt;location&lt;/span&gt; &lt;span class="n"&gt;/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_pass&lt;/span&gt; &lt;span class="s"&gt;http://localhost:3000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;Host&lt;/span&gt; &lt;span class="nv"&gt;$host&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;X-Real-IP&lt;/span&gt; &lt;span class="nv"&gt;$remote_addr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;# Serve static files directly (no proxy)&lt;/span&gt;
    &lt;span class="kn"&gt;location&lt;/span&gt; &lt;span class="n"&gt;/static/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kn"&gt;root&lt;/span&gt; &lt;span class="n"&gt;/var/www&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;expires&lt;/span&gt; &lt;span class="s"&gt;1y&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>systemdesign</category>
      <category>architecture</category>
      <category>backend</category>
      <category>devops</category>
    </item>
    <item>
      <title>Load Balancers</title>
      <dc:creator>Gouranga Das Samrat</dc:creator>
      <pubDate>Sun, 28 Jun 2026 02:00:00 +0000</pubDate>
      <link>https://dev.to/gouranga-das-khulna/load-balancers-23k9</link>
      <guid>https://dev.to/gouranga-das-khulna/load-balancers-23k9</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;One-liner:&lt;/strong&gt; A load balancer distributes incoming traffic across multiple servers so no single server becomes a bottleneck.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  📌 Why Load Balancers?
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Without:  [1000 req/sec] → [Server A] 🔥 (overloaded)
                         → [Server B] 💤 (idle)

With LB:  [1000 req/sec] → [Load Balancer]
                               ├──500 req/sec──► [Server A]
                               └──500 req/sec──► [Server B]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Prevents any one server from being overwhelmed&lt;/li&gt;
&lt;li&gt;Enables horizontal scaling&lt;/li&gt;
&lt;li&gt;Provides high availability — removes dead servers from rotation&lt;/li&gt;
&lt;li&gt;SSL termination — offload TLS overhead from app servers&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🔀 Load Balancing Algorithms
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Round Robin
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Request 1 → Server A
Request 2 → Server B
Request 3 → Server C
Request 4 → Server A (cycles back)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;✅ Simple, even distribution&lt;br&gt;
❌ Doesn't account for server load or request weight&lt;/p&gt;
&lt;h3&gt;
  
  
  2. Weighted Round Robin
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Server A (weight 3): gets 3 requests
Server B (weight 1): gets 1 request
Server C (weight 2): gets 2 requests
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;✅ Handles heterogeneous servers&lt;br&gt;
❌ Still doesn't reflect real-time load&lt;/p&gt;
&lt;h3&gt;
  
  
  3. Least Connections
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Server A: 100 active connections
Server B: 20 active connections  ← send here
Server C: 80 active connections
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;✅ Dynamic — adapts to actual load&lt;br&gt;
✅ Great for long-lived connections (WebSockets)&lt;/p&gt;
&lt;h3&gt;
  
  
  4. IP Hash (Sticky Sessions)
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;hash(client_IP) % numServers → always same server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;✅ Session affinity — user always hits same server&lt;br&gt;
❌ Defeats purpose of stateless horizontal scaling&lt;br&gt;
❌ Uneven if many users share same IP (corporate NAT)&lt;/p&gt;
&lt;h3&gt;
  
  
  5. Least Response Time
&lt;/h3&gt;

&lt;p&gt;Routes to the server with the lowest combination of active connections + response time.&lt;/p&gt;
&lt;h3&gt;
  
  
  6. Random with Two Choices (Power of Two)
&lt;/h3&gt;

&lt;p&gt;Pick 2 random servers, send to the one with fewer connections.&lt;br&gt;
✅ Surprisingly close to optimal with very low overhead&lt;/p&gt;


&lt;h2&gt;
  
  
  🏗️ Layer 4 vs Layer 7 Load Balancers
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Layer 4 (Transport Layer)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Works with &lt;strong&gt;TCP/UDP&lt;/strong&gt; (IP addresses + ports)&lt;/li&gt;
&lt;li&gt;Doesn't inspect packet content&lt;/li&gt;
&lt;li&gt;Very fast, low overhead&lt;/li&gt;
&lt;li&gt;Can't route based on URL path or headers
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Sees: IP:port → forward to server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Layer 7 (Application Layer)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Works with &lt;strong&gt;HTTP/HTTPS&lt;/strong&gt; content&lt;/li&gt;
&lt;li&gt;Can route based on URL, headers, cookies&lt;/li&gt;
&lt;li&gt;SSL termination here&lt;/li&gt;
&lt;li&gt;Slower (more processing) but far more powerful
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/api/*  → API servers
/static/* → Static file servers
/ws/*   → WebSocket servers
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Example: Nginx as L7 LB&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;upstream&lt;/span&gt; &lt;span class="s"&gt;api_servers&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;least_conn&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;server&lt;/span&gt; &lt;span class="nf"&gt;10.0.0.1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;server&lt;/span&gt; &lt;span class="nf"&gt;10.0.0.2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;server&lt;/span&gt; &lt;span class="nf"&gt;10.0.0.3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;location&lt;/span&gt; &lt;span class="n"&gt;/api/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="kn"&gt;proxy_pass&lt;/span&gt; &lt;span class="s"&gt;http://api_servers&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="kn"&gt;location&lt;/span&gt; &lt;span class="n"&gt;/static/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="kn"&gt;proxy_pass&lt;/span&gt; &lt;span class="s"&gt;http://cdn_server&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  💓 Health Checks
&lt;/h2&gt;

&lt;p&gt;LB constantly checks if servers are alive:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Passive: Monitor responses — if 5xx for 3 consecutive requests → mark unhealthy
Active:  Send GET /health every 10 seconds → expect 200 OK within 2 seconds
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When a server is unhealthy → LB stops sending traffic. When it recovers → gradually re-added.&lt;/p&gt;




&lt;h2&gt;
  
  
  🔒 SSL Termination
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Client ──[HTTPS]──► Load Balancer ──[HTTP]──► App Servers
         (encrypted)              (unencrypted, internal network)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;App servers don't need SSL certificates&lt;/li&gt;
&lt;li&gt;Reduces CPU overhead on app servers&lt;/li&gt;
&lt;li&gt;Centralized certificate management&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  ⚠️ Load Balancer as SPOF
&lt;/h2&gt;

&lt;p&gt;The LB itself can become a SPOF!&lt;/p&gt;

&lt;p&gt;Solution: &lt;strong&gt;Active-Passive LB Pair&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[LB Primary] ──── health ────► [LB Secondary]
       │                              │
  (active)                    (standby — takes over if primary fails)
       └──────────────────────────────┘
                    VIP (Virtual IP floats between them)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🌍 Real Products
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Product&lt;/th&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Use&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Nginx&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Software L4/L7&lt;/td&gt;
&lt;td&gt;Self-hosted, versatile&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;HAProxy&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Software L4/L7&lt;/td&gt;
&lt;td&gt;High-performance, battle-tested&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;AWS ALB&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Managed L7&lt;/td&gt;
&lt;td&gt;AWS, auto-scaling integration&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;AWS NLB&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Managed L4&lt;/td&gt;
&lt;td&gt;Ultra-high performance, static IPs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cloudflare&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;DNS + L7&lt;/td&gt;
&lt;td&gt;Global, DDoS protection&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  🔑 Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;LBs enable horizontal scaling and eliminate single points of failure&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;L7 LBs&lt;/strong&gt; are more powerful but heavier; &lt;strong&gt;L4 LBs&lt;/strong&gt; are faster&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Least connections&lt;/strong&gt; is usually the best algorithm for dynamic workloads&lt;/li&gt;
&lt;li&gt;The LB itself needs to be made HA (active-passive pair)&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>aws</category>
      <category>systemdesign</category>
      <category>backend</category>
    </item>
    <item>
      <title>CDN — Content Delivery Network</title>
      <dc:creator>Gouranga Das Samrat</dc:creator>
      <pubDate>Sat, 27 Jun 2026 02:00:00 +0000</pubDate>
      <link>https://dev.to/gouranga-das-khulna/cdn-content-delivery-network-1nnd</link>
      <guid>https://dev.to/gouranga-das-khulna/cdn-content-delivery-network-1nnd</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;One-liner:&lt;/strong&gt; A globally distributed network of servers that caches your static content close to users, dramatically reducing latency and offloading traffic from your origin server.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  📌 The Problem
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User in Mumbai → requests image from origin server in US-East
Latency: 200–300ms (round trip across the globe)

Multiply by: every image, CSS file, JS bundle, video chunk...
Result: Slow, painful experience
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  💡 The Solution: CDN
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User in Mumbai → requests image
CDN Edge Node in Mumbai → serves cached image
Latency: 5–20ms (local)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;CDN brings content &lt;strong&gt;closer to users&lt;/strong&gt; by caching it at edge locations worldwide.&lt;/p&gt;




&lt;h2&gt;
  
  
  🗺️ CDN Architecture
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                        [Origin Server - US]
                               │
              ┌────────────────┼────────────────┐
              │                │                │
        [Edge - Mumbai]  [Edge - London]  [Edge - Singapore]
              │
         [User - India] ← 15ms →
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cloudflare has 300+ edge locations. AWS CloudFront has 400+ PoPs (Points of Presence).&lt;/p&gt;




&lt;h2&gt;
  
  
  📦 What CDNs Cache
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Static Assets (Always CDN-appropriate)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Images (JPEG, PNG, WebP, SVG)&lt;/li&gt;
&lt;li&gt;JavaScript bundles (&lt;code&gt;bundle.js&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;CSS files (&lt;code&gt;styles.css&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Fonts (&lt;code&gt;.woff2&lt;/code&gt;, &lt;code&gt;.ttf&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Videos (HLS/DASH streaming chunks)&lt;/li&gt;
&lt;li&gt;HTML (for static sites)&lt;/li&gt;
&lt;li&gt;PDF documents&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Dynamic Content (Advanced CDN features)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;API responses (short TTL — 1–5 minutes)&lt;/li&gt;
&lt;li&gt;Personalized content (with Vary headers)&lt;/li&gt;
&lt;li&gt;HTML with Edge Side Includes (ESI)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🔄 Cache Flow: CDN Request Lifecycle
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Cache HIT (fast path)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User → CDN Edge → Cache HIT → Serve from edge
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Cache MISS (slow path — first request)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User → CDN Edge → Cache MISS
               → Fetch from Origin Server
               → Store in edge cache
               → Serve to user
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Cache INVALIDATION (when you deploy)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You push new bundle.js →
Signal CDN to invalidate old bundle.js →
Next request → MISS → fetches new version → caches it
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  ⏱️ Cache Control Headers
&lt;/h2&gt;

&lt;p&gt;The origin server controls CDN caching via HTTP headers:&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;# Cache for 1 year (immutable assets with content hash in filename)
Cache-Control: public, max-age=31536000, immutable

# Cache for 5 minutes (dynamic-ish content)
Cache-Control: public, max-age=300

# Don't cache (private user data)
Cache-Control: private, no-store

# Cache but validate with server first
Cache-Control: no-cache
ETag: "abc123"
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Filename Hashing Strategy
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bundle.js       → hard to cache long (changes on deploy)
bundle.a3f4c1.js → cache for 1 year (hash changes on deploy)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🔒 CDN Security Features
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;DDoS Protection&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Absorb volumetric attacks at edge (Cloudflare: 150+ Tbps capacity)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;WAF&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Web Application Firewall — block SQLi, XSS at edge&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Bot Protection&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Detect and block malicious bots&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;TLS Termination&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Handle HTTPS at edge globally&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Rate Limiting&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Throttle requests at edge before they hit origin&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Geo-blocking&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Block traffic from specific countries&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  ⚙️ CDN Configuration Example (Cloudflare)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;Page Rules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="err"&gt;*&lt;/span&gt;&lt;span class="s"&gt;.myapp.com/static/*  → Cache Everything, Edge TTL&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1 year&lt;/span&gt;
&lt;span class="err"&gt;*&lt;/span&gt;&lt;span class="s"&gt;.myapp.com/api/*     → Bypass Cache (dynamic)&lt;/span&gt;
&lt;span class="err"&gt;*&lt;/span&gt;&lt;span class="s"&gt;.myapp.com/*.html    → Cache, Edge TTL&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1 hour&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🔄 Push vs Pull CDN
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Pull CDN (Most Common)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Origin server remains the source of truth&lt;/li&gt;
&lt;li&gt;CDN fetches content from origin &lt;strong&gt;on first request&lt;/strong&gt; (cache miss)&lt;/li&gt;
&lt;li&gt;Automatic — no manual upload needed&lt;/li&gt;
&lt;li&gt;Examples: Cloudflare, CloudFront&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Push CDN
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;You explicitly &lt;strong&gt;upload&lt;/strong&gt; content to CDN&lt;/li&gt;
&lt;li&gt;CDN serves it from edge; origin doesn't need to exist for every request&lt;/li&gt;
&lt;li&gt;Good for known, large files (video, software downloads)&lt;/li&gt;
&lt;li&gt;Examples: AWS S3 + CloudFront for uploads, Akamai NetStorage&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🌍 Popular CDN Providers
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Provider&lt;/th&gt;
&lt;th&gt;Strength&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cloudflare&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Best DDoS protection, free tier, 300+ PoPs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;AWS CloudFront&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Deep AWS integration, Lambda@Edge&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Fastly&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Real-time purging, developer-friendly&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Akamai&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Largest network, enterprise&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;BunnyCDN&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Cheap, fast, developer-friendly&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  📊 CDN Impact on Performance
&lt;/h2&gt;

&lt;p&gt;Without CDN (Mumbai user, US origin):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Latency: ~200ms&lt;/li&gt;
&lt;li&gt;Origin bandwidth: 100GB/day&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With CDN:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Latency: ~15ms (13× faster!)&lt;/li&gt;
&lt;li&gt;Cache hit ratio: ~85%&lt;/li&gt;
&lt;li&gt;Origin bandwidth: ~15GB/day (85% reduction)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🎨 Diagram
&lt;/h2&gt;

&lt;p&gt;The diagram shows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;World map with edge nodes&lt;/li&gt;
&lt;li&gt;Cache HIT vs MISS flows&lt;/li&gt;
&lt;li&gt;Origin server → edge propagation&lt;/li&gt;
&lt;li&gt;Cache-Control header on HTTP response&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🔑 Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;CDN = &lt;strong&gt;geographic caching&lt;/strong&gt; — serve content from the closest edge node&lt;/li&gt;
&lt;li&gt;Reduces latency, reduces origin load, handles DDoS&lt;/li&gt;
&lt;li&gt;Use long TTLs + &lt;strong&gt;content hashing&lt;/strong&gt; for static assets&lt;/li&gt;
&lt;li&gt;Most modern apps should use a CDN from day 1 (Cloudflare free tier is excellent)&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>systemdesign</category>
      <category>api</category>
      <category>backend</category>
      <category>webdev</category>
    </item>
    <item>
      <title>API Gateway</title>
      <dc:creator>Gouranga Das Samrat</dc:creator>
      <pubDate>Sun, 21 Jun 2026 02:00:00 +0000</pubDate>
      <link>https://dev.to/gouranga-das-khulna/api-gateway-4dok</link>
      <guid>https://dev.to/gouranga-das-khulna/api-gateway-4dok</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;One-liner:&lt;/strong&gt; A single entry point for all client requests that handles cross-cutting concerns like auth, rate limiting, routing, and logging — so your microservices don't have to.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  📌 The Problem
&lt;/h2&gt;

&lt;p&gt;In a microservices architecture, clients would need to call many services directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Mobile App → auth-service:3001
           → user-service:3002
           → order-service:3003
           → payment-service:3004
           → notification-service:3005
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Problems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Client needs to know every service's address&lt;/li&gt;
&lt;li&gt;Auth logic duplicated in every service&lt;/li&gt;
&lt;li&gt;CORS, rate limiting repeated everywhere&lt;/li&gt;
&lt;li&gt;No single point for monitoring&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  💡 The Solution: API Gateway
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Mobile App ──────────────► [API Gateway]
                                │
                                ├─► auth-service
                                ├─► user-service
                                ├─► order-service
                                └─► payment-service
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The gateway is the &lt;strong&gt;single front door&lt;/strong&gt; to your backend.&lt;/p&gt;




&lt;h2&gt;
  
  
  🛠️ What API Gateways Do
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Request Routing
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;POST /auth/login      → auth-service
GET  /users/:id       → user-service
POST /orders          → order-service
GET  /products        → product-service
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Authentication &amp;amp; Authorization
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Client → [Gateway]
          → Validate JWT token
          → If invalid: 401 Unauthorized (request never hits services)
          → If valid: forward with user context
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Rate Limiting
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User A: 100 requests/min → allow
User A: 101st request    → 429 Too Many Requests
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. SSL Termination
&lt;/h3&gt;

&lt;p&gt;Handles HTTPS at the gateway; internal traffic can be HTTP.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Request/Response Transformation
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;Client&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;sends:&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;span class="nl"&gt;"user_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;123&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;span class="err"&gt;Gateway&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;transforms&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;to:&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;span class="nl"&gt;"userId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"user_123"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"timestamp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"..."&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;h3&gt;
  
  
  6. Load Balancing
&lt;/h3&gt;

&lt;p&gt;Routes to healthy instances of each microservice.&lt;/p&gt;

&lt;h3&gt;
  
  
  7. Caching
&lt;/h3&gt;

&lt;p&gt;Cache responses at the gateway level for frequently accessed data.&lt;/p&gt;

&lt;h3&gt;
  
  
  8. Logging &amp;amp; Monitoring
&lt;/h3&gt;

&lt;p&gt;Single place to log all incoming requests, response times, error rates.&lt;/p&gt;

&lt;h3&gt;
  
  
  9. Circuit Breaking
&lt;/h3&gt;

&lt;p&gt;If a downstream service is failing, stop sending requests → return cached/fallback response.&lt;/p&gt;

&lt;h3&gt;
  
  
  10. API Versioning
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/v1/users → old-user-service (v1)
/v2/users → new-user-service (v2)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🔄 Request Lifecycle Through Gateway
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Client Request
    │
    ▼
[1] SSL Termination
    │
    ▼
[2] Authentication (JWT/OAuth validation)
    │
    ▼
[3] Rate Limiting Check
    │
    ▼
[4] Request Routing (which service?)
    │
    ▼
[5] Request Transformation (headers, body)
    │
    ▼
[6] Forward to Microservice
    │
    ▼
[7] Response Transformation
    │
    ▼
[8] Logging &amp;amp; Metrics
    │
    ▼
Client Response
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  ⚖️ API Gateway vs Load Balancer
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Load Balancer&lt;/th&gt;
&lt;th&gt;API Gateway&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Primary role&lt;/td&gt;
&lt;td&gt;Distribute traffic&lt;/td&gt;
&lt;td&gt;Smart routing + cross-cutting concerns&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Layer&lt;/td&gt;
&lt;td&gt;L4 or L7&lt;/td&gt;
&lt;td&gt;L7 (always)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Authentication&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rate limiting&lt;/td&gt;
&lt;td&gt;Limited&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Request transformation&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Circuit breaking&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Routing by path&lt;/td&gt;
&lt;td&gt;L7 only&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Overhead&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;td&gt;Higher&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;Often used together: LB in front of API Gateway for the gateway's own HA.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  ⚖️ API Gateway vs Reverse Proxy
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Reverse Proxy&lt;/th&gt;
&lt;th&gt;API Gateway&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Purpose&lt;/td&gt;
&lt;td&gt;Forward requests, hide servers&lt;/td&gt;
&lt;td&gt;Orchestrate microservices&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Auth&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Business logic&lt;/td&gt;
&lt;td&gt;Minimal&lt;/td&gt;
&lt;td&gt;Yes (routing rules, transforms)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Example&lt;/td&gt;
&lt;td&gt;Nginx, HAProxy&lt;/td&gt;
&lt;td&gt;Kong, AWS API Gateway&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  🌍 Popular API Gateway Products
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Product&lt;/th&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Best For&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Kong&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Open source&lt;/td&gt;
&lt;td&gt;Self-hosted, plugin ecosystem&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;AWS API Gateway&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Managed&lt;/td&gt;
&lt;td&gt;AWS ecosystem, serverless&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Nginx&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Open source&lt;/td&gt;
&lt;td&gt;Can be configured as gateway&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Traefik&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Open source&lt;/td&gt;
&lt;td&gt;Docker/Kubernetes native&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Apigee&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Enterprise&lt;/td&gt;
&lt;td&gt;Google Cloud, enterprise features&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Azure API Management&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Managed&lt;/td&gt;
&lt;td&gt;Azure ecosystem&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  ⚠️ Gateway Pitfalls
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Pitfall&lt;/th&gt;
&lt;th&gt;Impact&lt;/th&gt;
&lt;th&gt;Fix&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Gateway is SPOF&lt;/td&gt;
&lt;td&gt;If gateway dies, everything dies&lt;/td&gt;
&lt;td&gt;Run multiple instances behind LB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Too much logic in gateway&lt;/td&gt;
&lt;td&gt;Gateway becomes a monolith&lt;/td&gt;
&lt;td&gt;Keep it thin — only cross-cutting concerns&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;High latency&lt;/td&gt;
&lt;td&gt;Every request passes through gateway&lt;/td&gt;
&lt;td&gt;Optimize, cache at gateway, keep logic light&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tight coupling&lt;/td&gt;
&lt;td&gt;Gateway knows too much about services&lt;/td&gt;
&lt;td&gt;Use routing rules, not business logic&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  🎨 Diagram
&lt;/h2&gt;

&lt;p&gt;The diagram shows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Client → Gateway → multiple microservices&lt;/li&gt;
&lt;li&gt;Auth, Rate Limiting, Logging modules inside gateway&lt;/li&gt;
&lt;li&gt;Gateway cluster (multiple instances) behind a load balancer&lt;/li&gt;
&lt;li&gt;Circuit breaker to a failing service&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🔑 Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;API Gateway = &lt;strong&gt;single entry point&lt;/strong&gt; + cross-cutting concerns&lt;/li&gt;
&lt;li&gt;Move auth, rate limiting, logging &lt;strong&gt;out of services&lt;/strong&gt; and into the gateway&lt;/li&gt;
&lt;li&gt;The gateway can become a bottleneck/SPOF — make it HA and keep it lightweight&lt;/li&gt;
&lt;li&gt;Don't put business logic in the gateway — that belongs in services&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>systemdesign</category>
      <category>api</category>
      <category>backend</category>
    </item>
    <item>
      <title>SQL vs NoSQL</title>
      <dc:creator>Gouranga Das Samrat</dc:creator>
      <pubDate>Sat, 20 Jun 2026 02:00:00 +0000</pubDate>
      <link>https://dev.to/gouranga-das-khulna/sql-vs-nosql-f69</link>
      <guid>https://dev.to/gouranga-das-khulna/sql-vs-nosql-f69</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;One-liner:&lt;/strong&gt; SQL databases store data in structured tables with strict schemas; NoSQL databases trade strict consistency for flexibility and horizontal scalability.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  📌 SQL (Relational Databases)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Core Properties
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Structured&lt;/strong&gt; — Data in tables with rows and columns&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Schema&lt;/strong&gt; — Fixed structure, must be defined upfront&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ACID&lt;/strong&gt; — Atomicity, Consistency, Isolation, Durability&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Relations&lt;/strong&gt; — Foreign keys, JOINs across tables&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Query Language&lt;/strong&gt; — SQL (standardized)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Examples
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Database&lt;/th&gt;
&lt;th&gt;Best For&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;PostgreSQL&lt;/td&gt;
&lt;td&gt;Complex queries, JSONB support, general purpose&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MySQL&lt;/td&gt;
&lt;td&gt;Web apps, e-commerce&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SQLite&lt;/td&gt;
&lt;td&gt;Local/embedded, mobile apps&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Oracle&lt;/td&gt;
&lt;td&gt;Enterprise, banking&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MS SQL Server&lt;/td&gt;
&lt;td&gt;Microsoft ecosystem&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  When to Use SQL
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;✅ Complex queries with JOINs&lt;/li&gt;
&lt;li&gt;✅ Strong consistency required (banking, payments)&lt;/li&gt;
&lt;li&gt;✅ Data is relational by nature (users → orders → products)&lt;/li&gt;
&lt;li&gt;✅ ACID transactions needed&lt;/li&gt;
&lt;li&gt;✅ Data structure is well-known and unlikely to change&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  📌 NoSQL (Non-Relational Databases)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Core Properties
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Flexible schema&lt;/strong&gt; — Add/remove fields without migrations&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Horizontally scalable&lt;/strong&gt; — Designed to scale out&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Eventual consistency&lt;/strong&gt; — Usually (some offer strong consistency)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Optimized for specific access patterns&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Types of NoSQL
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. Document Store
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;MongoDB,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;CouchDB,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Firestore&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;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="s2"&gt;"user_123"&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;"Rahul"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"address"&lt;/span&gt;&lt;span class="p"&gt;:&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;span class="nl"&gt;"city"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Delhi"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"pin"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"110001"&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;span class="nl"&gt;"tags"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"premium"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"verified"&lt;/span&gt;&lt;span class="p"&gt;]&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;Best for: User profiles, product catalogs, CMS&lt;/p&gt;

&lt;h4&gt;
  
  
  2. Key-Value Store
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Redis, DynamoDB, Memcached
"session:abc123" → { userId: 42, expiry: ... }
"counter:pageviews" → 1000000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Best for: Sessions, caching, real-time counters, leaderboards&lt;/p&gt;

&lt;h4&gt;
  
  
  3. Column-Family Store
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Cassandra, HBase
Row key → { column1: val, column2: val, column3: val }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Best for: Time-series data, IoT, write-heavy workloads, Netflix viewing history&lt;/p&gt;

&lt;h4&gt;
  
  
  4. Graph Database
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Neo4j, Amazon Neptune
Nodes (Person) → Edges (FOLLOWS) → Nodes (Person)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Best for: Social networks, fraud detection, recommendation engines&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚖️ The Comparison
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dimension&lt;/th&gt;
&lt;th&gt;SQL&lt;/th&gt;
&lt;th&gt;NoSQL&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Schema&lt;/td&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;Flexible&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Horizontal scaling&lt;/td&gt;
&lt;td&gt;Hard&lt;/td&gt;
&lt;td&gt;Easy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Transactions&lt;/td&gt;
&lt;td&gt;Full ACID&lt;/td&gt;
&lt;td&gt;Often eventual consistency&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JOINs&lt;/td&gt;
&lt;td&gt;Easy&lt;/td&gt;
&lt;td&gt;Avoid (denormalize)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Query flexibility&lt;/td&gt;
&lt;td&gt;High (SQL)&lt;/td&gt;
&lt;td&gt;Limited to access patterns&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Learning curve&lt;/td&gt;
&lt;td&gt;Moderate&lt;/td&gt;
&lt;td&gt;Varies by type&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Maturity&lt;/td&gt;
&lt;td&gt;50+ years&lt;/td&gt;
&lt;td&gt;15–20 years&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  🔄 ACID vs BASE
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ACID (SQL)
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Property&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Atomicity&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;All or nothing — transaction either fully succeeds or fully fails&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Consistency&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;DB always goes from one valid state to another&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Isolation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Concurrent transactions don't interfere&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Durability&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Once committed, data survives crashes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  BASE (NoSQL)
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Property&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Basically Available&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;System always responds (maybe stale data)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Soft state&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;State can change over time, even without input&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Eventually consistent&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;System will eventually be consistent&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  🏗️ Choosing Between SQL and NoSQL
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Decision Tree:

Is the data relational?
├── Yes → SQL (start here)
└── No ↓
    Do you need flexible schema?
    ├── Yes → Document (MongoDB)
    └── No ↓
        Is it write-heavy time-series?
        ├── Yes → Column (Cassandra)
        └── No ↓
            Is it graph-traversal heavy?
            ├── Yes → Graph (Neo4j)
            └── No → Key-Value (Redis/DynamoDB)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🌍 Real-World Usage Patterns
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Company&lt;/th&gt;
&lt;th&gt;SQL&lt;/th&gt;
&lt;th&gt;NoSQL&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Uber&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;PostgreSQL (trips)&lt;/td&gt;
&lt;td&gt;Cassandra (location updates)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Netflix&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;MySQL (billing)&lt;/td&gt;
&lt;td&gt;Cassandra (viewing history)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Instagram&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;PostgreSQL (user data)&lt;/td&gt;
&lt;td&gt;Redis (feed cache)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Twitter&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;MySQL&lt;/td&gt;
&lt;td&gt;Redis (timeline), Cassandra (tweets)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Airbnb&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;MySQL&lt;/td&gt;
&lt;td&gt;ElasticSearch (search)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;Most large systems use &lt;strong&gt;both&lt;/strong&gt; — polyglot persistence!&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  🔑 Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Default to SQL&lt;/strong&gt; for new projects — better tooling, stronger guarantees&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Move to NoSQL&lt;/strong&gt; when you hit specific scale/flexibility walls&lt;/li&gt;
&lt;li&gt;Most production systems use &lt;strong&gt;both&lt;/strong&gt; (polyglot persistence)&lt;/li&gt;
&lt;li&gt;NoSQL doesn't mean "no schema" — you still have implicit structure&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>systemdesign</category>
      <category>database</category>
      <category>sql</category>
      <category>nosql</category>
    </item>
    <item>
      <title>Read Replicas</title>
      <dc:creator>Gouranga Das Samrat</dc:creator>
      <pubDate>Sun, 14 Jun 2026 02:00:00 +0000</pubDate>
      <link>https://dev.to/gouranga-das-khulna/read-replicas-48ng</link>
      <guid>https://dev.to/gouranga-das-khulna/read-replicas-48ng</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;One-liner:&lt;/strong&gt; Copies of your primary database that handle read queries, freeing the primary to focus on writes.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  📌 The Problem
&lt;/h2&gt;

&lt;p&gt;Most web applications are &lt;strong&gt;read-heavy&lt;/strong&gt; (80-90% reads, 10-20% writes).&lt;/p&gt;

&lt;p&gt;A single database server handles both reads and writes → becomes a bottleneck.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;All traffic → [Primary DB]
              CPU: 95% 🔥
              Connections: maxed out 🔥
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  💡 The Solution: Read Replicas
&lt;/h2&gt;

&lt;p&gt;Add secondary copies of the database:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Primary&lt;/strong&gt; (Master) → handles all &lt;strong&gt;writes&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Replicas&lt;/strong&gt; (Slaves) → handle all &lt;strong&gt;reads&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[App Server 1] ──write──► [Primary DB] ──replicates──► [Replica 1]
[App Server 2] ──read──►  [Replica 1]                 [Replica 2]
[App Server 3] ──read──►  [Replica 2]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🔄 How Replication Works
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Synchronous Replication
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Write → Primary → waits for Replica ACK → confirms to client
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;✅ Zero data loss — Replica always has latest data&lt;/li&gt;
&lt;li&gt;❌ Higher write latency — must wait for replica confirmation&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Asynchronous Replication
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Write → Primary → confirms to client → replicates to Replica in background
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;✅ Lower write latency&lt;/li&gt;
&lt;li&gt;❌ Replica lag — reads might return slightly stale data&lt;/li&gt;
&lt;li&gt;❌ If primary crashes before replication, data loss possible&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Semi-Synchronous
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Write → Primary → waits for ACK from at least 1 replica → confirms
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Balance between safety and latency (MySQL's default option)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  📊 Replication Lag
&lt;/h2&gt;

&lt;p&gt;Replica lag is the delay between a write on primary and it being visible on replica.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Lag&lt;/th&gt;
&lt;th&gt;Impact&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&amp;lt; 100ms&lt;/td&gt;
&lt;td&gt;Usually fine — imperceptible to users&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;100ms – 1s&lt;/td&gt;
&lt;td&gt;Acceptable for most use cases&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;gt; 1s&lt;/td&gt;
&lt;td&gt;Noticeable — "I just posted but I can't see it" bug&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Minutes&lt;/td&gt;
&lt;td&gt;Data consistency issue — investigate urgently&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Handling Lag in Code
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Read-after-write consistency:&lt;/span&gt;
&lt;span class="c1"&gt;// After a user writes, route their next read to primary&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getUserProfile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;justUpdated&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;justUpdated&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;primaryDB&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SELECT * FROM users WHERE id = ?&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;replicaDB&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SELECT * FROM users WHERE id = ?&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🏗️ Architecture Patterns
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Single Replica (Simple)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Writes → [Primary] → [Replica 1] ← Reads
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Multiple Replicas (Common)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;         [Primary] ──► [Replica 1]  \
Writes →      │    ──► [Replica 2]  ──► Read traffic distributed
              └────► [Replica 3]  /
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Cascading Replicas
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Primary] → [Replica 1] → [Replica 2] → [Replica 3]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Reduces load on primary but increases replica lag.&lt;/p&gt;

&lt;h3&gt;
  
  
  Regional Replicas (Multi-region)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Primary - Mumbai] ──► [Replica - Singapore]
                   ──► [Replica - US-East]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Serve reads from the closest region to the user.&lt;/p&gt;




&lt;h2&gt;
  
  
  🔄 Failover: When Primary Dies
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Detect failure&lt;/strong&gt; — health check fails&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Elect new primary&lt;/strong&gt; — replica with least lag is promoted&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Redirect writes&lt;/strong&gt; — app/load balancer routes writes to new primary&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Old primary rejoins&lt;/strong&gt; — becomes a replica when it comes back
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Before: App → Primary(A) → Replica(B)
Failure: Primary(A) dies
After:  App → Primary(B)   [B promoted]
              ↑
           Replica(A) [A rejoins as replica]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  ⚠️ Read Replica Caveats
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Caveat&lt;/th&gt;
&lt;th&gt;Detail&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Eventual consistency&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Reads may return stale data&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Write bottleneck&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Replicas help reads; writes still limited to primary&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Complex routing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Need to distinguish read vs write queries&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cost&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Each replica = another database server&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  🌍 When to Add Read Replicas
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DB CPU &amp;gt; 70% sustained → add replica
Read:Write ratio &amp;gt; 5:1 → add replica
Reporting queries slowing down app → add dedicated analytics replica
Multi-region users → add geo-replica
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🎨 Diagram
&lt;/h2&gt;

&lt;p&gt;The diagram shows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Primary DB receiving writes&lt;/li&gt;
&lt;li&gt;Replication arrows to 2-3 replicas&lt;/li&gt;
&lt;li&gt;App servers routing reads to replicas&lt;/li&gt;
&lt;li&gt;Failover promotion flow&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🔑 Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Read replicas solve &lt;strong&gt;read scalability&lt;/strong&gt; — writes still bottleneck on primary&lt;/li&gt;
&lt;li&gt;Use &lt;strong&gt;async replication&lt;/strong&gt; for performance, &lt;strong&gt;sync&lt;/strong&gt; for zero data loss&lt;/li&gt;
&lt;li&gt;Always handle &lt;strong&gt;replica lag&lt;/strong&gt; in your application code&lt;/li&gt;
&lt;li&gt;Read replicas are the first step; sharding is the next if writes bottleneck&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>systemdesign</category>
      <category>database</category>
    </item>
    <item>
      <title>Database Sharding</title>
      <dc:creator>Gouranga Das Samrat</dc:creator>
      <pubDate>Sat, 13 Jun 2026 02:00:00 +0000</pubDate>
      <link>https://dev.to/gouranga-das-khulna/database-sharding-2ihl</link>
      <guid>https://dev.to/gouranga-das-khulna/database-sharding-2ihl</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;One-liner:&lt;/strong&gt; Splitting a large database into smaller, independent pieces (shards) spread across multiple machines — each shard holds a subset of the data.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  📌 Why Sharding?
&lt;/h2&gt;

&lt;p&gt;Read replicas help with reads. But what when &lt;strong&gt;writes&lt;/strong&gt; bottleneck?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;10M writes/day → 1 Primary DB can't keep up
Data: 100 TB → 1 server can't store it all
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sharding splits both storage AND write load.&lt;/p&gt;




&lt;h2&gt;
  
  
  💡 How Sharding Works
&lt;/h2&gt;

&lt;p&gt;Imagine a &lt;code&gt;users&lt;/code&gt; table with 100M rows.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Without sharding:&lt;/strong&gt; All 100M rows on one server.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;With sharding (4 shards):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Shard 0: users where userId % 4 = 0  (25M rows)
Shard 1: users where userId % 4 = 1  (25M rows)
Shard 2: users where userId % 4 = 2  (25M rows)
Shard 3: users where userId % 4 = 3  (25M rows)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🔑 Sharding Strategies
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Hash-Based Sharding
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;shard&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;shardKey&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;numShards&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;✅ Even distribution&lt;br&gt;&lt;br&gt;
❌ Adding shards → massive rebalancing (use consistent hashing!)&lt;br&gt;&lt;br&gt;
Best for: User IDs, random keys&lt;/p&gt;
&lt;h3&gt;
  
  
  2. Range-Based Sharding
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Shard 0: userId 1–1,000,000
Shard 1: userId 1,000,001–2,000,000
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;✅ Simple, range queries efficient&lt;br&gt;&lt;br&gt;
❌ Hot spots if data isn't evenly distributed (new users pile into last shard)&lt;br&gt;&lt;br&gt;
Best for: Time-series data (date ranges), ordered data&lt;/p&gt;
&lt;h3&gt;
  
  
  3. Directory-Based Sharding
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Lookup Service / Mapping Table]
userId 1234 → Shard 3
userId 5678 → Shard 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;✅ Most flexible — can move data between shards&lt;br&gt;&lt;br&gt;
❌ Lookup service becomes bottleneck / SPOF&lt;br&gt;&lt;br&gt;
Best for: When data movement between shards is needed&lt;/p&gt;
&lt;h3&gt;
  
  
  4. Geographic Sharding
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Users in India    → Shard-India  (Mumbai)
Users in US       → Shard-US     (Virginia)
Users in Europe   → Shard-EU     (Frankfurt)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;✅ Low latency for users&lt;br&gt;&lt;br&gt;
❌ Cross-shard queries for global reports&lt;br&gt;&lt;br&gt;
Best for: Multi-region products with data residency requirements&lt;/p&gt;


&lt;h2&gt;
  
  
  🔑 Choosing a Shard Key
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The most critical decision in sharding.&lt;/strong&gt; A bad shard key causes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Hot spots&lt;/strong&gt; — all traffic goes to one shard&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Uneven data&lt;/strong&gt; — one shard is 10× larger&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cross-shard joins&lt;/strong&gt; — expensive queries&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Good Shard Key Properties
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Property&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;High cardinality&lt;/td&gt;
&lt;td&gt;Many unique values → even distribution&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Low correlation&lt;/td&gt;
&lt;td&gt;Shouldn't correlate with access patterns&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Immutable&lt;/td&gt;
&lt;td&gt;Changing it means moving data between shards&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Frequently queried&lt;/td&gt;
&lt;td&gt;Queries can be routed to one shard&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h3&gt;
  
  
  Common Shard Keys
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;System&lt;/th&gt;
&lt;th&gt;Shard Key&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;User data&lt;/td&gt;
&lt;td&gt;&lt;code&gt;userId&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multi-tenant SaaS&lt;/td&gt;
&lt;td&gt;&lt;code&gt;tenantId&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Messages&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;conversationId&lt;/code&gt; or &lt;code&gt;userId&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Orders&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;customerId&lt;/code&gt; or &lt;code&gt;orderId&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Time-series&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;timestamp&lt;/code&gt; + &lt;code&gt;deviceId&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;


&lt;h2&gt;
  
  
  ⚠️ Sharding Challenges
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Cross-Shard Queries
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- This is easy on 1 DB:&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt; &lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;userId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;

&lt;span class="c1"&gt;-- With sharding: users on Shard 0, orders on Shard 1 → expensive cross-shard join!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Solutions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Denormalize data (store redundant user info in orders table)&lt;/li&gt;
&lt;li&gt;Application-level joins (fetch from each shard, merge in code)&lt;/li&gt;
&lt;li&gt;Co-locate related data on same shard (order and user on same shard)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Rebalancing
&lt;/h3&gt;

&lt;p&gt;Adding a new shard → need to move data → expensive operation&lt;/p&gt;

&lt;p&gt;Solution: &lt;strong&gt;Consistent hashing&lt;/strong&gt; minimizes data movement&lt;/p&gt;
&lt;h3&gt;
  
  
  Hot Spots
&lt;/h3&gt;

&lt;p&gt;Celebrity/viral content — 90% of requests go to one shard.&lt;/p&gt;

&lt;p&gt;Solution: &lt;strong&gt;Key splitting&lt;/strong&gt; — split the hot key across multiple shards with a suffix:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;tweet:viral_id_0, tweet:viral_id_1, tweet:viral_id_2 ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🏗️ Sharding Architecture
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[App Server] → [Shard Router / Proxy Layer]
                    │
          ┌────────┼────────┐
       [Shard 0] [Shard 1] [Shard 2]
          │          │         │
       [Replica] [Replica] [Replica]  (each shard also has replicas!)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🆚 Sharding vs Partitioning
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Term&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Sharding&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Horizontal partitioning across &lt;strong&gt;different machines&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Partitioning&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Splitting data within &lt;strong&gt;one machine&lt;/strong&gt; (e.g., PostgreSQL table partitions)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Start with partitioning (within one DB), then shard when you need cross-machine scale.&lt;/p&gt;




&lt;h2&gt;
  
  
  🎨 Diagram
&lt;/h2&gt;

&lt;p&gt;The diagram shows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Shard router receiving queries&lt;/li&gt;
&lt;li&gt;Hash-based routing to 3 shards&lt;/li&gt;
&lt;li&gt;Each shard with its own replica&lt;/li&gt;
&lt;li&gt;Cross-shard join problem highlighted in red&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🔑 Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Sharding splits &lt;strong&gt;both data and write load&lt;/strong&gt; across machines&lt;/li&gt;
&lt;li&gt;Shard key choice is &lt;strong&gt;irreversible&lt;/strong&gt; — choose carefully&lt;/li&gt;
&lt;li&gt;Start with &lt;strong&gt;vertical scaling → read replicas → sharding&lt;/strong&gt; (don't jump to sharding early)&lt;/li&gt;
&lt;li&gt;Every large database (DynamoDB, Cassandra, MongoDB) shards internally for you&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>database</category>
      <category>systemdesign</category>
      <category>sql</category>
      <category>postgres</category>
    </item>
    <item>
      <title>🥧 314 Trillion Digits of Pi: The Software Engineering Secrets Behind y-cruncher</title>
      <dc:creator>Gouranga Das Samrat</dc:creator>
      <pubDate>Thu, 11 Jun 2026 04:00:00 +0000</pubDate>
      <link>https://dev.to/gouranga-das-khulna/314-trillion-digits-of-pi-the-software-engineering-secrets-behind-y-cruncher-5ddp</link>
      <guid>https://dev.to/gouranga-das-khulna/314-trillion-digits-of-pi-the-software-engineering-secrets-behind-y-cruncher-5ddp</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;How a high school project became the most dominant Pi-computing benchmark in the world — and what every software engineer can learn from it.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;If someone told you a single program could stress-test your CPU, RAM, and storage simultaneously, recover from hardware failures mid-computation, run for &lt;strong&gt;110 days straight&lt;/strong&gt;, and spit out 314 trillion digits of Pi at the end — you'd probably assume it was built by a team of PhDs at a national lab.&lt;/p&gt;

&lt;p&gt;It was built by one person. It started as a high school project. And it's been setting world records since 2009.&lt;/p&gt;

&lt;p&gt;This is y-cruncher. Let's talk about it.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Even Is y-cruncher?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="http://www.numberworld.org/y-cruncher/" rel="noopener noreferrer"&gt;y-cruncher&lt;/a&gt; is a multi-threaded, SIMD-vectorized program that computes mathematical constants — Pi, e, square roots, and more — to trillions of decimal digits. It's the tool of choice for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;World record Pi computations&lt;/strong&gt; (every record since 2009 has used it)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CPU stress testing and overclocking validation&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Memory subsystem benchmarking&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hardware stability detection&lt;/strong&gt; (it'll find flaws that Prime95 and AIDA64 miss)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As of November 2025, the current world record stands at &lt;strong&gt;314 trillion digits&lt;/strong&gt;, computed in a single uninterrupted 110-day run on a 384-core AMD EPYC server. The verification took just 4.37 hours.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Should a Software Engineer Care?
&lt;/h2&gt;

&lt;p&gt;Fair question. You're probably not computing Pi for a living. But y-cruncher is a goldmine of fascinating engineering decisions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It exploits &lt;strong&gt;SIMD instruction sets&lt;/strong&gt; (SSE, AVX, AVX-512) at a level most production software never touches&lt;/li&gt;
&lt;li&gt;Its &lt;strong&gt;checkpoint-restart system&lt;/strong&gt; is a masterclass in fault-tolerant distributed computation&lt;/li&gt;
&lt;li&gt;It implements &lt;strong&gt;custom memory allocators&lt;/strong&gt; that outperform the OS for specific access patterns&lt;/li&gt;
&lt;li&gt;It demonstrates how &lt;strong&gt;multi-socket NUMA topology&lt;/strong&gt; wreaks havoc on parallel performance — and how to fight back&lt;/li&gt;
&lt;li&gt;Its benchmark results expose the &lt;strong&gt;memory bandwidth ceiling&lt;/strong&gt; that most workloads never hit but y-cruncher constantly runs into&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In short: reading about y-cruncher will make you a better systems programmer, even if you never run it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Getting Started: Installation in Under 2 Minutes
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Windows
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Download &lt;code&gt;y-cruncher v0.8.7.9547b.zip&lt;/code&gt; from the &lt;a href="http://www.numberworld.org/y-cruncher/" rel="noopener noreferrer"&gt;official site&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Extract and run &lt;code&gt;y-cruncher.exe&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;You may need the &lt;a href="https://aka.ms/vs/17/release/vc_redist.x64.exe" rel="noopener noreferrer"&gt;MSVC redistributable&lt;/a&gt; if you see DLL errors&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Antivirus false positives are common due to the low-level SIMD code. The binary is safe — but the static-linked version was reworked specifically to reduce false positives.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Linux
&lt;/h3&gt;

&lt;p&gt;Choose between two variants based on your needs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Static — most portable, works on nearly any distro, no TBB/NUMA binding&lt;/span&gt;
wget http://www.numberworld.org/y-cruncher/y-cruncher&lt;span class="se"&gt;\ &lt;/span&gt;v0.8.7.9547-static.tar.xz
&lt;span class="nb"&gt;tar&lt;/span&gt; &lt;span class="nt"&gt;-xf&lt;/span&gt; &lt;span class="s2"&gt;"y-cruncher v0.8.7.9547-static.tar.xz"&lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;y-cruncher_v0.8.7.9547-static
./y-cruncher

&lt;span class="c"&gt;# Dynamic — full features (NUMA binding, TBB) but requires Ubuntu 24.04+ or compatible&lt;/span&gt;
wget http://www.numberworld.org/y-cruncher/y-cruncher&lt;span class="se"&gt;\ &lt;/span&gt;v0.8.7.9547-dynamic.tar.xz
&lt;span class="nb"&gt;tar&lt;/span&gt; &lt;span class="nt"&gt;-xf&lt;/span&gt; &lt;span class="s2"&gt;"y-cruncher v0.8.7.9547-dynamic.tar.xz"&lt;/span&gt;
./y-cruncher
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;System requirements:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;64-bit x86/x64 processor&lt;/li&gt;
&lt;li&gt;Windows 8+ or any 64-bit Linux distro&lt;/li&gt;
&lt;li&gt;RAM: as much as you can get — more is almost always better&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Running Your First Benchmark
&lt;/h2&gt;

&lt;p&gt;When you launch y-cruncher, you'll get a console menu. For benchmarking:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Select &lt;strong&gt;"Benchmark"&lt;/strong&gt; from the main menu&lt;/li&gt;
&lt;li&gt;Choose a size (start with &lt;strong&gt;250 million&lt;/strong&gt; or &lt;strong&gt;1 billion&lt;/strong&gt; digits — comfortable for most modern desktops)&lt;/li&gt;
&lt;li&gt;Watch it go&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;What you'll see reported:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Computation mode : Ram Only
Decimal Digits   : 1,000,000,000
Hexadecimal Digits: 830,482,023

Start Date       : ...
End Date         : ...

Total Computation Time : 14.670 seconds
Total Verification Time: 10.421 seconds
Total Time             : 25.091 seconds
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt; "Total Computation Time" is the relevant benchmark number. "Total Time" includes verification, which is a separate algorithmic pass.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  What are "good" numbers?
&lt;/h3&gt;

&lt;p&gt;Here's a quick reference for 1 billion digits on common hardware (lower = better):&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Hardware&lt;/th&gt;
&lt;th&gt;Time (seconds)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Ryzen 9 9950X (16C, DDR5-6000)&lt;/td&gt;
&lt;td&gt;~14.7s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Intel Core i9-13900KS&lt;/td&gt;
&lt;td&gt;~15.9s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ryzen 9 7950X (16C, DDR5-5200)&lt;/td&gt;
&lt;td&gt;~16.8s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ryzen 9 3950X (16C, DDR4-3200)&lt;/td&gt;
&lt;td&gt;~29.5s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Core i7-11800H (laptop, 60W)&lt;/td&gt;
&lt;td&gt;~32.3s&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If your number is significantly higher than expected for your hardware, it's usually a memory configuration issue (see below).&lt;/p&gt;




&lt;h2&gt;
  
  
  The Memory Bandwidth Trap: Why Your Expensive CPU Might Be Underperforming
&lt;/h2&gt;

&lt;p&gt;This is one of the most practically useful things y-cruncher teaches.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;y-cruncher is memory-bound.&lt;/strong&gt; Almost completely. On every high-end desktop since ~2012, the CPU sits and waits for data. This means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;GHz doesn't matter as much as memory bandwidth&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Unpopulated DIMM slots hurt you more than you think&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Memory frequency matters enormously&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Real benchmark showing this on a Core i9-7940X:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Memory speed&lt;/th&gt;
&lt;th&gt;10 billion digit time&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;DDR4-2666&lt;/td&gt;
&lt;td&gt;365 seconds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DDR4-3466&lt;/td&gt;
&lt;td&gt;322 seconds&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;That's a &lt;strong&gt;~12% speedup&lt;/strong&gt; just from faster RAM on the &lt;em&gt;same CPU&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  How to maximize memory bandwidth for y-cruncher
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Checklist:&lt;/span&gt;
&lt;span class="c"&gt;# 1. Populate ALL memory channels&lt;/span&gt;
&lt;span class="c"&gt;#    (4-channel platform = use 4 DIMMs, not 2)&lt;/span&gt;

&lt;span class="c"&gt;# 2. Enable XMP/EXPO in BIOS&lt;/span&gt;
&lt;span class="c"&gt;#    Most DDR4/DDR5 kits ship at JEDEC defaults (3200/4800)&lt;/span&gt;
&lt;span class="c"&gt;#    XMP can push to 6000+ MT/s on DDR5&lt;/span&gt;

&lt;span class="c"&gt;# 3. On Skylake-X specifically: also overclock L3 cache&lt;/span&gt;
&lt;span class="c"&gt;#    (L3 bandwidth is an additional bottleneck on that architecture)&lt;/span&gt;

&lt;span class="c"&gt;# 4. Enable Large Pages (Windows)&lt;/span&gt;
&lt;span class="c"&gt;#    Run y-cruncher as Administrator for this to work&lt;/span&gt;
&lt;span class="c"&gt;#    Post-Spectre/Meltdown mitigations cause up to 5% overhead&lt;/span&gt;
&lt;span class="c"&gt;#    Large pages bypass the problematic page table walk&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  The Engineering Marvel: Checkpoint-Restart
&lt;/h2&gt;

&lt;p&gt;Here's what separates y-cruncher from just being a fast calculator.&lt;/p&gt;

&lt;p&gt;Computing 300 trillion digits of Pi takes &lt;strong&gt;months&lt;/strong&gt;. On commodity hardware. With power outages, kernel panics, memory errors, and cosmic ray bit flips all waiting to destroy your work.&lt;/p&gt;

&lt;p&gt;y-cruncher's solution is a robust checkpoint-restart system that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Periodically snapshots computation state to disk&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Verifies checkpoints with redundancy checks&lt;/strong&gt; (catching hardware bit errors before they propagate)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resumes automatically after any interruption&lt;/strong&gt; — even after software bugs in y-cruncher itself have been fixed and the computation re-started&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Several world record computations have &lt;em&gt;survived bugs in y-cruncher itself&lt;/em&gt; because the checkpoint infrastructure caught the error, allowed a fix, and resumed from the last valid state. That's some serious fault tolerance engineering.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The 314 trillion digit record in November 2025 is remarkable specifically because it was the first recent record achieved &lt;em&gt;without&lt;/em&gt; checkpointing — a single uninterrupted 110-day run. This is described as Storage Review's third attempt; the previous two were stopped by hardware/software issues.&lt;/p&gt;

&lt;p&gt;For the software engineers in the room: this is a production-grade distributed systems problem solved elegantly in a desktop application.&lt;/p&gt;




&lt;h2&gt;
  
  
  Advanced: The NUMA Problem (And Why Multi-Socket Is Hard)
&lt;/h2&gt;

&lt;p&gt;If you're running y-cruncher on a workstation with two CPUs — or benchmarking cloud instances — pay attention.&lt;/p&gt;

&lt;p&gt;On multi-socket (NUMA) systems, memory access latency and bandwidth are &lt;em&gt;asymmetric&lt;/em&gt;. Core 0 on Socket 0 reaches Socket 0's RAM in ~80ns. It reaches Socket 1's RAM in ~140ns. If your threads are spread across both sockets but chasing the same data, you'll hit contention that tanks throughput.&lt;/p&gt;

&lt;p&gt;y-cruncher's documentation is explicit about this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Benchmark numbers on multi-socket machines "may not be entirely representative of what the hardware is capable of"&lt;/li&gt;
&lt;li&gt;The Push Pool vs Cilk Plus scheduler choice matters for machines with &amp;gt;64 cores&lt;/li&gt;
&lt;li&gt;Node-interleaving in the BIOS should be &lt;em&gt;disabled&lt;/em&gt; on Windows systems with &amp;gt;64 logical cores (otherwise you get imbalanced processor groups)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The load imbalance symptoms to watch for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Core count is not a power of two&lt;/li&gt;
&lt;li&gt;Cores are heterogeneous (hybrid architectures like Intel's P+E core designs)&lt;/li&gt;
&lt;li&gt;Background processes stealing cycles from any single thread&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Using y-cruncher for Stress Testing (The Real Killer App)
&lt;/h2&gt;

&lt;p&gt;Many overclockers and hardware enthusiasts use y-cruncher &lt;em&gt;specifically&lt;/em&gt; because it's uniquely good at exposing instability:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;It simultaneously maxes out CPU computation AND the entire memory subsystem.&lt;/strong&gt; Most stress tests only hit one or the other. y-cruncher hits both at the same time.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The telltale error you'll see on unstable hardware:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Redundancy Check Failed: Coefficient is too large
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This means the two independent algorithmic passes (compute + verify) produced different results — which means either the CPU computed something wrong, or memory delivered corrupted data.&lt;/p&gt;

&lt;p&gt;If you see this on a machine you thought was stable: &lt;strong&gt;don't ignore it.&lt;/strong&gt; This is y-cruncher doing exactly what it's designed to do.&lt;/p&gt;

&lt;p&gt;Common causes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;RAM running at XMP/EXPO speeds without sufficient voltage&lt;/li&gt;
&lt;li&gt;CPU overclocked too aggressively (especially with AVX offsets not set)&lt;/li&gt;
&lt;li&gt;Thermal throttling corrupting in-flight computation&lt;/li&gt;
&lt;li&gt;Subtimings too tight on the memory controller&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Understanding the Algorithms (For the Curious)
&lt;/h2&gt;

&lt;p&gt;y-cruncher uses two independent algorithms for most constants:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Computation pass:&lt;/strong&gt; Chudnovsky algorithm for Pi (exponentially converging series). Each term adds ~14.18 digits of Pi. The challenge is computing this in arbitrary precision — which requires implementing arithmetic on numbers with &lt;em&gt;trillions of digits&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Verification pass:&lt;/strong&gt; A different formula (e.g., Ramanujan's formula, or Bailey-Borwein-Plouffe variants) to independently confirm the result. If both passes agree to the last digit, the result is almost certainly correct.&lt;/p&gt;

&lt;p&gt;The interesting engineering is in the big number arithmetic:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Uses &lt;strong&gt;Number Theoretic Transforms&lt;/strong&gt; (NTTs) — the modular arithmetic equivalent of FFTs — for multiplication&lt;/li&gt;
&lt;li&gt;Exploits &lt;strong&gt;SIMD vector units&lt;/strong&gt; (AVX-512 on modern hardware) to parallelize the transform butterflies&lt;/li&gt;
&lt;li&gt;Implements &lt;strong&gt;cache-oblivious algorithms&lt;/strong&gt; for better memory access patterns during the transform&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The result: multiplication of two N-digit numbers in O(N log N) time instead of O(N²). At a trillion digits, this difference is the gap between "computationally feasible" and "computationally impossible."&lt;/p&gt;




&lt;h2&gt;
  
  
  Practical Takeaways for Software Engineers
&lt;/h2&gt;

&lt;p&gt;Whether you run y-cruncher or never touch it, here's what to take away:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Memory bandwidth is often your real bottleneck.&lt;/strong&gt; Profile for it. Don't just assume your algorithm is CPU-bound.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Fault tolerance is a first-class feature.&lt;/strong&gt; The world record wouldn't exist without checkpoint-restart. Think about what your long-running jobs do when a node dies.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. NUMA topology changes everything in parallel code.&lt;/strong&gt; Thread affinity and memory locality matter more than raw core count on multi-socket systems.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. SIMD is still a performance multiplier worth understanding.&lt;/strong&gt; A 4× speedup from AVX-2 or 8× from AVX-512 is not unusual for data-parallel numerical code. Compilers help, but hand-tuning helps more.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Stress test with something that actually stresses.&lt;/strong&gt; y-cruncher's simultaneous CPU + memory load finds problems that single-threaded or DRAM-only tests miss entirely.&lt;/p&gt;




&lt;h2&gt;
  
  
  Where to Go From Here
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Download y-cruncher:&lt;/strong&gt; &lt;a href="http://www.numberworld.org/y-cruncher/" rel="noopener noreferrer"&gt;numberworld.org/y-cruncher&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub mirror:&lt;/strong&gt; Available for HTTPS downloads (linked from the main site)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Benchmarks leaderboard:&lt;/strong&gt; Rankings from 25 million to 1 trillion digits are published on the site&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Advanced docs:&lt;/strong&gt; The site has deep documentation on multi-threading internals, memory allocation strategies, and swap mode configuration&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mersenneforum subforum:&lt;/strong&gt; For discussion with the community doing record-level runs&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;The fact that a program started as a high school project now drives the world's most demanding computational records — and teaches systems programmers lessons about memory bandwidth, fault tolerance, NUMA, and SIMD — is genuinely inspiring.&lt;/p&gt;

&lt;p&gt;Go run it. Break your overclock. Then fix it and run it again.&lt;/p&gt;




</description>
      <category>cpp</category>
      <category>algorithms</category>
      <category>computerscience</category>
      <category>performance</category>
    </item>
    <item>
      <title>pkg.go.dev Finally Has an Official API — No More Web Scraping</title>
      <dc:creator>Gouranga Das Samrat</dc:creator>
      <pubDate>Wed, 10 Jun 2026 04:00:00 +0000</pubDate>
      <link>https://dev.to/gouranga-das-khulna/pkggodev-finally-has-an-official-api-no-more-web-scraping-25cj</link>
      <guid>https://dev.to/gouranga-das-khulna/pkggodev-finally-has-an-official-api-no-more-web-scraping-25cj</guid>
      <description>&lt;p&gt;If you've ever built a Go tool that needed package metadata — documentation, versions, symbols, import counts — you already know the pain. You were either scraping the pkg.go.dev HTML (fragile, bad, and you knew it), or you were guessing from local filesystem data and hoping for the best.&lt;/p&gt;

&lt;p&gt;The Go team just shipped a real fix for this: an official pkg.go.dev API.&lt;/p&gt;

&lt;p&gt;Let's look at what it actually does.&lt;/p&gt;




&lt;h2&gt;
  
  
  What's Available
&lt;/h2&gt;

&lt;p&gt;The API lives under &lt;code&gt;/v1beta&lt;/code&gt; and covers the main things you'd actually need:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Endpoint&lt;/th&gt;
&lt;th&gt;What it gives you&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/v1beta/package/{path}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Package metadata&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/v1beta/module/{path}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Module metadata&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/v1beta/versions/{path}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;All versions of a module&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/v1beta/packages/{path}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;All packages in a module&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/v1beta/search?q={query}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Search results&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/v1beta/symbols/{path}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Exported symbols&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/v1beta/imported-by/{path}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;What imports this package&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/v1beta/vulns/{path}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Known vulnerabilities&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;v1beta&lt;/code&gt; label is honest — it's not finalized yet. But the team has committed to moving toward a stable &lt;code&gt;v1&lt;/code&gt; after a feedback period, and they're promising backward compatibility going forward.&lt;/p&gt;




&lt;h2&gt;
  
  
  Quick Start: Hit It With curl
&lt;/h2&gt;

&lt;p&gt;No auth, no setup. Just GET requests:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl https://pkg.go.dev/v1beta/package/github.com/google/go-cmp/cmp | jq &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;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;"modulePath"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"github.com/google/go-cmp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"v0.7.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"isLatest"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"isStandardLibrary"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"goos"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"all"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"goarch"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"all"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"github.com/google/go-cmp/cmp"&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;"cmp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"synopsis"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Package cmp determines equality of values."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"isRedistributable"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&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;You can pin a specific version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="s2"&gt;"https://pkg.go.dev/v1beta/package/github.com/google/go-cmp/cmp?version=v0.6.0"&lt;/span&gt; | jq &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or use &lt;code&gt;master&lt;/code&gt; / &lt;code&gt;main&lt;/code&gt; branch names, which resolve automatically to their pseudo-version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="s2"&gt;"https://pkg.go.dev/v1beta/package/github.com/google/go-cmp/cmp?version=master"&lt;/span&gt; | jq &lt;span class="s1"&gt;'{path, version}'&lt;/span&gt;
&lt;span class="c"&gt;# {&lt;/span&gt;
&lt;span class="c"&gt;#   "path": "github.com/google/go-cmp/cmp",&lt;/span&gt;
&lt;span class="c"&gt;#   "version": "v0.7.1-0.20260310220054-34c9473539b8"&lt;/span&gt;
&lt;span class="c"&gt;# }&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  One Gotcha: Module Paths Must Be Unambiguous
&lt;/h2&gt;

&lt;p&gt;This tripped me up when I first read the docs. The API follows a "precision over convenience" rule that differs from the web UI.&lt;/p&gt;

&lt;p&gt;On the website, if you type &lt;code&gt;example.com/a/b/c&lt;/code&gt;, it resolves to the longest matching module path automatically. The API won't do that. If &lt;code&gt;example.com/a/b/c&lt;/code&gt; could live in either &lt;code&gt;example.com/a&lt;/code&gt; or &lt;code&gt;example.com/a/b&lt;/code&gt;, the API returns an error and asks you to be more specific.&lt;/p&gt;

&lt;p&gt;Makes sense for programmatic use — you don't want silent resolution surprises in a tool. Just something to plan for when you're building integrations.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Reference CLI: &lt;code&gt;pkgsite-cli&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;The Go team also shipped a reference client you can install and start using immediately:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go &lt;span class="nb"&gt;install &lt;/span&gt;golang.org/x/pkgsite/cmd/internal/pkgsite-cli@latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Search for packages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pkgsite-cli search &lt;span class="s2"&gt;"uuid"&lt;/span&gt;
&lt;span class="c"&gt;# github.com/google/uuid&lt;/span&gt;
&lt;span class="c"&gt;#   Module:   github.com/google/uuid@v1.6.0&lt;/span&gt;
&lt;span class="c"&gt;#   Synopsis: Package uuid generates and inspects UUIDs.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inspect a package:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pkgsite-cli package github.com/google/go-cmp/cmp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;See what imports a package:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pkgsite-cli package &lt;span class="nt"&gt;--imported-by&lt;/span&gt; github.com/google/go-cmp/cmp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;List exported symbols:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pkgsite-cli package &lt;span class="nt"&gt;--symbols&lt;/span&gt; github.com/google/go-cmp/cmp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;List all versions of a module:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pkgsite-cli module &lt;span class="nt"&gt;-versions&lt;/span&gt; github.com/google/go-cmp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Worth noting: the CLI interface is explicitly marked as unstable — it's a reference implementation, not a finished product. Use it to understand the API, not as a dependency in scripts you care about.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why This Matters Now
&lt;/h2&gt;

&lt;p&gt;The "years of community feedback" line in the announcement is underselling it. Go tooling has had a real data access gap for a long time. Custom linters, documentation generators, dependency analyzers, IDE plugins — all of them were either scraping or going without.&lt;/p&gt;

&lt;p&gt;The announcement also mentions AI-assisted coding tools specifically, and that's probably the real driver here. Tools that reason about your dependencies need structured, reliable data about packages. Scraping doesn't cut it when you want a language server to tell you something accurate about a module it's never seen before.&lt;/p&gt;

&lt;p&gt;An OpenAPI spec is published too, so generating clients in any language is straightforward.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I'd Use This For
&lt;/h2&gt;

&lt;p&gt;A few things come to mind immediately:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dependency audits&lt;/strong&gt; — pull vulnerability data via &lt;code&gt;/v1beta/vulns/{path}&lt;/code&gt; for every module in your &lt;code&gt;go.sum&lt;/code&gt; without spinning up a full &lt;code&gt;govulncheck&lt;/code&gt; run.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Import graph tooling&lt;/strong&gt; — the &lt;code&gt;/v1beta/imported-by&lt;/code&gt; endpoint makes it practical to build tools that understand downstream impact of an API change.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Documentation bots&lt;/strong&gt; — fetch synopsis and symbol data for packages your team uses, feed it wherever you need it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Version tracking&lt;/strong&gt; — watch specific modules for new releases without polling GitHub.&lt;/p&gt;




&lt;h2&gt;
  
  
  The State of It
&lt;/h2&gt;

&lt;p&gt;It's a &lt;code&gt;v1beta&lt;/code&gt;. The endpoints work, the data is good, and the team is clearly committed to making this a real stable API. But I wouldn't bet a production pipeline on the exact response shape staying identical until &lt;code&gt;v1&lt;/code&gt; lands.&lt;/p&gt;

&lt;p&gt;For internal tooling and experiments? Use it today. For anything you're shipping to other people? Keep an eye on the issue tracker and wait for &lt;code&gt;v1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Go give it a curl. The &lt;a href="https://pkg.go.dev/api" rel="noopener noreferrer"&gt;full API spec&lt;/a&gt; and &lt;a href="https://pkg.go.dev/api" rel="noopener noreferrer"&gt;OpenAPI definition&lt;/a&gt; are live now.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Feedback and bug reports go to the &lt;a href="https://github.com/golang/pkgsite/issues" rel="noopener noreferrer"&gt;pkgsite issue tracker&lt;/a&gt;. The team specifically asked for community feedback before the v1 freeze, so this is a good time to poke at edge cases.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>go</category>
      <category>opensource</category>
      <category>programming</category>
      <category>api</category>
    </item>
  </channel>
</rss>
