<?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: Piyush Gupta</title>
    <description>The latest articles on DEV Community by Piyush Gupta (@piyush6348).</description>
    <link>https://dev.to/piyush6348</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F12063%2F16835832.jpeg</url>
      <title>DEV Community: Piyush Gupta</title>
      <link>https://dev.to/piyush6348</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/piyush6348"/>
    <language>en</language>
    <item>
      <title>Master-Class: Sending Real-Time Updates from Server to Clients: Server to Server, Android, iOS</title>
      <dc:creator>Piyush Gupta</dc:creator>
      <pubDate>Sat, 25 Apr 2026 14:28:47 +0000</pubDate>
      <link>https://dev.to/piyush6348/master-class-sending-real-time-updates-from-server-to-clients-server-to-server-android-ios-10cg</link>
      <guid>https://dev.to/piyush6348/master-class-sending-real-time-updates-from-server-to-clients-server-to-server-android-ios-10cg</guid>
      <description>&lt;p&gt;Real-time communication is now a cornerstone of modern software. Whether you're showing live scores, streaming AI responses, pushing a payment confirmation to a phone, or propagating an event between two microservices — the underlying question is the same: &lt;em&gt;how does the server reach the client before the client asks?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The answer looks very different depending on who the client is. A backend server, an Android device, and an iPhone each live in fundamentally different environments, face different constraints, and have completely different ecosystems waiting to solve this problem. This article walks through each scenario in depth — the concepts, the practical tooling, and real code.&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 1: The Mental Model — Push vs. Poll
&lt;/h2&gt;

&lt;p&gt;Before jumping into techniques, it's worth understanding why this is even hard.&lt;/p&gt;

&lt;p&gt;HTTP was originally designed around a simple request-response cycle: the client asks, the server answers, connection closes. This works perfectly for loading a webpage but is deeply mismatched for "tell me when something changes." Developers have historically compensated in two ways:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Polling&lt;/strong&gt; — the client repeatedly asks the server "anything new?" on a timer. Simple to implement, universally supported, but wasteful. You're spending bandwidth and compute on mostly-empty responses.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Long polling&lt;/strong&gt; — a refinement where the server holds the request open until it actually has something to say, then responds, and the client immediately reconnects. Better latency than polling, but it still creates a new HTTP connection per event, adding overhead and complicating server logic. It was common in the 2000s and early 2010s and is now largely regarded as a legacy fallback.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Push&lt;/strong&gt; — the server maintains an open channel and sends data down it whenever necessary. This is the modern standard, and the rest of this article is about how it's done in practice.&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 2: Server to Server
&lt;/h2&gt;

&lt;p&gt;When the "client" is another server or backend service, you have the most flexibility. There's no battery to drain, no mobile OS gating the connection, and no user permission dialogs. The ecosystem here splits broadly into two families: &lt;strong&gt;persistent streaming connections&lt;/strong&gt; and &lt;strong&gt;asynchronous messaging&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  WebSockets
&lt;/h3&gt;

&lt;p&gt;WebSockets establish a full-duplex, persistent TCP connection via an HTTP upgrade handshake. Once the handshake completes, either side can send frames at any time with minimal overhead — no HTTP headers are re-sent per message.&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="nf"&gt;GET&lt;/span&gt; &lt;span class="nn"&gt;/chat&lt;/span&gt; &lt;span class="k"&gt;HTTP&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="m"&gt;1.1&lt;/span&gt;
&lt;span class="na"&gt;Host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;server.example.com&lt;/span&gt;
&lt;span class="na"&gt;Upgrade&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;websocket&lt;/span&gt;
&lt;span class="na"&gt;Connection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Upgrade&lt;/span&gt;
&lt;span class="na"&gt;Sec-WebSocket-Key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dGhlIHNhbXBsZSBub25jZQ==&lt;/span&gt;

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After this exchange, the connection is a raw duplex channel. A Node.js server using the popular &lt;code&gt;ws&lt;/code&gt; library looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Server (Node.js)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;WebSocket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ws&lt;/span&gt;&lt;span class="dl"&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;wss&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;WebSocket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;8080&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;wss&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;connection&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;ws&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="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Client connected&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Push data to the client at any time&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;interval&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;setInterval&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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;readyState&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;WebSocket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OPEN&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&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;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;update&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;getLatestMetrics&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;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;close&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;clearInterval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;interval&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Client (Python)
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;websockets&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;websockets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ws://server.example.com:8080&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&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;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="nf"&gt;print&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;Received: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;data&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="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;WebSockets are the right choice when you need low latency, bidirectional messaging, or binary data. The tradeoff is that they require stateful servers — you can't just put a standard load balancer in front without sticky sessions or a shared pub/sub layer (Redis is commonly used for this).&lt;/p&gt;

&lt;h3&gt;
  
  
  Server-Sent Events (SSE)
&lt;/h3&gt;

&lt;p&gt;SSE is a simpler, HTTP-based protocol for one-directional streaming from server to client. The server responds with &lt;code&gt;Content-Type: text/event-stream&lt;/code&gt; and never closes the connection, sending data in a simple text format:&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="err"&gt;data:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"price_update"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;142.50&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;\n\n&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;data:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"price_update"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;143.10&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;\n\n&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each event is separated by a blank line. Events can also carry an &lt;code&gt;id&lt;/code&gt; field for resumption after reconnects, and a named &lt;code&gt;event&lt;/code&gt; field for routing on the client.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Server (Node.js / Express)&lt;/span&gt;
&lt;span class="nx"&gt;app&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/events&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;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&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="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&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="s1"&gt;text/event-stream&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Cache-Control&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="s1"&gt;no-cache&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Connection&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="s1"&gt;keep-alive&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;X-Accel-Buffering&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="s1"&gt;no&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Critical for Nginx&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sendEvent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&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="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`id: &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="s2"&gt;\n`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`data: &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;data&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;\n\n`&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;interval&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;setInterval&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;sendEvent&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;metrics&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;getMetrics&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt; &lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;close&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;clearInterval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;interval&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Client consuming SSE (Python)
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sseclient&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;

&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&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="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;http://server.example.com/events&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sseclient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SSEClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;events&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="nf"&gt;print&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;Received event: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;SSE has built-in automatic reconnection — if the connection drops, the client will reconnect and send the last received event ID, allowing the server to resume from where it left off. However, SSE only transmits UTF-8 text and is strictly unidirectional. For server-to-server communication where the receiving service only needs to consume a stream of events, SSE is a lighter-weight and simpler choice than WebSockets.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Important gotcha:&lt;/strong&gt; corporate proxies and some CDN/reverse proxy configurations buffer SSE streams silently, making events arrive in batches rather than in real time. The &lt;code&gt;X-Accel-Buffering: no&lt;/code&gt; header fixes this for Nginx, but intermediaries you don't control remain a problem. For server-to-server communication within a private network, this is rarely an issue.&lt;/p&gt;

&lt;h3&gt;
  
  
  gRPC Streaming
&lt;/h3&gt;

&lt;p&gt;gRPC is Google's open-source RPC framework, built on HTTP/2 and Protocol Buffers. It supports four communication patterns, including &lt;strong&gt;server streaming&lt;/strong&gt; — where the client makes one request and the server streams back a sequence of responses.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight protobuf"&gt;&lt;code&gt;&lt;span class="c1"&gt;// service.proto&lt;/span&gt;
&lt;span class="na"&gt;syntax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"proto3"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;service&lt;/span&gt; &lt;span class="n"&gt;MetricsService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Client sends one request, server streams many responses&lt;/span&gt;
  &lt;span class="k"&gt;rpc&lt;/span&gt; &lt;span class="n"&gt;StreamMetrics&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MetricsRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;returns&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt; &lt;span class="n"&gt;MetricsResponse&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;message&lt;/span&gt; &lt;span class="nc"&gt;MetricsRequest&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="na"&gt;service_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;message&lt;/span&gt; &lt;span class="nc"&gt;MetricsResponse&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="na"&gt;cpu_usage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="na"&gt;memory_usage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kt"&gt;int64&lt;/span&gt; &lt;span class="na"&gt;timestamp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Server (Python)
&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MetricsServicer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MetricsService&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;StreamMetrics&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;is_active&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
            &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="nc"&gt;MetricsResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;cpu_usage&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;get_cpu&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
                &lt;span class="n"&gt;memory_usage&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;get_memory&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
                &lt;span class="n"&gt;timestamp&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;time&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// Client (Go)&lt;/span&gt;
&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StreamMetrics&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;MetricsRequest&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ServiceName&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"api"&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Recv&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;err&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EOF&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;break&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"CPU: %.2f%%, Memory: %.2f%%&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CpuUsage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MemoryUsage&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;p&gt;gRPC is particularly well-suited for internal microservice communication. Binary serialization via Protocol Buffers makes it fast and compact. HTTP/2 multiplexing allows many streams over one connection. The strongly typed contract enforced by &lt;code&gt;.proto&lt;/code&gt; files also provides excellent developer ergonomics in polyglot architectures.&lt;/p&gt;

&lt;h3&gt;
  
  
  Message Queues and Pub/Sub Brokers
&lt;/h3&gt;

&lt;p&gt;For asynchronous delivery — where the receiving server doesn't need to be online at the moment the event is produced — message brokers are the standard approach. They decouple the producer from the consumer and provide durability, retry logic, and fan-out.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Apache Kafka&lt;/strong&gt; is the dominant choice for high-throughput event streaming. It persists events to disk in ordered, replayable logs called topics. Consumers can catch up from any offset, making it excellent for architectures that need auditability or event sourcing.&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="c1"&gt;# Producer (Python)
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;kafka&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;KafkaProducer&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;

&lt;span class="n"&gt;producer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;KafkaProducer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;bootstrap_servers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;kafka:9092&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;value_serializer&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;v&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;v&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;producer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;user-events&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;event&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;checkout&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;user_id&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;u123&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;amount&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;49.99&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="n"&gt;producer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;flush&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;# Consumer
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;kafka&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;KafkaConsumer&lt;/span&gt;
&lt;span class="n"&gt;consumer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;KafkaConsumer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;user-events&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;bootstrap_servers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;kafka:9092&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;value_deserializer&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;m&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;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;consumer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;process_event&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&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;p&gt;&lt;strong&gt;RabbitMQ&lt;/strong&gt; is better suited for task queues and flexible routing. It supports exchanges with different routing modes — direct, fanout, topic, and headers — and is widely used for work queues where each message should be processed by exactly one consumer.&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="c1"&gt;# Publisher (Python / pika)
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pika&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;

&lt;span class="n"&gt;connection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pika&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;BlockingConnection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pika&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ConnectionParameters&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;rabbitmq&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;channel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exchange_declare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;exchange&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;notifications&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;exchange_type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;fanout&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;basic_publish&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;exchange&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;notifications&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;routing_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="o"&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="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;payment_confirmed&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;order_id&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ord_789&lt;/span&gt;&lt;span class="sh"&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;p&gt;&lt;strong&gt;Webhooks&lt;/strong&gt; deserve a mention here as well. Rather than the consumer server maintaining a persistent connection, the producer simply makes an HTTP POST to a pre-registered URL whenever an event occurs. This is the dominant pattern for third-party integrations (payment processors, GitHub events, Stripe, Twilio, etc.) because it requires no persistent infrastructure on either side. The tradeoff is that the receiving endpoint must be publicly reachable and the producer must handle retries.&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 3: Server to Android
&lt;/h2&gt;

&lt;p&gt;Android introduces meaningful constraints. Maintaining a persistent TCP connection in the background drains the battery, and Android's OS actively restricts background work. The ecosystem has converged on a clear stack.&lt;/p&gt;

&lt;h3&gt;
  
  
  Firebase Cloud Messaging (FCM)
&lt;/h3&gt;

&lt;p&gt;FCM is the de facto standard for reaching Android devices from a server. It is Google's cloud-based messaging infrastructure that handles the persistent connection to every Android device so your server doesn't have to.&lt;/p&gt;

&lt;p&gt;The architecture involves three parties: your application server, the FCM infrastructure, and the device. Your server sends a payload to FCM's API; FCM routes it to the target device using a persistent, battery-optimized connection maintained by Google Play Services.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The flow:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The Android app registers with FCM on first launch and receives a unique registration token.&lt;/li&gt;
&lt;li&gt;The app sends this token to your backend and stores it (typically in a database keyed to the user).&lt;/li&gt;
&lt;li&gt;When your server needs to push an update, it posts to FCM's HTTP v1 API with the target token and message payload.&lt;/li&gt;
&lt;li&gt;FCM delivers the message to the device, waking the app if necessary.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Android — FirebaseMessagingService&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyFirebaseMessagingService&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;FirebaseMessagingService&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;// Called when FCM generates a new token (on first install or token refresh)&lt;/span&gt;
    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onNewToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onNewToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c1"&gt;// Send token to your backend so it can reach this device&lt;/span&gt;
        &lt;span class="nf"&gt;sendTokenToServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Called when a message arrives while app is in foreground&lt;/span&gt;
    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onMessageReceived&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;remoteMessage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;RemoteMessage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;remoteMessage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isNotEmpty&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;let&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;updateType&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;remoteMessage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;payload&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;remoteMessage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"payload"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="nf"&gt;handleUpdate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;updateType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;payload&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;span class="p"&gt;}&lt;/span&gt;
&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="c1"&gt;// Server — sending via FCM HTTP v1 API (Node.js)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;admin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;firebase-admin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;admin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;initializeApp&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;credential&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;admin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;credential&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;serviceAccount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;});&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;sendUpdate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;deviceToken&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&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;admin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;messaging&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;deviceToken&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;order_update&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;orderId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ord_789&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;shipped&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;android&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;priority&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;high&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;ttl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3600&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt; &lt;span class="c1"&gt;// 1 hour&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;p&gt;FCM supports two message types. &lt;strong&gt;Notification messages&lt;/strong&gt; are handled automatically by the system — Android displays them in the notification tray without any app code running, which is what most apps use for alerts. &lt;strong&gt;Data messages&lt;/strong&gt; deliver a custom key-value payload to your app's &lt;code&gt;onMessageReceived&lt;/code&gt; handler, giving you full control over how to process and display the update. You can combine both in a single message.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Token management&lt;/strong&gt; is a detail that trips up many implementations. Tokens change when the user reinstalls the app, clears data, or on certain OS events. Your server must handle the &lt;code&gt;UNREGISTERED&lt;/code&gt; error from FCM and remove stale tokens, and your app must call &lt;code&gt;onNewToken&lt;/code&gt; to push refreshed tokens to the backend.&lt;/p&gt;

&lt;h3&gt;
  
  
  WebSockets on Android (Foreground Only)
&lt;/h3&gt;

&lt;p&gt;For apps that need real-time streaming &lt;em&gt;while the user is actively using them&lt;/em&gt; — a live chat, a trading terminal, a GPS tracker — WebSockets work well on Android. The standard library is OkHttp, which is already a transitive dependency in most Android projects.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Android WebSocket with OkHttp&lt;/span&gt;
&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;client&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OkHttpClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Builder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pingInterval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;TimeUnit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SECONDS&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// Keep-alive pings&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;request&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Builder&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"wss://api.example.com/stream"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;listener&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;object&lt;/span&gt; &lt;span class="err"&gt;: &lt;/span&gt;&lt;span class="nc"&gt;WebSocketListener&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onOpen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;webSocket&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;WebSocket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;webSocket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"""{"action": "subscribe", "channel": "updates"}"""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;webSocket&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;WebSocket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;update&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parseUpdate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;runOnUiThread&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;updateUI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;update&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;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onFailure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;webSocket&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;WebSocket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Throwable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Implement exponential backoff reconnection here&lt;/span&gt;
        &lt;span class="nf"&gt;scheduleReconnect&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;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;webSocket&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;newWebSocket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;listener&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The critical caveat is lifecycle. Android will kill background services, and a WebSocket in a paused or stopped app is unreliable. For anything that needs to work when the app is not in the foreground, FCM is the right tool.&lt;/p&gt;

&lt;h3&gt;
  
  
  MQTT — For IoT and Low-Bandwidth Scenarios
&lt;/h3&gt;

&lt;p&gt;MQTT is a lightweight publish/subscribe protocol designed for constrained devices. It runs over TCP and uses a small binary format, making it efficient on poor networks. Apps using Eclipse Paho or HiveMQ client libraries subscribe to topics on a broker; any server can publish to those topics.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Android MQTT with Paho&lt;/span&gt;
&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;client&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MqttAndroidClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"tcp://broker.example.com:1883"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;clientId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;client&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="s"&gt;"sensors/temperature/#"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;topic&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;payload&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;updateSensorDisplay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;topic&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;payload&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;p&gt;MQTT is particularly common in IoT applications where devices are battery-powered or on metered connections, and where the update cadence is high (sensor data every second, for example). For mainstream consumer apps, FCM is a simpler path.&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 4: Server to iOS
&lt;/h2&gt;

&lt;p&gt;iOS has the most controlled environment of the three. Apple enforces strict rules on background execution and network usage, all in service of battery life and user privacy. The practical ecosystem is narrow but well-designed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Apple Push Notification service (APNs)
&lt;/h3&gt;

&lt;p&gt;APNs is the only sanctioned way to send server-initiated updates to an iOS device when the app is not in the foreground. There is no alternative. Just like FCM on Android, APNs maintains a persistent, encrypted connection to every Apple device so third-party servers don't have to.&lt;/p&gt;

&lt;p&gt;The flow mirrors FCM in structure but differs in the details:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The iOS app requests permission from the user to receive notifications.&lt;/li&gt;
&lt;li&gt;On approval, it calls &lt;code&gt;UIApplication.shared.registerForRemoteNotifications()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;iOS registers with APNs and returns a device token to &lt;code&gt;application(_:didRegisterForRemoteNotificationsWithDeviceToken:)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The app sends this token to your backend.&lt;/li&gt;
&lt;li&gt;Your server constructs a JSON payload and sends it to APNs over HTTP/2, authenticated with a JWT signed by your APNs key.&lt;/li&gt;
&lt;li&gt;APNs delivers the notification to the device.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;// AppDelegate.swift&lt;/span&gt;
&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;application&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;application&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;UIApplication&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                 &lt;span class="n"&gt;didFinishLaunchingWithOptions&lt;/span&gt; &lt;span class="nv"&gt;launchOptions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;UIApplication&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;LaunchOptionsKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;]?)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;center&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;UNUserNotificationCenter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;current&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;center&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;requestAuthorization&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sound&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;badge&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;granted&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
        &lt;span class="k"&gt;guard&lt;/span&gt; &lt;span class="n"&gt;granted&lt;/span&gt; &lt;span class="k"&gt;else&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="kt"&gt;DispatchQueue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;UIApplication&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shared&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;registerForRemoteNotifications&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;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;application&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;application&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;UIApplication&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                 &lt;span class="n"&gt;didRegisterForRemoteNotificationsWithDeviceToken&lt;/span&gt; &lt;span class="nv"&gt;deviceToken&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;deviceToken&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;format&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"%02.2hhx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;joined&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;sendTokenToBackend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;application&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;application&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;UIApplication&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                 &lt;span class="n"&gt;didReceiveRemoteNotification&lt;/span&gt; &lt;span class="nv"&gt;userInfo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;AnyHashable&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                 &lt;span class="n"&gt;fetchCompletionHandler&lt;/span&gt; &lt;span class="nv"&gt;completionHandler&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;@escaping&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;UIBackgroundFetchResult&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;CompletionHandler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Handle silent background update&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;userInfo&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;as?&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;handleSilentUpdate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
            &lt;span class="nf"&gt;completionHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&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;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;APNs payload structure:&lt;/strong&gt;&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;"aps"&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;"alert"&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;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Order Shipped"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"body"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Your order #789 has been dispatched."&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;"sound"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"default"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"badge"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&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;"order_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;"ord_789"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"shipped"&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;For &lt;strong&gt;silent background updates&lt;/strong&gt; — where you want to update the app's data without showing a visible notification — use &lt;code&gt;content-available: 1&lt;/code&gt; with no &lt;code&gt;alert&lt;/code&gt; key and set the priority to 5 (low priority):&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;"aps"&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;"content-available"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&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;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"cache_refresh"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"product_catalog"&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;&lt;strong&gt;Authentication:&lt;/strong&gt; Apple strongly recommends using APNs authentication keys (&lt;code&gt;.p8&lt;/code&gt; files) over the older certificate-based approach. Keys never expire and one key works across all your apps in a team.&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="c1"&gt;# Server — sending to APNs (Python with httpx + PyJWT)
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;jwt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;httpx&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create_apns_jwt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;team_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;private_key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&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;jwt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;iss&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;team_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;iat&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()},&lt;/span&gt;
        &lt;span class="n"&gt;private_key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;algorithm&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ES256&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;alg&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ES256&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;kid&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;key_id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;send_apns_notification&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;device_token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;create_apns_jwt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;KEY_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TEAM_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;PRIVATE_KEY&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&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;https://api.push.apple.com/3/device/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;device_token&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;httpx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;AsyncClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http2&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;authorization&lt;/span&gt;&lt;span class="sh"&gt;"&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;bearer &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;token&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;apns-topic&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;com.example.myapp&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;apns-push-type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;alert&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;apns-priority&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;10&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;payload&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;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that APNs &lt;strong&gt;requires HTTP/2&lt;/strong&gt;. The &lt;code&gt;httpx&lt;/code&gt; library with &lt;code&gt;[http2]&lt;/code&gt; extras, or Apple's own &lt;code&gt;apns2&lt;/code&gt; libraries in various languages, handle this correctly.&lt;/p&gt;

&lt;h3&gt;
  
  
  WebSockets on iOS (Foreground)
&lt;/h3&gt;

&lt;p&gt;For in-app real-time features, iOS 13+ ships &lt;code&gt;URLSessionWebSocketTask&lt;/code&gt; natively, eliminating the need for third-party libraries for basic use cases.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Native WebSocket (iOS 13+)&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;RealtimeManager&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;webSocketTask&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;URLSessionWebSocketTask&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;URLSession&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;configuration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;string&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"wss://api.example.com/stream"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;
        &lt;span class="n"&gt;webSocketTask&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;webSocketTask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;with&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;webSocketTask&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resume&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;receiveMessage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;receiveMessage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;webSocketTask&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;receive&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;weak&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
            &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;success&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;message&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;text&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                    &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;handleUpdate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                    &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;handleBinaryUpdate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="kd"&gt;@unknown&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;break&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;receiveMessage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// Continue listening&lt;/span&gt;
            &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;failure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;error&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;scheduleReconnect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;after&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;3.0&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;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;disconnect&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;webSocketTask&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cancel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;with&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;goingAway&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;reason&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;nil&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;p&gt;For older iOS versions or more complex scenarios (automatic reconnection, heartbeats, channel-based pub/sub), libraries like &lt;strong&gt;Starscream&lt;/strong&gt; are commonly used.&lt;/p&gt;

&lt;h3&gt;
  
  
  Combining APNs with In-App Streaming
&lt;/h3&gt;

&lt;p&gt;A well-architected iOS app typically uses both: APNs for background/offline delivery, and WebSockets for in-app streaming. The logic at the app level checks whether a WebSocket connection is active; if so, the update arrives via that channel. If not, APNs wakes the app or delivers a visible notification. Firebase SDKs handle this abstraction automatically when you use the FCM SDK on iOS, routing through APNs under the hood.&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 5: Choosing the Right Approach
&lt;/h2&gt;

&lt;p&gt;Here's a practical decision guide based on what the software community actually uses:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Scenario&lt;/th&gt;
&lt;th&gt;Recommended Approach&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Server → Server (low latency, bidirectional)&lt;/td&gt;
&lt;td&gt;WebSockets or gRPC streaming&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Server → Server (one-way stream)&lt;/td&gt;
&lt;td&gt;SSE or gRPC server streaming&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Server → Server (async, durable)&lt;/td&gt;
&lt;td&gt;Kafka (high throughput) or RabbitMQ (task routing)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Server → Third-party service&lt;/td&gt;
&lt;td&gt;Webhooks (HTTP POST)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Server → Android (background)&lt;/td&gt;
&lt;td&gt;FCM&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Server → Android (foreground, in-app)&lt;/td&gt;
&lt;td&gt;WebSocket (OkHttp)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Server → iOS (background/offline)&lt;/td&gt;
&lt;td&gt;APNs (directly or via FCM SDK)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Server → iOS (foreground, in-app)&lt;/td&gt;
&lt;td&gt;URLSessionWebSocketTask or Starscream&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Server → IoT devices&lt;/td&gt;
&lt;td&gt;MQTT&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Part 6: Production Considerations
&lt;/h2&gt;

&lt;p&gt;Regardless of which technology you pick, several cross-cutting concerns determine whether a real-time system actually holds up in production.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reconnection and resilience.&lt;/strong&gt; Networks fail. Connections drop. Every client implementation needs exponential backoff reconnection logic. SSE and FCM handle this automatically; WebSocket implementations on mobile must do it manually. On the server side, design your event delivery to be idempotent — clients may receive the same event more than once after a reconnect.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Missed events.&lt;/strong&gt; Persistent connections mean that events produced while a client was offline can be missed. SSE's &lt;code&gt;Last-Event-ID&lt;/code&gt; header helps for short outages. For mobile, FCM stores up to 100 messages per device and delivers them when the device comes back online (subject to TTL). For critical business events, use a separate REST endpoint the client can call after reconnecting to fetch the state it missed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scalability.&lt;/strong&gt; A single server can maintain tens of thousands of WebSocket connections, but as you scale horizontally, you need a shared pub/sub layer so that a message produced on Server A can reach a client connected to Server B. Redis Pub/Sub and Redis Streams are the most common solutions for this. Kafka is used when you need durability and replay.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Security.&lt;/strong&gt; WebSocket connections should always use &lt;code&gt;wss://&lt;/code&gt; (TLS). APNs and FCM connections are encrypted by their respective platforms. JWT or session tokens should be validated during the WebSocket/SSE handshake, not just at connection time. For APNs, rotate your &lt;code&gt;.p8&lt;/code&gt; key if it is ever exposed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Token hygiene for mobile.&lt;/strong&gt; Device tokens (both FCM and APNs) change and expire. Build logic to handle registration errors returned by FCM (&lt;code&gt;UNREGISTERED&lt;/code&gt;) and APNs (&lt;code&gt;BadDeviceToken&lt;/code&gt;, &lt;code&gt;Unregistered&lt;/code&gt;) and remove stale tokens from your database immediately. Sending to dead tokens wastes quota and can trigger rate limiting.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Real-time server-to-client communication is not a single technology but a landscape of tools, each optimized for a specific environment and use case. WebSockets and SSE dominate server-to-server streaming; gRPC streaming is the preferred choice in microservice architectures; message brokers like Kafka and RabbitMQ handle asynchronous event propagation at scale. On Android, FCM is the unambiguous standard for background delivery, augmented by WebSockets for in-app streaming. On iOS, everything routes through APNs for background delivery, while &lt;code&gt;URLSessionWebSocketTask&lt;/code&gt; handles the foreground case.&lt;/p&gt;

&lt;p&gt;The key insight is that mobile operating systems impose constraints that make "just keep a connection open" untenable for background use — which is precisely why platform-managed push infrastructure (FCM, APNs) exists. For server-to-server communication where those constraints don't apply, you have far more freedom, and the choice comes down to latency requirements, directionality, durability needs, and operational complexity you're willing to take on.&lt;/p&gt;

&lt;p&gt;Pick the smallest, most appropriate tool for each client type, build reconnection and missed-event recovery into every path, and your real-time system will be robust regardless of what the network throws at it.&lt;/p&gt;

</description>
      <category>systemdesign</category>
      <category>backend</category>
      <category>communication</category>
    </item>
    <item>
      <title>Top 5 FREE Resources to Master DSA (Stop Paying for Coding Bootcamps! 💸)</title>
      <dc:creator>Piyush Gupta</dc:creator>
      <pubDate>Fri, 17 Apr 2026 08:00:00 +0000</pubDate>
      <link>https://dev.to/piyush6348/top-5-free-resources-to-master-dsa-stop-paying-for-coding-bootcamps--24pd</link>
      <guid>https://dev.to/piyush6348/top-5-free-resources-to-master-dsa-stop-paying-for-coding-bootcamps--24pd</guid>
      <description>&lt;p&gt;One of the biggest myths in tech is that you need a $500+ "Elite" course to pass Big Tech interviews. In reality, the best engineers often use the exact same free resources available to everyone.&lt;/p&gt;

&lt;p&gt;Based on the &lt;a href="https://youtu.be/P-91Xe8ov8w" rel="noopener noreferrer"&gt;latest guide from Engineer Talks&lt;/a&gt;, here are the top 5 free resources and a proven strategy to master DSA from scratch.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Master Strategy: Don't "Resource Hop" 🚫
&lt;/h2&gt;

&lt;p&gt;Before we dive in, remember this: &lt;strong&gt;Mastering one resource is better than finishing 10% of five different ones.&lt;/strong&gt; Stick to a plan and finish the curriculum before moving on.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. &lt;a href="https://www.youtube.com/@Pepcoding/playlists" rel="noopener noreferrer"&gt;Pepcoding&lt;/a&gt; (Best for Learning Concepts) 🎓
&lt;/h2&gt;

&lt;p&gt;If you are a beginner or find certain topics (like Dynamic Programming) confusing, start here.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Why it works:&lt;/strong&gt; The explanations break down complex logic into understandable segments. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Starting Point:&lt;/strong&gt; Check out the &lt;strong&gt;"Level 1" playlist&lt;/strong&gt; for a complete scratch-to-pro journey.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deep Dives:&lt;/strong&gt; They have specialized playlists for Linked Lists, Binary Trees, and DP that are goldmines for interview prep.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  2. &lt;a href="https://leetcode.com/" rel="noopener noreferrer"&gt;LeetCode&lt;/a&gt; (The Practice Standard) 💻
&lt;/h2&gt;

&lt;p&gt;This is the industry standard for coding practice. Use it to transition from "understanding" a concept to "implementing" it under constraints.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Filtering:&lt;/strong&gt; Use tags to solve topic-wise problems and sort by difficulty (Start with Easy, move to Medium).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Discussion Forum:&lt;/strong&gt; If your code is slow, the discussion tab is where you learn how to optimize time and space complexity from the community.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  3. &lt;a href="https://www.geeksforgeeks.org/interview-experiences/google-interview-questions/" rel="noopener noreferrer"&gt;GeeksforGeeks&lt;/a&gt; (The Company Specific Cheat Code) 🏢
&lt;/h2&gt;

&lt;p&gt;GFG is unbeatable when it comes to &lt;strong&gt;Company-Specific&lt;/strong&gt; preparation.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Strategy:&lt;/strong&gt; Two weeks before your interview with a specific company, go to GFG and read their "Interview Experiences".&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Patterns:&lt;/strong&gt; This helps you identify the specific types of questions a company likes to ask (e.g., Amazon loves Trees; Google loves Graphs).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  4. &lt;a href="https://www.interviewbit.com/" rel="noopener noreferrer"&gt;InterviewBit&lt;/a&gt; (The Time-Management Tool) ⏱️
&lt;/h2&gt;

&lt;p&gt;In a real interview, you usually have 45 minutes to solve 2 problems. Speed and accuracy matter.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Timed Practice:&lt;/strong&gt; InterviewBit forces you to solve problems against a clock, simulating the pressure of a real interview.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pro Tip:&lt;/strong&gt; Find a question on GFG to understand it, then find the same question on InterviewBit to solve it under time pressure.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  5. &lt;a href="https://www.techiedelight.com/" rel="noopener noreferrer"&gt;Techie Delight&lt;/a&gt; (For "Off-Road" Problems) 🛠️
&lt;/h2&gt;

&lt;p&gt;Once you have exhausted LeetCode or want a fresh challenge, Techie Delight offers unique problems that don't always appear on mainstream platforms. It's a great "final boss" resource before you start your actual interview loop.&lt;/p&gt;




&lt;h3&gt;
  
  
  Honorable Mentions 🎖️
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://www.youtube.com/user/mycodeschool" rel="noopener noreferrer"&gt;MyCodeSchool&lt;/a&gt;:&lt;/strong&gt; One of the best places for absolute beginners to learn about Pointers, Recursion, and basic Sorting [00:07:09].&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  My Recommended Roadmap:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Learn&lt;/strong&gt; core concepts from &lt;strong&gt;Pepcoding&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Practice&lt;/strong&gt; implementation on &lt;strong&gt;LeetCode&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Refine&lt;/strong&gt; your speed on &lt;strong&gt;InterviewBit&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Target&lt;/strong&gt; specific companies using &lt;strong&gt;GeeksforGeeks&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;&lt;strong&gt;Which resource helped you the most in your last interview? Let’s share the knowledge in the comments!&lt;/strong&gt; 👇&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Inspired by the Engineer Talks guide on free DSA resources. &lt;a href="https://youtu.be/P-91Xe8ov8w" rel="noopener noreferrer"&gt;Watch the full video here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>dsa</category>
      <category>interviewprep</category>
      <category>career</category>
      <category>programming</category>
    </item>
    <item>
      <title>Master-Class: Scaling Databases with Sharding, Partitioning, and Consistent Hashing</title>
      <dc:creator>Piyush Gupta</dc:creator>
      <pubDate>Sun, 12 Apr 2026 08:00:00 +0000</pubDate>
      <link>https://dev.to/piyush6348/master-class-scaling-databases-with-sharding-partitioning-and-consistent-hashing-44p1</link>
      <guid>https://dev.to/piyush6348/master-class-scaling-databases-with-sharding-partitioning-and-consistent-hashing-44p1</guid>
      <description>&lt;p&gt;Scaling a database is often the "final boss" of system design. While scaling your application layer is as simple as spinning up more containers, databases are stateful, making them significantly harder to distribute.&lt;/p&gt;

&lt;p&gt;When vertical scaling hits a physical limit, you have no choice but to &lt;strong&gt;scale horizontally&lt;/strong&gt;. In this guide, we break down the three pillars of horizontal scaling and how they intersect with replication strategies to build truly resilient systems.&lt;/p&gt;




&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Sharding vs. Partitioning: The Core Difference&lt;/li&gt;
&lt;li&gt;Partitioning Strategies: Horizontal vs. Vertical&lt;/li&gt;
&lt;li&gt;The "Modulo" Problem: Why Simple Hashing Fails&lt;/li&gt;
&lt;li&gt;Consistent Hashing: The Secret to Rebalancing&lt;/li&gt;
&lt;li&gt;The Hybrid Model: Relating Replication to Sharding&lt;/li&gt;
&lt;li&gt;The Complexity Trade-offs&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Sharding vs. Partitioning: The Core Difference
&lt;/h2&gt;

&lt;p&gt;While often used interchangeably, they operate at different layers of the stack:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Partitioning:&lt;/strong&gt; This is a &lt;strong&gt;logical&lt;/strong&gt; split of your data. It’s about taking a giant dataset and breaking it into smaller, manageable chunks (e.g., splitting a 1TB table into ten 100GB chunks).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sharding:&lt;/strong&gt; This is a &lt;strong&gt;physical&lt;/strong&gt; split across machines. It involves distributing those partitions across different database instances (shards) to distribute the CPU, RAM, and I/O load.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The Golden Rule:&lt;/strong&gt; You shard the &lt;em&gt;database&lt;/em&gt; and you partition the &lt;em&gt;data&lt;/em&gt;.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Partitioning Strategies
&lt;/h2&gt;

&lt;p&gt;How do you decide which data goes into which partition? It must be deterministic.&lt;/p&gt;

&lt;h3&gt;
  
  
  A. Horizontal Partitioning (Sharding)
&lt;/h3&gt;

&lt;p&gt;You split the table by &lt;strong&gt;rows&lt;/strong&gt;. For example, users with IDs 1–1000 go to Partition A, and 1001–2000 go to Partition B.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Best for:&lt;/strong&gt; Distributing massive datasets across nodes for write/read throughput.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  B. Vertical Partitioning
&lt;/h3&gt;

&lt;p&gt;You split the table by &lt;strong&gt;columns&lt;/strong&gt;. A &lt;code&gt;User&lt;/code&gt; table might be split into &lt;code&gt;User_Profile&lt;/code&gt; (Name, Email) and &lt;code&gt;User_Metadata&lt;/code&gt; (Bio, Settings, Blob data).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Best for:&lt;/strong&gt; Reducing I/O for queries that only need specific, frequently accessed columns.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The "Modulo" Problem: Why Simple Hashing Fails
&lt;/h2&gt;

&lt;p&gt;When sharding, we need to map a key (like &lt;code&gt;user_id&lt;/code&gt;) to a specific server. The simplest way is &lt;strong&gt;Modulo Hashing&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;

&lt;/p&gt;
&lt;div class="katex-element"&gt;
  &lt;span class="katex-display"&gt;&lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;serverindex=hash(key)(modn)
server_index = hash(key) \pmod n
&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;ser&lt;/span&gt;&lt;span class="mord mathnormal"&gt;v&lt;/span&gt;&lt;span class="mord mathnormal"&gt;e&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;r&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mathnormal mtight"&gt;i&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;n&lt;/span&gt;&lt;span class="mord mathnormal"&gt;d&lt;/span&gt;&lt;span class="mord mathnormal"&gt;e&lt;/span&gt;&lt;span class="mord mathnormal"&gt;x&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;=&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;ha&lt;/span&gt;&lt;span class="mord mathnormal"&gt;s&lt;/span&gt;&lt;span class="mord mathnormal"&gt;h&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord mathnormal"&gt;k&lt;/span&gt;&lt;span class="mord mathnormal"&gt;ey&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;span class="mspace allowbreak"&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord"&gt;&lt;span class="mord mathrm"&gt;mod&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;n&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;


&lt;p&gt;Where 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;nn &lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;n&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
 is the number of servers. This works until you need to scale. If you have 3 servers (
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;n=3n=3 &lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;n&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;=&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;3&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
) and you add a 4th (
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;n=4n=4 &lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;n&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;=&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;4&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
), the result of the modulo operation changes for almost &lt;strong&gt;every single key&lt;/strong&gt;. This forces a massive data migration that can bring your system down.&lt;/p&gt;


&lt;h2&gt;
  
  
  Consistent Hashing: The Secret to Rebalancing
&lt;/h2&gt;

&lt;p&gt;Consistent Hashing solves the "Modulo Problem" by decoupling the keys from the number of servers using a &lt;strong&gt;Hash Ring&lt;/strong&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  How it Works:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The Ring:&lt;/strong&gt; Both servers and data keys are hashed onto the same ring (range 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;00 &lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;0&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
 to 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;232−12^{32}-1 &lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord"&gt;2&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mtight"&gt;&lt;span class="mord mtight"&gt;32&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;−&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Clockwise Assignment:&lt;/strong&gt; To find a key's server, you move clockwise on the ring until you hit the first server.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Minimal Migration:&lt;/strong&gt; When you add a new server, it only takes over a small portion of the ring. &lt;strong&gt;Only the keys between the new server and its counter-clockwise neighbor need to move.&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;


&lt;h2&gt;
  
  
  The Hybrid Model: Relating Replication to Sharding
&lt;/h2&gt;

&lt;p&gt;Sharding handles &lt;strong&gt;capacity&lt;/strong&gt;, but Replication handles &lt;strong&gt;availability&lt;/strong&gt;. In a production system, every "Shard" is actually a "Replication Group."&lt;/p&gt;
&lt;h3&gt;
  
  
  A. Sharded + Single-Leader Replication
&lt;/h3&gt;

&lt;p&gt;Each shard is a replica set with one Leader and multiple Followers.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Workflow:&lt;/strong&gt; Consistent hashing sends you to &lt;strong&gt;Shard 4&lt;/strong&gt;. Within Shard 4, all writes go to the Leader, and reads can be distributed to Followers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Example:&lt;/strong&gt; Vitess (MySQL) or MongoDB.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  B. Sharded + Multi-Leader Replication
&lt;/h3&gt;

&lt;p&gt;Common in multi-region deployments. You shard by geography (e.g., EU users vs. US users), but within each shard, you have multiple leaders (e.g., London and Paris) to reduce local latency.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Example:&lt;/strong&gt; Global Spanner configurations.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  C. Sharded + Leaderless Replication (The "Dynamo" Way)
&lt;/h3&gt;

&lt;p&gt;In systems like Cassandra, sharding and replication are unified on the ring.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Workflow:&lt;/strong&gt; A key is hashed to the ring. Instead of going to one node, it is replicated to the &lt;strong&gt;next N nodes&lt;/strong&gt; clockwise.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Quorum:&lt;/strong&gt; You use 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;W+R&amp;gt;NW + R &amp;gt; N &lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;W&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;+&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;R&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;&amp;gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;N&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
 to ensure consistency across those sharded replicas.&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  The Complexity Trade-offs
&lt;/h2&gt;

&lt;p&gt;Sharding is powerful, but it comes with a high "architectural tax":&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Cross-Shard Joins:&lt;/strong&gt; Joining data from Shard A and Shard B is incredibly expensive. You often have to perform the join in the application layer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hotspots:&lt;/strong&gt; If one user (e.g., a celebrity) gets 100x more traffic than others, the shard they reside on will become a bottleneck.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Operational Overhead:&lt;/strong&gt; Managing backups, monitoring, and failover for 100 shards is significantly more complex than a single instance.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  Summary Comparison
&lt;/h3&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;Modulo Hashing&lt;/th&gt;
&lt;th&gt;Consistent Hashing&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Scaling Impact&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;~100% data migration&lt;/td&gt;
&lt;td&gt;~$1/n$ data migration&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Fault Tolerance&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Replication Choice&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Usually Single-Leader&lt;/td&gt;
&lt;td&gt;Often Leaderless / Multi-Leader&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;


&lt;h2&gt;
  
  
  Final Thought
&lt;/h2&gt;

&lt;p&gt;Sharding is how we find the "house" for our data; Replication is how we ensure that house doesn't burn down. Don't shard until you hit the physical limits of your hardware, but when you do, use &lt;strong&gt;Consistent Hashing&lt;/strong&gt; to ensure your growth is sustainable.&lt;/p&gt;




&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/piyush6348/master-class-understanding-database-replication-single-multi-and-leaderless-hhm" class="crayons-story__hidden-navigation-link"&gt;Master-Class: Understanding Database Replication (Single, Multi, and Leaderless)&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/piyush6348" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F12063%2F16835832.jpeg" alt="piyush6348 profile" class="crayons-avatar__image" width="460" height="460"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/piyush6348" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Piyush Gupta
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Piyush Gupta
                
              
              &lt;div id="story-author-preview-content-3456633" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/piyush6348" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F12063%2F16835832.jpeg" class="crayons-avatar__image" alt="" width="460" height="460"&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Piyush Gupta&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/piyush6348/master-class-understanding-database-replication-single-multi-and-leaderless-hhm" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Apr 5&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/piyush6348/master-class-understanding-database-replication-single-multi-and-leaderless-hhm" id="article-link-3456633"&gt;
          Master-Class: Understanding Database Replication (Single, Multi, and Leaderless)
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/systemdesign"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;systemdesign&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/backend"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;backend&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/database"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;database&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/distributedsystems"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;distributedsystems&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/piyush6348/master-class-understanding-database-replication-single-multi-and-leaderless-hhm" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;3&lt;span class="hidden s:inline"&gt; reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/piyush6348/master-class-understanding-database-replication-single-multi-and-leaderless-hhm#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              &lt;span class="hidden s:inline"&gt;Add Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            3 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
      <category>database</category>
      <category>systemdesign</category>
      <category>backend</category>
      <category>distributedsystems</category>
    </item>
    <item>
      <title>How to Use LeetCode Effectively for Interview Prep (The Strategic Way)</title>
      <dc:creator>Piyush Gupta</dc:creator>
      <pubDate>Tue, 07 Apr 2026 15:12:32 +0000</pubDate>
      <link>https://dev.to/piyush6348/how-to-use-leetcode-effectively-for-interview-prep-the-strategic-way-4ii5</link>
      <guid>https://dev.to/piyush6348/how-to-use-leetcode-effectively-for-interview-prep-the-strategic-way-4ii5</guid>
      <description>&lt;p&gt;Preparing for coding interviews at top-tier companies can be overwhelming. While everyone knows about &lt;strong&gt;LeetCode&lt;/strong&gt;, most people use it inefficiently—simply solving random problems without a clear roadmap.&lt;/p&gt;

&lt;p&gt;In this guide, based on insights from the &lt;a href="https://youtu.be/pSKe9vunF2E" rel="noopener noreferrer"&gt;Engineer Talks&lt;/a&gt; deep dive, we break down the most effective way to master Data Structures and Algorithms (DSA) without burning out.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Quality Over Quantity 📈
&lt;/h2&gt;

&lt;p&gt;One of the biggest mistakes is focusing on the "Total Solved" count. Solving 500 problems without understanding the core patterns won't help you when an interviewer throws a curveball.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Strategy:&lt;/strong&gt; Focus on understanding the logic behind every solution.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The "Struggle" Rule:&lt;/strong&gt; If you are stuck, give it at least &lt;strong&gt;30–45 minutes&lt;/strong&gt; of pure thought before looking at the hints. If you must look at the solution, don't just copy-paste it. Close the tab and try to implement it from scratch.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  2. Topic-Wise Mastery (The "Tag" Strategy) 🏷️
&lt;/h2&gt;

&lt;p&gt;Randomizing problems is for the final stages of prep. When you're starting, you need to build a foundation.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Step-by-Step:&lt;/strong&gt; Pick one topic (e.g., Linked Lists) and solve 15–20 problems of varying difficulty before moving to the next. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Benefit:&lt;/strong&gt; This builds &lt;strong&gt;pattern recognition&lt;/strong&gt;. When you see a new problem in an interview, you’ll immediately recognize it as a "Two Pointer" or "Sliding Window" problem because you've trained your brain to see that specific structure.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  3. The "Difficulty Ladder" 🪜
&lt;/h2&gt;

&lt;p&gt;Don't jump straight into "Hard" problems. It’s the fastest way to lose motivation.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Easy:&lt;/strong&gt; Start here to get familiar with the syntax and basic operations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Medium:&lt;/strong&gt; This is the &lt;strong&gt;"Sweet Spot."&lt;/strong&gt; Most interview questions from Big Tech companies fall into this category. You should spend 70% of your time here.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hard:&lt;/strong&gt; Tackle these only once you are consistently solving Mediums in under 30 minutes.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  4. Leverage the Community 💡
&lt;/h2&gt;

&lt;p&gt;The real gold on LeetCode isn't just the problem statement; it's the &lt;strong&gt;Discussion&lt;/strong&gt; and &lt;strong&gt;Solutions&lt;/strong&gt; tabs.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Optimization:&lt;/strong&gt; Even if your code passes, check the top-voted solutions. There is almost always a more elegant or optimized way (better Time or Space Complexity) that you hadn't considered.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Alternative Languages:&lt;/strong&gt; Seeing how a problem is solved in Python vs. C++ can give you a better perspective on language-specific optimizations.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  5. Consistency Over Intensity ⏱️
&lt;/h2&gt;

&lt;p&gt;It is better to solve &lt;strong&gt;1 problem a day for 30 days&lt;/strong&gt; than 30 problems in one weekend and then quitting for a month.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Daily Challenge:&lt;/strong&gt; Use the "LeetCode Daily Challenge" to keep your streak alive and force yourself to touch different topics every day.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mock Contests:&lt;/strong&gt; Once you're comfortable, participate in Weekly Contests to simulate the time pressure of a real interview.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Final Thoughts
&lt;/h3&gt;

&lt;p&gt;LeetCode is a tool, not a goal. Your objective is to become a better problem solver, not a better "LeetCoder." Focus on the &lt;strong&gt;why&lt;/strong&gt; behind the code, and the offers will follow.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Don't count the problems, make the problems count."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Have you started your LeetCode journey yet? What’s the hardest topic you’ve encountered so far? Let’s discuss in the comments!&lt;/strong&gt; 👇&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Based on the guide by Engineer Talks. &lt;a href="https://youtu.be/pSKe9vunF2E" rel="noopener noreferrer"&gt;Watch the original video here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>leetcode</category>
      <category>interviewprep</category>
      <category>dsa</category>
      <category>career</category>
    </item>
    <item>
      <title>Mastering Schema Evolution: Why Apache Avro is the King of Big Data (Part 2)</title>
      <dc:creator>Piyush Gupta</dc:creator>
      <pubDate>Sun, 05 Apr 2026 14:03:38 +0000</pubDate>
      <link>https://dev.to/piyush6348/mastering-schema-evolution-why-apache-avro-is-the-king-of-big-data-part-2-3987</link>
      <guid>https://dev.to/piyush6348/mastering-schema-evolution-why-apache-avro-is-the-king-of-big-data-part-2-3987</guid>
      <description>&lt;h2&gt;
  
  
  The Evolution Nightmare
&lt;/h2&gt;

&lt;p&gt;In &lt;a href="https://dev.to/piyush6348/beyond-json-a-high-performance-guide-to-thrift-protocol-buffers-part-1-2nee"&gt;Part 1&lt;/a&gt;, we saw how Thrift and Protocol Buffers use numeric tags to shrink data. But in a real-world distributed system, you can’t upgrade every microservice at the same time. You will always have &lt;strong&gt;Old Code&lt;/strong&gt; talking to &lt;strong&gt;New Code&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This creates a massive problem: &lt;strong&gt;Schema Evolution&lt;/strong&gt;. If Service A adds a new field to its database, will Service B (running the old code) crash when it tries to read that data?&lt;/p&gt;

&lt;h3&gt;
  
  
  Forward vs. Backward Compatibility
&lt;/h3&gt;

&lt;p&gt;To build a resilient system, you must understand two concepts:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Backward Compatibility:&lt;/strong&gt; New code can read data written by old code. (Essential when you update your "Readers" first).&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Forward Compatibility:&lt;/strong&gt; Old code can read data written by new code. (Essential when you update your "Writers" first).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In Thrift and Protobuf, this is managed by &lt;strong&gt;Tags&lt;/strong&gt;. If a reader sees a tag it doesn't recognize, it simply ignores it. But what if you want to avoid tags entirely?&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Apache Avro: The "No Tag" Evolution
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Apache Avro&lt;/strong&gt; was created within the Hadoop ecosystem because Thrift wasn't a perfect fit for massive data files. Unlike Protobuf, Avro &lt;strong&gt;does not store tag numbers&lt;/strong&gt; or field types in the binary data. It only stores the raw values.&lt;/p&gt;

&lt;h3&gt;
  
  
  How it works: The Pairwise Resolution
&lt;/h3&gt;

&lt;p&gt;How does the reader know what the data is if there are no tags? &lt;/p&gt;

&lt;p&gt;Avro uses two schemas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Writer’s Schema:&lt;/strong&gt; The schema the application used when it sent the data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reader’s Schema:&lt;/strong&gt; The schema the receiving application expects.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When data is read, the Avro library looks at both schemas side-by-side. If the field order changed or a field was renamed, Avro "resolves" the difference by looking at the field names.&lt;/p&gt;

&lt;p&gt;![Diagram: Avro Reader and Writer Schema Resolution Logic]&lt;/p&gt;

&lt;h3&gt;
  
  
  Implementation Example (Avro JSON Schema)
&lt;/h3&gt;

&lt;p&gt;Avro schemas are written in simple JSON, making them much easier to generate dynamically than the IDLs we saw in Part 1.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;user_schema.avsc&lt;/strong&gt;&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;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"record"&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;"User"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"namespace"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"com.piyush.devto"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"fields"&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="p"&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;"username"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&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="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;"age"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&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;"int"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"null"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"default"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&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="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;"email"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&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;"string"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"null"&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="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;&lt;strong&gt;Python Implementation:&lt;/strong&gt;&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="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;avro.schema&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;avro.datafile&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;DataFileWriter&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;avro.io&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;DatumWriter&lt;/span&gt;

&lt;span class="c1"&gt;# 1. Load the schema from a file
&lt;/span&gt;&lt;span class="n"&gt;schema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;avro&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;schema&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="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user_schema.avsc&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rb&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

&lt;span class="c1"&gt;# 2. Write binary data to an Avro Object Container File
&lt;/span&gt;&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nc"&gt;DataFileWriter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;users.avro&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;wb&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nc"&gt;DatumWriter&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;username&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Piyush&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;age&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;email&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;piyush@example.com&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Data serialized to users.avro&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  The Killer Feature: Database Integration
&lt;/h2&gt;

&lt;p&gt;One reason Avro is the "gold standard" for &lt;strong&gt;Kafka&lt;/strong&gt; and &lt;strong&gt;Big Data&lt;/strong&gt; is its relationship with relational databases.&lt;/p&gt;

&lt;p&gt;Because Avro schemas are JSON, you can write a script to automatically convert a SQL table into an Avro schema. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SQL Column&lt;/strong&gt; → Avro Field Name&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SQL Data Type&lt;/strong&gt; → Avro Type&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Nullable Column&lt;/strong&gt; → Avro Union &lt;code&gt;["type", "null"]&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This makes Avro perfect for &lt;strong&gt;Change Data Capture (CDC)&lt;/strong&gt;, where you stream every single update from your Postgres or MySQL database into a Data Lake like S3 or Snowflake.&lt;/p&gt;




&lt;h2&gt;
  
  
  Summary: Choosing Your Weapon
&lt;/h2&gt;

&lt;p&gt;Which encoding should you use for your next project?&lt;/p&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;JSON&lt;/th&gt;
&lt;th&gt;Protobuf / Thrift&lt;/th&gt;
&lt;th&gt;Apache Avro&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Best For&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Public APIs&lt;/td&gt;
&lt;td&gt;Internal Microservices&lt;/td&gt;
&lt;td&gt;Big Data / Pipelines&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Speed&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Slowest&lt;/td&gt;
&lt;td&gt;Fast&lt;/td&gt;
&lt;td&gt;Fastest (no tags)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Schema&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Optional&lt;/td&gt;
&lt;td&gt;Required (IDL)&lt;/td&gt;
&lt;td&gt;Required (JSON)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Logic&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Human-readable&lt;/td&gt;
&lt;td&gt;Tag-based&lt;/td&gt;
&lt;td&gt;Resolution-based&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Final Thoughts
&lt;/h3&gt;

&lt;p&gt;Encoding isn't just about saving bytes; it's about defining the &lt;strong&gt;contract&lt;/strong&gt; between your services. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;strong&gt;JSON&lt;/strong&gt; when you need ease of use. &lt;/li&gt;
&lt;li&gt;Use &lt;strong&gt;Protobuf&lt;/strong&gt; for gRPC and internal speed. &lt;/li&gt;
&lt;li&gt;Use &lt;strong&gt;Avro&lt;/strong&gt; when your data is massive and your schemas are constantly evolving.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;What are you using in production? Let's discuss in the comments!&lt;/strong&gt;&lt;/p&gt;



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

---

### Why this works for dev.to:
* **Series Link:** The `series` tag in the metadata automatically links Part 1 and Part 2 on the platform.
* **Liquid Tags:** I used blockquotes and bolded text to highlight "Forward/Backward" compatibility—a common interview question for senior devs.
* **Conclusion Table:** Dev.to readers love a quick "Cheat Sheet" or comparison table to wrap up a long-form post.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>bigdata</category>
      <category>architecture</category>
      <category>kafka</category>
      <category>programming</category>
    </item>
    <item>
      <title>Beyond JSON: A High-Performance Guide to Thrift &amp; Protocol Buffers (Part 1)</title>
      <dc:creator>Piyush Gupta</dc:creator>
      <pubDate>Sun, 05 Apr 2026 14:02:03 +0000</pubDate>
      <link>https://dev.to/piyush6348/beyond-json-a-high-performance-guide-to-thrift-protocol-buffers-part-1-2nee</link>
      <guid>https://dev.to/piyush6348/beyond-json-a-high-performance-guide-to-thrift-protocol-buffers-part-1-2nee</guid>
      <description>&lt;h2&gt;
  
  
  The "Text-Based" Performance Tax
&lt;/h2&gt;

&lt;p&gt;Most of us start our careers in the land of &lt;strong&gt;JSON&lt;/strong&gt;. It’s human-readable, it’s the language of the web, and it’s incredibly easy to debug. But as your system scales from a few hundred requests to hundreds of thousands per second, JSON starts to reveal its "tax."&lt;/p&gt;

&lt;h3&gt;
  
  
  Why JSON/XML is Killing Your Throughput:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Redundancy:&lt;/strong&gt; Every single message repeats the keys. If you send a list of 1,000 users, you are sending the string &lt;code&gt;"username"&lt;/code&gt; 1,000 times. That’s pure overhead.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Parsing Overhead:&lt;/strong&gt; Converting a string like &lt;code&gt;"12345.67"&lt;/code&gt; into a 64-bit float is a CPU-intensive operation. In high-performance systems, the time spent parsing JSON often exceeds the time spent processing the actual business logic.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Binary Inefficiency:&lt;/strong&gt; If you need to send binary data (like a profile picture or a byte array), you must use &lt;strong&gt;Base64&lt;/strong&gt; encoding, which increases the data size by approximately &lt;strong&gt;33%&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The Solution:&lt;/strong&gt; Binary Encoding. By using a schema-based binary format, we can strip away the field names and focus entirely on the data.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  1. Apache Thrift: The Multi-Protocol Powerhouse
&lt;/h2&gt;

&lt;p&gt;Originally developed at Facebook to solve cross-language service communication, &lt;strong&gt;Apache Thrift&lt;/strong&gt; is both an encoding format and a full RPC (Remote Procedure Call) framework.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Magic of the IDL
&lt;/h3&gt;

&lt;p&gt;Thrift uses an &lt;strong&gt;Interface Definition Language (IDL)&lt;/strong&gt;. Instead of defining your data in code, you define it in a &lt;code&gt;.thrift&lt;/code&gt; file. This acts as the single source of truth for all your services, whether they are written in Python, Go, or Java.&lt;/p&gt;

&lt;h3&gt;
  
  
  Binary Protocol vs. Compact Protocol
&lt;/h3&gt;

&lt;p&gt;Thrift offers different ways to "pack" your data:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Binary Protocol:&lt;/strong&gt; A simple, fast approach that encodes data in a straightforward binary format without much compression.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Compact Protocol:&lt;/strong&gt; This is where the efficiency shines. It uses &lt;strong&gt;Variable-length integers (Varints)&lt;/strong&gt;. For example, the number &lt;code&gt;7&lt;/code&gt; only takes 1 byte, while &lt;code&gt;7,000,000&lt;/code&gt; takes significantly more. It also packs field IDs and data types into a single byte whenever possible.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Implementation Example (Thrift IDL)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// user_profile.thrift
namespace java com.piyush.devto
namespace py devto.piyush

struct UserProfile {
  1: required string username,
  2: optional i32 age,
  3: optional bool is_active = true,
  4: optional list&amp;lt;string&amp;gt; tags
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Python Serialization Code:&lt;/strong&gt;&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="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;thrift.protocol&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;TCompactProtocol&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;thrift.transport&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;TTransport&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;devto.piyush.ttypes&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;UserProfile&lt;/span&gt;

&lt;span class="c1"&gt;# Creating a sample object
&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;UserProfile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Piyush&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tags&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;distributed-systems&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;backend&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="c1"&gt;# Step 1: Initialize a memory buffer
&lt;/span&gt;&lt;span class="n"&gt;transport&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TTransport&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;TMemoryBuffer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;# Step 2: Use the Compact Protocol
&lt;/span&gt;&lt;span class="n"&gt;protocol&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TCompactProtocol&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;TCompactProtocol&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;transport&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Step 3: Write (Serialize) the object to the buffer
&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;protocol&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Get the raw bytes
&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;transport&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getvalue&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nf"&gt;print&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;Total encoded size: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; bytes&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  2. Protocol Buffers (Protobuf): The Google Standard
&lt;/h2&gt;

&lt;p&gt;If you’ve ever looked into &lt;strong&gt;gRPC&lt;/strong&gt;, you’ve encountered &lt;strong&gt;Protocol Buffers&lt;/strong&gt;. Developed by Google, it is arguably the most popular binary encoding format in the industry today.&lt;/p&gt;

&lt;h3&gt;
  
  
  The "Tag" System: Why Order Matters
&lt;/h3&gt;

&lt;p&gt;In Protobuf, the &lt;em&gt;name&lt;/em&gt; of the field (&lt;code&gt;username&lt;/code&gt;) is never sent over the wire. Instead, Protobuf uses &lt;strong&gt;Tags&lt;/strong&gt; (unique numbers assigned to each field). &lt;/p&gt;

&lt;p&gt;When the encoder sees &lt;code&gt;string username = 1;&lt;/code&gt;, it simply writes: &lt;code&gt;[Field Tag 1] [Data Length] [Value]&lt;/code&gt;. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Critical Rule:&lt;/strong&gt; Once you assign a tag number (like &lt;code&gt;1&lt;/code&gt;), you can &lt;strong&gt;never&lt;/strong&gt; change it. If you change a tag, you break the ability for your services to understand each other.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Visualizing the Binary Layout
&lt;/h3&gt;

&lt;p&gt;While JSON looks like a mess of curly braces and quotes, a binary message looks like a streamlined stream of bits.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tag &amp;amp; Type&lt;/th&gt;
&lt;th&gt;Length/Value&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;code&gt;0x12&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0x06&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Field #1 is a String of 6 bytes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;0x50 0x69 0x79...&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;"Piyush"&lt;/td&gt;
&lt;td&gt;The actual data&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;0x18&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0x19&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Field #2 is an Integer (25)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h3&gt;
  
  
  Implementation Example (Protobuf)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight protobuf"&gt;&lt;code&gt;&lt;span class="na"&gt;syntax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"proto3"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;devto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;piyush&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;message&lt;/span&gt; &lt;span class="nc"&gt;UserProfile&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="na"&gt;username&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kt"&gt;int32&lt;/span&gt; &lt;span class="na"&gt;age&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="na"&gt;is_active&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;repeated&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="na"&gt;tags&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&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;p&gt;&lt;strong&gt;Java Implementation:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Building the object&lt;/span&gt;
&lt;span class="nc"&gt;UserProfile&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;UserProfile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newBuilder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setUsername&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Piyush"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setAge&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setIsActive&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addTags&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"java"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addTags&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"grpc"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Serialization to byte array&lt;/span&gt;
&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;binaryData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toByteArray&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Deserialization on the other end&lt;/span&gt;
&lt;span class="nc"&gt;UserProfile&lt;/span&gt; &lt;span class="n"&gt;receivedUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;UserProfile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;parseFrom&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;binaryData&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"User: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;receivedUser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getUsername&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Summary of Part 1
&lt;/h2&gt;

&lt;p&gt;By moving from JSON to a format like Thrift or Protobuf, you aren't just saving a few bytes. You are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Lowering Latency:&lt;/strong&gt; Binary data is parsed up to &lt;strong&gt;10x faster&lt;/strong&gt; than text.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Reducing Infrastructure Costs:&lt;/strong&gt; Less bandwidth means lower cloud egress bills.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Enforcing Type Safety:&lt;/strong&gt; Your API becomes a contract that cannot be easily broken.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Coming up in Part 2:&lt;/strong&gt; We will dive into &lt;strong&gt;Schema Evolution&lt;/strong&gt; (how to update your data without crashing your app) and why &lt;strong&gt;Apache Avro&lt;/strong&gt; is the undisputed king of Big Data and Kafka pipelines.&lt;/p&gt;

</description>
      <category>performance</category>
      <category>backend</category>
      <category>architecture</category>
      <category>programming</category>
    </item>
    <item>
      <title>B-Trees, Clustered Indexes, and the OLAP Revolution (Part 2) 📊</title>
      <dc:creator>Piyush Gupta</dc:creator>
      <pubDate>Sun, 05 Apr 2026 13:52:02 +0000</pubDate>
      <link>https://dev.to/piyush6348/b-trees-clustered-indexes-and-the-olap-revolution-part-2-4dj4</link>
      <guid>https://dev.to/piyush6348/b-trees-clustered-indexes-and-the-olap-revolution-part-2-4dj4</guid>
      <description>&lt;p&gt;In &lt;a href="https://dev.to/piyush6348/how-databases-actually-work-from-log-files-to-lsm-trees-part-1-joo"&gt;Part 1&lt;/a&gt;, we looked at LSM Trees—the write-heavy champions found in NoSQL databases. But if you’re using &lt;strong&gt;PostgreSQL, MySQL, or Oracle&lt;/strong&gt;, you’re likely interacting with a different beast: the &lt;strong&gt;B-Tree&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;Today, we’ll explore why B-Trees still dominate the relational world and how the "Big Data" era forced us to rethink how we store rows entirely.&lt;/p&gt;

&lt;h2&gt;
  
  
  Table Of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;1. The King of RDBMS: B-Trees&lt;/li&gt;
&lt;li&gt;2. Clustered vs. Non-Clustered Indexes&lt;/li&gt;
&lt;li&gt;3. OLTP vs. OLAP: The Great Divide&lt;/li&gt;
&lt;li&gt;4. Why Column-Oriented Storage Wins at Scale&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  1. The King of RDBMS: B-Trees
&lt;/h2&gt;

&lt;p&gt;B-Trees are the most widely used indexing structure in history. Unlike the variable-size segments in LSM Trees, B-Trees break the database down into fixed-size &lt;strong&gt;pages&lt;/strong&gt; (usually 4KB to 16KB).&lt;/p&gt;

&lt;h3&gt;
  
  
  How it Works:
&lt;/h3&gt;

&lt;p&gt;A B-Tree is a balanced tree where each node contains multiple keys and pointers to child pages. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Root:&lt;/strong&gt; The entry point for every query.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Leaf Nodes:&lt;/strong&gt; These contain the actual data or a reference to where the data lives on disk.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because the tree is always balanced, a B-Tree with a branching factor of 500 and just 4 levels can store &lt;strong&gt;256 billion rows&lt;/strong&gt;! This makes lookups incredibly consistent at $O(\log n)$.&lt;/p&gt;

&lt;h3&gt;
  
  
  B-Trees vs. LSM Trees: The Trade-off
&lt;/h3&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;B-Trees&lt;/th&gt;
&lt;th&gt;LSM Trees&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Best for&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Read-heavy workloads&lt;/td&gt;
&lt;td&gt;Write-heavy workloads&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Fragmentation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;High (due to empty page space)&lt;/td&gt;
&lt;td&gt;Low (sequential background merges)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Throughput&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Lower (multiple disk seeks)&lt;/td&gt;
&lt;td&gt;Higher (sequential appends)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  2. Clustered vs. Non-Clustered Indexes
&lt;/h2&gt;

&lt;p&gt;Where does the actual row live? This is a common interview question that boils down to index design:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Clustered Index:&lt;/strong&gt; The index &lt;strong&gt;is&lt;/strong&gt; the data. The leaf nodes of the B-Tree contain the actual row values. You can only have one clustered index per table (usually the Primary Key).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Non-Clustered (Secondary):&lt;/strong&gt; The index contains a "pointer" (like a Row ID) to the data's location. This allows for multiple indexes but requires an extra "hop" to fetch the full row.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  3. OLTP vs. OLAP: The Great Divide
&lt;/h2&gt;

&lt;p&gt;Most web developers spend their time in &lt;strong&gt;OLTP (Online Transaction Processing)&lt;/strong&gt;. You handle thousands of small queries: &lt;em&gt;"Update this user’s bio"&lt;/em&gt; or &lt;em&gt;"Add this item to the cart."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;However, businesses eventually need &lt;strong&gt;OLAP (Online Analytical Processing)&lt;/strong&gt;. This involves massive aggregate queries like: &lt;em&gt;"What was the total revenue in Q4 across all Asian markets?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Running these on your production database will cause it to crawl. Instead, we move data to a &lt;strong&gt;Data Warehouse&lt;/strong&gt; using &lt;strong&gt;ETL (Extract, Transform, Load)&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. Why Column-Oriented Storage Wins at Scale
&lt;/h2&gt;

&lt;p&gt;Traditional databases store data &lt;strong&gt;Row-by-Row&lt;/strong&gt;. To calculate an average age, the DB loads the entire row (Name, Email, Bio, Password) just to access one tiny "Age" integer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Column-Oriented Storage&lt;/strong&gt; (BigQuery, Snowflake, ClickHouse) stores each column in its own file.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Code Reality:
&lt;/h3&gt;

&lt;p&gt;Imagine a table with 100 columns and 1 billion rows.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Row-oriented: Reads 100 columns from disk per row.&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;AVG&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;-- Column-oriented: Reads ONLY the 'age' file. &lt;/span&gt;
&lt;span class="c1"&gt;-- It ignores the other 99 columns completely.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By only reading the necessary bytes, analytical queries that used to take hours now take seconds. Furthermore, because column data is often repetitive (e.g., many users living in the same "City"), these files compress significantly better than row-based data.&lt;/p&gt;




&lt;h2&gt;
  
  
  💬 Engineering Challenge
&lt;/h2&gt;

&lt;p&gt;Most modern architectures use &lt;strong&gt;Polyglot Persistence&lt;/strong&gt;—an RDBMS (B-Trees) for user transactions and a Data Warehouse (Columnar) for analytics.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Join the conversation:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Have you ever crashed a production DB by running a heavy "Analytical" query during peak hours?&lt;/li&gt;
&lt;li&gt;What’s your "Big Data" tool of choice—Snowflake, BigQuery, or maybe self-hosted ClickHouse?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Drop a comment below with your horror stories or favorite setups!&lt;/strong&gt; 🛠️✨&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>database</category>
      <category>sql</category>
      <category>bigdata</category>
      <category>systemdesign</category>
    </item>
    <item>
      <title>How Databases Actually Work: From Log Files to LSM Trees (Part 1) 🚀</title>
      <dc:creator>Piyush Gupta</dc:creator>
      <pubDate>Sun, 05 Apr 2026 13:49:52 +0000</pubDate>
      <link>https://dev.to/piyush6348/how-databases-actually-work-from-log-files-to-lsm-trees-part-1-joo</link>
      <guid>https://dev.to/piyush6348/how-databases-actually-work-from-log-files-to-lsm-trees-part-1-joo</guid>
      <description>&lt;p&gt;We often treat databases like PostgreSQL, MySQL, or MongoDB as magic black boxes. We send a query, and data comes back. But what is actually happening on the disk? &lt;/p&gt;

&lt;p&gt;If you've ever wondered why some databases are "fast for writes" while others are "fast for reads," the answer lies in the &lt;strong&gt;Storage Engine&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;In this post, we’re going to build a database from scratch and evolve it into a production-grade LSM Tree.&lt;/p&gt;

&lt;h2&gt;
  
  
  Table Of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;1. The World’s Simplest Database&lt;/li&gt;
&lt;li&gt;2. Adding an Index (The Hash Map)&lt;/li&gt;
&lt;li&gt;3. Solving the Space Crisis: Compaction&lt;/li&gt;
&lt;li&gt;4. The Power of SSTables and LSM Trees&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  1. The World’s Simplest Database
&lt;/h2&gt;

&lt;p&gt;The simplest way to store data is to just append it to a text file. No complex schemas, just raw speed.&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;# Simple Key-Value Store in Bash&lt;/span&gt;
db_set&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;$2&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; database.db
&lt;span class="o"&gt;}&lt;/span&gt;

db_get&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;# We use 'tail -n 1' to get the most recent update for that key&lt;/span&gt;
  &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="s2"&gt;"^&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;,"&lt;/span&gt; database.db | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="s2"&gt;"s/^&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;,//"&lt;/span&gt; | &lt;span class="nb"&gt;tail&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; 1
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The Verdict:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Writes:&lt;/strong&gt; &lt;strong&gt;O(1)&lt;/strong&gt; — Extremely fast. You just append to the end of the file.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reads:&lt;/strong&gt; &lt;strong&gt;O(n)&lt;/strong&gt; — Terrible. To find one key, you have to scan the entire file from start to finish.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  2. Adding an Index (The Hash Map)
&lt;/h2&gt;

&lt;p&gt;To fix the $O(n)$ read problem, we use a &lt;strong&gt;Hash Index&lt;/strong&gt;. Think of this as a "Table of Contents" kept in your server's RAM.&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="c1"&gt;# Conceptual In-Memory Index
&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user_123&lt;/span&gt;&lt;span class="sh"&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="c1"&gt;# Byte offset in the file
&lt;/span&gt;  &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user_456&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user_789&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;128&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_data&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;offset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;index&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="nb"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;seek&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read_line&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is how &lt;strong&gt;Bitcask&lt;/strong&gt; (the default storage engine for Riak) works. It’s incredibly fast, but there’s a catch: &lt;strong&gt;All your keys must fit in RAM.&lt;/strong&gt; If you have billions of keys, your server will crash.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Solving the Space Crisis: Compaction
&lt;/h2&gt;

&lt;p&gt;Since we only append to our log, the file grows forever even if we're just updating the same key. Databases solve this via &lt;strong&gt;Compaction&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;We break the log into segments. Once a segment reaches a certain size, we close it and start a new one. A background process then merges these segments, throwing away old, overwritten values.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. The Power of SSTables and LSM Trees
&lt;/h2&gt;

&lt;p&gt;What if we store our data files sorted by key? This is a &lt;strong&gt;Sorted String Table (SSTable)&lt;/strong&gt;. Sorting allows us to merge segments efficiently (like Merge Sort) and perform range queries.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Modern Architecture:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Memtable:&lt;/strong&gt; All writes go to a balanced tree in memory (AVL or Red-Black Tree).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SSTable:&lt;/strong&gt; When the Memtable gets too big, we flush it to disk as a sorted file.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;WAL (Write-Ahead Log):&lt;/strong&gt; Before writing to the Memtable, we append the operation to a "crash-recovery" log on disk.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;StorageEngine&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&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;value&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# 1. Append to WAL (for crash recovery)
&lt;/span&gt;        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;wal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&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;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# 2. Add to Memtable
&lt;/span&gt;        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;memtable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&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;value&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;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;memtable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;is_full&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;memtable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;flush_to_sstable_on_disk&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;LSM Trees (Log-Structured Merge Trees)&lt;/strong&gt; are used by Cassandra, RocksDB, and LevelDB. They are the kings of write-heavy workloads!&lt;/p&gt;




&lt;h3&gt;
  
  
  💬 Let's Discuss!
&lt;/h3&gt;

&lt;p&gt;Have you ever run into a situation where your database writes were lagging? Did you realize your storage engine might be the bottleneck?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Question for the comments:&lt;/strong&gt; If you were building a high-frequency trading app with millions of updates per second, would you choose an LSM-based store or a traditional RDBMS? Why?&lt;/p&gt;

</description>
      <category>database</category>
      <category>backend</category>
      <category>architecture</category>
      <category>performance</category>
    </item>
    <item>
      <title>Master-Class: Understanding Database Replication (Single, Multi, and Leaderless)</title>
      <dc:creator>Piyush Gupta</dc:creator>
      <pubDate>Sun, 05 Apr 2026 13:39:36 +0000</pubDate>
      <link>https://dev.to/piyush6348/master-class-understanding-database-replication-single-multi-and-leaderless-hhm</link>
      <guid>https://dev.to/piyush6348/master-class-understanding-database-replication-single-multi-and-leaderless-hhm</guid>
      <description>&lt;p&gt;Database Replication is the process of keeping a copy of the same data on multiple nodes. Whether you are aiming for high availability, reduced latency, or horizontal scalability, choosing the right replication algorithm is critical.&lt;/p&gt;

&lt;p&gt;In this guide, we will explore the three primary algorithms used in modern distributed systems: &lt;strong&gt;Single Leader&lt;/strong&gt;, &lt;strong&gt;Multi-Leader&lt;/strong&gt;, and &lt;strong&gt;Leaderless&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Single Leader Replication&lt;/li&gt;
&lt;li&gt;Multi-Leader Replication&lt;/li&gt;
&lt;li&gt;Leaderless Replication&lt;/li&gt;
&lt;li&gt;The Replication Lag Problem&lt;/li&gt;
&lt;li&gt;Summary Comparison&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  1. Single Leader Replication
&lt;/h2&gt;

&lt;p&gt;This is the most common approach (used by MySQL, PostgreSQL, and MongoDB). One node is designated as the &lt;strong&gt;leader&lt;/strong&gt; (master), and all other nodes are &lt;strong&gt;followers&lt;/strong&gt; (read replicas).&lt;/p&gt;

&lt;h3&gt;
  
  
  How it Works
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Writes:&lt;/strong&gt; All write requests must be sent to the leader. The leader writes the data locally and sends the change to all followers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reads:&lt;/strong&gt; Clients can read from the leader or any follower.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Synchronous vs. Asynchronous
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Synchronous:&lt;/strong&gt; The leader waits for followers to confirm the write.

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Pros:&lt;/em&gt; Guaranteed consistency.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Cons:&lt;/em&gt; High latency; if one node fails, the whole write pipeline blocks.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Asynchronous:&lt;/strong&gt; The leader confirms the write immediately.

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Pros:&lt;/em&gt; High performance.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Cons:&lt;/em&gt; Risk of data loss if the leader fails before followers sync.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  Handling Failures
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Follower Failure:&lt;/strong&gt; A follower "catches up" by using its local log to request missing data from the leader.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Leader Failure (Failover):&lt;/strong&gt; Requires detecting failure via timeouts, electing a new leader, and reconfiguring the system.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  2. Multi-Leader Replication
&lt;/h2&gt;

&lt;p&gt;In this setup, more than one node can accept writes. This is typically used for applications spread across multiple geographic data centers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use Cases
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Multi-Data Center Operation:&lt;/strong&gt; Users write to the nearest data center to reduce latency.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Offline Operation:&lt;/strong&gt; Apps like calendars or note-taking tools act as local "leaders" that sync with a server later.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The Challenge: Conflict Resolution
&lt;/h3&gt;

&lt;p&gt;If two users edit the same data in different data centers simultaneously, a conflict occurs.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Conflict Avoidance:&lt;/strong&gt; Routing all writes for a specific record to the same leader.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Convergence:&lt;/strong&gt; Using &lt;strong&gt;Last Write Wins (LWW)&lt;/strong&gt; or &lt;strong&gt;Conflict-free Replicated Data Types (CRDTs)&lt;/strong&gt; to merge changes.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  3. Leaderless Replication
&lt;/h2&gt;

&lt;p&gt;Popularized by Amazon’s Dynamo, this approach allows &lt;strong&gt;any node&lt;/strong&gt; to accept writes and reads. Systems like Cassandra and Riak use this model.&lt;/p&gt;

&lt;h3&gt;
  
  
  Quorums ($n, w, r$)
&lt;/h3&gt;

&lt;p&gt;To maintain consistency without a leader, these systems use quorums:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;$n$: Total number of replicas.&lt;/li&gt;
&lt;li&gt;$w$: Nodes that must confirm a write.&lt;/li&gt;
&lt;li&gt;$r$: Nodes that must be queried for a read.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Rule:&lt;/strong&gt; For a successful read of the latest data, $w + r &amp;gt; n$.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Fixing Stale Data
&lt;/h3&gt;

&lt;p&gt;Since nodes can go down, systems fix stale data via:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Read Repair:&lt;/strong&gt; When a client detects an old version during a read, it pushes the newer value back to that node.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Anti-Entropy:&lt;/strong&gt; A background process that constantly syncs data between replicas.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  The Replication Lag Problem
&lt;/h2&gt;

&lt;p&gt;Regardless of the algorithm, asynchronous replication often results in "replication lag." To maintain a good user experience, developers should implement:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Read-Your-Own-Writes:&lt;/strong&gt; Ensures a user always sees the updates they just made.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monotonic Reads:&lt;/strong&gt; Ensures a user doesn't see data "disappear" when querying different replicas.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consistent Prefix Reads:&lt;/strong&gt; Guarantees that if writes happen in a specific order, they are read in that same order.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Summary Comparison
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Algorithm&lt;/th&gt;
&lt;th&gt;Best For&lt;/th&gt;
&lt;th&gt;Main Downside&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Single Leader&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Read-heavy apps, general simplicity&lt;/td&gt;
&lt;td&gt;Leader is a single point of failure for writes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Multi-Leader&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Multi-region apps, offline capabilities&lt;/td&gt;
&lt;td&gt;Extremely complex conflict resolution&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Leaderless&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;High write throughput, high availability&lt;/td&gt;
&lt;td&gt;Complexities in eventual consistency&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

</description>
      <category>systemdesign</category>
      <category>backend</category>
      <category>database</category>
      <category>distributedsystems</category>
    </item>
  </channel>
</rss>
