A daily field guide

Tech Deep-Dives

One system you use every day, taken apart each morning to see how it actually works under the hood.

WhatsApp: a server that carries messages it cannot read

Every WhatsApp message passes through WhatsApp's servers, yet the company says it cannot read them. The design challenge: how do you send a secret to someone who is offline, using a server you do not trust?

Legend: terms used below
End-to-end encryption
Messages are scrambled on the sender's phone and only unscrambled on the receiver's phone. Anything in the middle sees noise.
Key
A secret number used to scramble or unscramble data. Whoever has the right key can read the message.
Public / private key pair
Two linked keys. The public one can be shared with anyone and is used to start a secret; the private one never leaves your phone.
Prekey
A public key you upload to the server ahead of time, so others can start a secret conversation with you while you are offline.
Ratchet
A step that creates a fresh key from the old one and cannot be run backwards. Used so that each message gets its own key.
Forward secrecy
Stealing today's keys does not let anyone read yesterday's messages, because old keys are already gone.

The design

You message a friend whose phone is off. How can your phone agree on a secret with theirs, if they are not there to answer? The trick is that your friend's phone did some homework earlier. When WhatsApp was installed, it made a public and private key pair, kept the private half, and uploaded the public halves to WhatsApp's server. These include a batch of single-use prekeys.

Your phone downloads one of those public keys, mixes it with its own keys, and both sides can arrive at the same shared secret without it ever being sent. Your friend's phone repeats the same math when it comes back online. The server only handed over public keys, which are useless for reading anything.

After that, each message is protected by a ratchet. Every message is locked with a new key made from the previous one, and the old key is thrown away. This is the Signal Protocol, which WhatsApp adopted in 2016 with the Signal team's help.

Messages through a server that cannot read them Your phone gets a public key from the server, then sends an encrypted message through the server to your friend's phone, which holds the private key and can decrypt it. Your phonelocks the message Serversees only noise Friend's phoneunlocks it public key, uploaded earlier
The server stores public keys and carries locked messages. It never holds anything that can unlock them.
The server is a post office that handles locked boxes and never owns a key.

Things this explains

  1. Messages still arrive after your friend was offline for hours. The server holds the locked message until their phone connects.
  2. A new phone cannot read your old chats on its own. The keys lived on the old phone, so history only returns through a backup you chose to make.
  3. "Security code changed" notices appear. When a contact reinstalls the app, their keys change, and your phone tells you so you can notice a possible impostor.

Sources: WhatsApp Encryption Overview whitepaper and Signal Protocol documentation (X3DH and Double Ratchet), from background knowledge; not re-fetched this run.

Kubernetes: you describe the goal, a loop keeps it true

Big apps run as many small programs spread over many machines, and machines break all the time. Kubernetes keeps all of that running without a human restarting things at 3 a.m. The design challenge: how do you keep a messy, failing fleet matching what you asked for?

Legend: terms used below
Container
A packaged program that runs fenced off from other programs on the same machine.
Node
One machine (physical or virtual) in the cluster that runs containers.
Cluster
A group of nodes managed together as if they were one big computer.
Desired state
What you want to be true, such as "three copies of my web server should be running". It is a goal, not a list of steps.
Controller
A small program that repeatedly compares what is true now with the desired state and acts to close the gap.
etcd
A small, reliable database where Kubernetes stores the desired state and the current picture of the cluster.

The design

Say your app is a website that needs three copies running so it survives a crash. With Kubernetes you do not say "start a copy on machine 4, then another on machine 7". You write down a goal: "I want three copies of this container." That goal is the desired state, and it is saved in a small database called etcd.

Then a controller takes over. It runs a never-ending loop: look at what is actually running, compare it with the goal, and fix any difference. Two copies running? Ask for one more. Four? Remove one. It does not care how the gap appeared.

Other pieces do the actual placing. A scheduler picks which node has room for the new copy. An agent on that node then starts the container. Each piece does one narrow job, and they coordinate by reading and writing the shared goal, not by calling each other directly.

The reconcile loop You write a goal into the stored state. A controller compares it with what is running on the nodes, asks for a fix when they differ, and then looks again. Your goal"3 copies" Controllergoal vs. reality Nodesrunning 2 copies look again, forever
The controller never "finishes". It keeps comparing and nudging.
Don't tell it what to do. Tell it what should be true, and let a loop worry about the rest.

Things this explains

  1. Kill a container by hand and a new one appears. The loop sees two copies where the goal says three and starts another.
  2. A machine can die and the app barely notices. Its missing copies are just another gap between goal and reality, so they get recreated elsewhere.
  3. Changing a number in a file can scale an app. Edit "3" to "10", and the loop treats the difference as work to do.

Sources: Kubernetes documentation on controllers and cluster architecture, plus general background knowledge; not re-fetched this run.

Linux: the computer that promises memory it doesn't have

Almost every server you use runs Linux, and Linux happily says "yes" when a program asks for more memory than the machine could ever give. The design challenge: what happens when everyone actually tries to use what they were promised?

Legend: terms used below
Virtual memory
The private memory map each program sees. Its addresses are just promises; the operating system decides later which real chip space backs them.
Page
A small fixed chunk of memory (commonly 4 KB). The operating system hands memory out one page at a time.
Page fault
What happens when a program touches a promised page that has no real memory behind it yet. The operating system steps in and finds some.
Overcommit
Promising out more memory in total than the machine physically has, betting that programs won't use it all at once.
OOM killer
"Out of memory" killer. A part of the Linux kernel that picks a program and force-stops it when real memory runs out.
cgroup
A Linux feature that puts a group of processes under shared limits, such as a maximum amount of memory. Containers like Docker use it.

The design

Imagine a program that asks for 8 GB of memory on a laptop with 4 GB. You might expect an error. On Linux, the request usually succeeds. Nothing has gone wrong yet, because the program has not been given real memory. It has been given virtual memory: a range of addresses that exist only on paper.

Real memory is handed out later, one small page at a time, the first time the program actually touches it. That touch causes a page fault, the kernel quietly grabs a free page, and the program carries on without noticing.

So the kernel is practising overcommit. By default it refuses only the most absurd requests, such as one far larger than the whole machine could ever hold, and accepts the rest.

The bill arrives when too many programs really do use their promises. Free pages run out, the kernel first tries to reclaim memory by dropping cached files, and if that is not enough it calls the OOM killer. It scores the processes, mainly by how much memory each one is holding, and stops the worst offender with a hard kill signal. Nobody gets to clean up.

From a memory promise to a kill A program asks for memory and gets a promise. It touches pages, and the kernel gives real memory on each first touch. If real memory runs out, the OOM killer stops a process. Programasks for 8 GB Promisejust addresses Real pagesgiven on first touch OOM killerwhen none are left saying yes is free; paying up happens later
The kernel says yes at request time and only pays when pages are touched.
Saying yes costs nothing. The cost shows up when everybody collects.

Things this explains

  1. A program can "allocate" more memory than you own and run fine. It never touched most of it, so no real memory was used.
  2. A container dies with exit code 137 and no error message. That code means it was force-stopped by a kill signal, often the OOM killer after it hit its memory cap.
  3. A server gets slow and stuttery before something vanishes. The kernel first scrambles to reclaim memory, and only then kills a process.

Sources: Linux kernel documentation on overcommit accounting and the OOM killer, plus general background knowledge; not re-fetched this run.

Uber: the world cut into hexagons

Uber constantly asks "how many riders and drivers are near here, and what should a ride cost?" for every neighborhood on Earth. The design challenge: how do you turn a round planet into neat, comparable "areas" a computer can count in and look up instantly?

Legend: terms used below
Grid cell
One small, fixed area of the map. Every point on Earth belongs to exactly one cell.
Latitude/longitude
The usual pair of numbers for a spot on Earth. Two nearby spots have similar numbers, but "nearby" is awkward to compute from them.
H3
A grid system Uber built and released as open source. It covers the whole planet in hexagon-shaped cells.
Resolution
How small the cells are. A low resolution means huge cells (a region); a high one means tiny cells (a street corner).
Cell ID
A single number that names one cell. It is how the cell is stored and looked up in a database.
Surge pricing
Raising prices in an area where riders far outnumber available drivers.

The design

Open the Uber app and you see cars drifting on a map. Behind that, Uber needs to ask area-level questions: how many people are requesting rides around the stadium right now, and how many free drivers are close enough to help? Asking this with raw latitude and longitude is clumsy. There is no quick way to say "everything within this neighborhood" from two floating-point numbers.

So Uber chops the planet into grid cells. Every GPS ping from a phone or car is turned into the cell it falls in, and that cell has a single cell ID. Counting riders in a neighborhood becomes "count pings with this cell ID", a simple lookup any database does fast.

The grid Uber built is called H3, and the cells are hexagons. A hexagon has a nice property that squares lack: every neighbor is the same distance from the center. With squares, the diagonal neighbors are farther away than the side ones, which makes "spread out one step" uneven. With hexagons, the six neighbors are all equally close, so questions like "what's around this cell?" give round, fair-looking answers.

Cells also come in sizes. Each resolution level splits every cell into about seven smaller ones that sit roughly inside it. So one cell ID can be zoomed out to its parent (the whole district) or zoomed in to its children (individual blocks), and you pick whichever size suits the question.

From a GPS ping to a price A phone sends its location, which is converted to a cell ID. Requests and free drivers are counted per cell, and the counts decide the price in that cell. Phonesends location Cell IDwhich hexagon? Count per cellriders vs drivers Pricefor that area same cell ID = same neighborhood = easy to group
Once every location is a cell ID, area-level questions become simple counting.
Turn "where exactly?" into "which hexagon?", and a map question becomes a counting question.

Things this explains

  1. Surge prices apply to an area, not to you personally. Your location maps to a cell, and the price comes from that cell's supply and demand.
  2. Walking a block or two can change your price. You may have crossed into a neighboring cell with a different balance of riders and drivers.
  3. Heatmaps of busy areas look like honeycombs. Each hexagon is just one cell's count, colored by how high it is.

Sources: Uber Engineering's H3 announcement and the H3 project documentation (h3geo.org), plus general background knowledge; not re-fetched this run.

BitTorrent: the more people want it, the faster it gets

When a popular file is hosted on one server, every extra downloader makes things slower. BitTorrent flips that: a huge file reaches thousands of people quickly with no big server behind it. The design challenge: how do strangers share pieces of a file without a boss, and without trusting each other?

Legend: terms used below
Peer
Any computer taking part in the sharing. Each peer both downloads and uploads.
Swarm
Everyone currently sharing one particular file, all at once.
Piece
One small chunk of the file. A big file is cut into many pieces so they can be fetched from different peers.
Hash
A short fingerprint computed from some data. If the data changes even slightly, the fingerprint changes completely.
Tracker
A small server that only keeps a list of who is in a swarm. It never holds the file itself.
Choking
BitTorrent's word for refusing to upload to a peer for now. Peers choke those who give little back.

The design

Imagine a new game update that millions of people want today. If it sits on one company's server, that server's internet connection is the bottleneck. BitTorrent avoids this by cutting the file into many pieces and letting everyone who has some pieces hand them to everyone who needs them.

The group sharing one file is a swarm, and each member is a peer. To join, you first need a list of other peers. A small server called a tracker can give you one, and newer setups can find peers through a shared lookup system spread across the peers themselves. Then you connect to a few dozen of them and trade: "which pieces do you have?" "here is piece 7, send me piece 12."

You may be wary of downloading from strangers. The answer is that the small .torrent file (or a magnet link) contains a hash for every piece. After a piece arrives, you check it against its hash. A wrong or tampered piece is thrown away and fetched again from someone else. You never have to trust anyone.

Peers also try to grab the rarest pieces first, the ones few others have. That spreads every piece through the swarm quickly, so the original source can leave without the file becoming incomplete.

Peers swapping pieces A tracker tells peer A who else is in the swarm. Peers A and B then send different pieces directly to each other, and the file never goes through the tracker. Trackerjust a list of peers Peer Ahas pieces 1, 2 Peer Bhas pieces 3, 4 "who else is here?" peers swap pieces directly
The tracker only introduces peers. The actual pieces travel straight between them.
Cut the file into pieces, verify each one, and make every downloader an uploader too.

Things this explains

  1. Popular downloads are fast, obscure ones crawl. Speed depends on how many peers have the pieces you need.
  2. Your download slows when you pause uploading. Peers choke those who give nothing back.
  3. Linux distributions and game patchers offer torrents. It lets them release big files without paying for a giant server.

Sources: the BitTorrent protocol specification (BEP 3) and Bram Cohen's original description, plus general background knowledge; not re-fetched this run.

VS Code: one Python brain, every editor

Open a Python file in VS Code and you get red squiggles, autocomplete and "go to definition". Open it in Vim or Emacs and you get the same things. The design challenge: understanding a programming language is hard work, so how do you avoid rewriting that work for every editor and every language?

Legend: terms used below
Language server
A separate program that understands one programming language. It reads your code and answers questions like "what can go after this dot?".
LSP
Language Server Protocol. A shared set of messages that editors and language servers agree to use when they talk to each other.
JSON-RPC
A simple way to call a function in another program by sending it a small JSON message and getting a JSON reply.
Diagnostics
The list of problems a language server finds in your code: errors, warnings and hints. Editors show them as squiggly underlines.
Go to definition
Jumping from a name you are reading to the place where it was created.

The design

Suppose you type user. in a Python file and the editor pops up a list of things a user can do. Someone has to know what user is, where it came from and what it can do. That means parsing the code, tracking imports and understanding types. It is a lot of work.

Before 2016, each editor did this itself, for each language. Ten editors and twenty languages meant up to two hundred separate pieces of work. Microsoft's answer, created for VS Code, was the LSP. The language knowledge moves into a separate program, a language server. The editor only has to show things and send questions.

The two run as separate processes and talk using JSON-RPC messages, often over plain standard input and output. When you type, the editor tells the server what changed. The server keeps its own picture of your project. When you ask for completions, the editor sends "what fits at line 12, column 5?" and gets a list back. The server can also speak up on its own. After your edit, it sends diagnostics so the editor can draw the squiggles.

An editor talking to a language server The editor sends the server what you typed and what you are asking. The server sends back completions and a list of problems. Editorshows things Language serverunderstands the code "I typed this" / "what fits here?" completions, errors, definitions
The editor knows nothing about Python. It just asks, and the language server answers.
Teach the language once, in a server, and let every editor ask it questions.

Things this explains

  1. A new language often gets good editor support quickly. One language server covers many editors at once.
  2. Squiggles sometimes show up a moment after you stop typing. The server is a separate process that has to catch up and send its findings back.
  3. Autocomplete can feel different from one editor to another. The server gives the options, but each editor decides how to rank and display them.

Sources: the Language Server Protocol specification and Microsoft's overview of it, plus general background knowledge; not re-fetched this run.

Postgres: readers never wait for writers

A busy app runs thousands of queries at once, some reading a row while others change it. The design challenge: how can a database let everyone work at the same time without anyone seeing half-finished changes, and without making readers queue behind writers?

Legend: terms used below
Transaction
A group of reads and writes that the database treats as one unit: either all of it happens or none of it does.
Lock
A "do not touch" sign on data. Anyone else who needs it has to wait until the sign comes down.
MVCC
Multi-version concurrency control. Instead of overwriting data, the database keeps several versions of a row and shows each transaction the version that was current when it started.
Snapshot
The view of the database a transaction gets: everything that was committed when it began, and nothing that happened after.
Vacuum
Postgres's background cleaner. It removes old row versions that nobody can see any more.

The design

Say you are checking your bank balance in an app while a transfer is changing that same balance. The simple way to stay safe is a lock: the transfer locks the row, and your read waits. On a busy system, that means lots of people standing in line.

Postgres does something different, called MVCC. An UPDATE does not overwrite the row. It writes a brand-new version next to the old one and marks the old one as "replaced by transaction 105". Every row version carries the id of the transaction that created it and, if there is one, the id of the transaction that replaced it.

When your transaction starts, it gets a snapshot: roughly, a note of which transactions had finished at that moment. Then, for each row, Postgres shows you the newest version that your snapshot is allowed to see. The transfer's new version is invisible to you until it commits and you start a new query. You read the old balance, the transfer writes the new one, and neither blocks the other.

One row, two versions, two transactions A reader transaction points at the old version of a row (balance 100). A writer transaction creates a new version (balance 60) next to it. Neither waits for the other. Readerstarted earlier Writertransfers money Old versionbalance 100 New versionbalance 60 reads this one writes this one
The reader and the writer touch different versions of the same row, so neither has to wait.
Don't overwrite; add a version, and let each reader pick the one it is allowed to see.

Things this explains

  1. A slow report doesn't freeze your app. It reads its own snapshot and does not hold locks that block writers.
  2. A table can grow even when you only update rows. Each update adds a new version, and the old ones stay until vacuum cleans them up.
  3. A transaction left open for hours is a problem. Its snapshot may still need old versions, so vacuum cannot remove them.

Sources: the PostgreSQL documentation chapter on concurrency control and routine vacuuming, plus general background knowledge; not re-fetched this run.

Figma: many cursors, one design, no "file locked" message

In Figma, you and a teammate can drag the same shapes at the same moment and both see the result instantly. The design challenge: both of you are changing the same data from different computers with network delay between you, so how do you avoid ending up with two different versions of the file?

Legend: terms used below
Server as authority
One central server decides the official order of all changes. Everyone else follows its decisions.
Last-writer-wins
When two changes hit the same value, the one the server received later is kept and the other is overwritten.
Optimistic update
Showing your own change on screen right away, before the server has confirmed it.
CRDT
A data structure designed so that many computers can edit copies independently and always merge to the same result, with no central server needed.

The design

Picture a rectangle on the canvas. You change its colour to red. At the same moment, a teammate changes its colour to blue. Somebody has to decide what the rectangle ends up as, and everyone must see the same answer.

Figma keeps this simple with a server as authority. Every change goes to the server, and the server decides the order. A change is tiny: "object 42, property fill, new value red". Each property of each object is its own little slot. If two people change the same slot, last-writer-wins: whichever arrives at the server second is kept. If you change different slots, such as one person moving a shape and another recolouring it, both changes survive and nothing is lost.

Your screen does not wait for the server. Your edit shows up immediately as an optimistic update. If the server's news about someone else's edit touches a slot you have changed and not yet had confirmed, your app ignores that news for now, so your shape does not flicker back and forth. Once the server confirms your change, everything lines up.

Two editors and one authoritative server Alice and Bob each send an edit to the server. The server picks an order and sends the agreed result back to both of them. Alicefill = red Bobfill = blue Serverpicks the order edits go up agreed result goes back down
Edits flow to one server, which fixes their order. Everyone then converges on the same file.
Different slots merge; the same slot, the server's order decides.

Things this explains

  1. Your own edits feel instant even on slow Wi-Fi. Your screen updates first, and the server's confirmation arrives later.
  2. Sometimes a colour you set quietly changes to someone else's. You both hit the same slot, and the server's order picked the winner.
  3. You can move a shape while a teammate recolours it and both changes stick. They live in different slots, so there is nothing to fight over.

Sources: Figma's engineering blog post "How Figma's multiplayer technology works" and general background knowledge; not re-fetched this run.

HTTPS: how two strangers agree on a secret in public

When you open your bank's website on café Wi-Fi, everything you send passes through machines you do not trust. Yet nobody nearby can read your password. The design challenge: your browser has never talked to this server before, so how can they agree on a secret key while everyone is listening, and how do you know the server is really your bank?

Legend: terms used below
TLS
The protocol that sits under HTTPS. It sets up an encrypted, verified connection before any web page is sent.
Encryption key
A secret number used to scramble data so that only someone with the same key can unscramble it.
Key exchange
A trick that lets two sides end up with the same secret key without ever sending that key across the network.
Certificate
A file where a website claims "this is my name and my public key", signed by someone your device already trusts.
Certificate authority
An organisation whose job is to check who owns a website's name and then sign its certificate.
Digital signature
A value only the owner of a private key can produce, which anyone can check using the matching public key.

The design

Scrambling data is the easy part. Once both sides share one encryption key, they can use fast, simple encryption for the whole conversation. The hard part is getting that key onto both sides when you cannot meet in private first.

That is what TLS does in its first moments, called the handshake. Your browser and the server run a key exchange. Each side picks a throwaway secret number and sends only a number derived from it. Mixing your own secret with the other side's public number gives both of you the same result. A listener sees both public numbers but cannot work out the result. Because the secrets are thrown away afterwards, recording the traffic today does not help if the server is broken into next year.

That alone does not prove who you are talking to. An attacker in the middle could run a key exchange with you and another one with the real server. So the server also sends a certificate and proves it owns it by signing the handshake with its private key, a digital signature. Your device checks that the certificate names the site you asked for, and that it was signed by a certificate authority your device already trusts. Your operating system and browser ship with a list of these.

The TLS handshake in three steps The browser sends its public number. The server replies with its own number, its certificate and a signature. Both sides then derive the same key and send encrypted data. Browseryour device Serverthe website 1. Hello + my public number 2. My number + certificate + signature 3. Same key on both sides: encrypted data flows
Two messages are enough for both sides to share a key, and for the browser to check who it is talking to.
Slow maths to agree on a key, fast maths to use it.

Things this explains

  1. The browser warns you when a certificate has expired or names a different site. Those are exactly the two things it checks: the name, and that a trusted authority signed it.
  2. Padlock sites can still be scams. The certificate proves you reached the owner of that name, not that the owner is honest.
  3. Reconnecting to a site you just visited feels faster. Both sides can reuse what they already agreed, so less of the handshake is repeated.

Sources: RFC 8446 (TLS 1.3) and general background knowledge; not re-fetched this run.

Redis: a database that lives in memory and does one thing at a time

When you open a busy app, it often needs the same small facts again and again: who you are, what is in your cart, how many likes a post has. Asking a normal database on disk every time would be too slow. Redis answers these in a fraction of a millisecond. The design challenge: how do you stay that fast and still not lose everything when the machine restarts?

Legend: terms used below
Cache
A fast place to keep copies of data that is slow to get elsewhere, so the next request is quick.
RAM
The computer's working memory. It is far faster than a disk, but it is wiped when the power goes off.
Key-value store
A database where you save a value under a name (the key) and ask for it back by that name.
Snapshot
A full copy of all the data at one moment, written to disk.
Append-only file
A file where every change is added at the end as one more line, so the data can be rebuilt by replaying it.
Eviction
Deleting some stored data on purpose to make room when memory is full.

The design

Redis is a key-value store that keeps everything in RAM. Your app asks "give me the value for cart:42" and gets it straight from memory, with no disk read in the way. That is why it is so often used as a cache in front of a slower database.

The values are not just text. Redis can hold lists, sets, counters and sorted lists. A game leaderboard, for example, is one sorted list where Redis keeps players ordered by score for you.

The second surprising choice: Redis runs your commands one at a time on a single main thread. No two commands ever run at the same moment, so there are no locks and no half-finished updates to worry about. Adding 1 to a counter is always safe, even with thousands of apps hitting it.

Many clients, one thread, data in memory Several app servers send commands to Redis. A single thread runs them one by one against data in memory. A background copy of the changes is written to disk. Many appssend commands One threadruns one command at a time Data in RAManswers in microseconds Disk: saved copy
Commands queue up, run one by one against memory, and a copy is saved to disk on the side.

Memory is wiped on restart, so Redis offers two ways to save to disk. A snapshot writes everything out every so often. An append-only file adds each change to the end of a file as it happens. Snapshots are compact but can lose the last few minutes; the append-only file loses far less but grows bigger. Many setups use both.

To take a snapshot without freezing the app, Redis asks the operating system to make a copy-on-write clone of its own process. The clone sees the data as it was at that instant and writes it to disk, while the original keeps serving requests.

Fast comes from doing less waiting, not from doing things in parallel.

Things this explains

  1. Apps sometimes show stale data for a moment. A cache holds a copy, and until it expires or is updated, you may see the old one.
  2. Rate limits and like counters rarely go wrong under heavy load. Each increment is one uninterrupted command, so two requests cannot overwrite each other.
  3. A cache restart can make a site briefly slow. If memory is empty, every request falls through to the slower database until the cache fills again.

Sources: Redis documentation (persistence, eviction and the Redis admin pages). Written from background knowledge; not re-fetched this run.

Kafka: a diary that many programs read at their own pace

When you order food or watch a video, dozens of behind-the-scenes programs need to hear about it: billing, recommendations, analytics, fraud checks. Companies like LinkedIn, who built Kafka, needed to move enormous streams of such events between programs without losing any. The design challenge: how do you let many readers consume a firehose of events, each at its own speed, without the sender slowing down?

Legend: terms used below
Event
A small record of something that happened, such as "order 42 was placed".
Log
A list where new items are only ever added at the end and old items are never changed.
Topic
A named stream of events, such as "orders". Think of it as one log with a label.
Partition
One slice of a topic. Splitting a topic into partitions lets several machines share the work.
Offset
The position number of an event in a partition. A reader remembers its offset to know where it stopped.
Consumer
A program that reads events from a topic.
Replica
A backup copy of a partition kept on another machine.

The design

Picture a billing program that is down for ten minutes while orders keep arriving. If the order system sent messages straight to billing, they would be lost, or the order system would have to wait. Kafka sits in the middle instead and simply writes each event down, in order.

The heart of it is a log. Events are added to the end and are not edited or removed when someone reads them. A named stream is called a topic, and each topic is cut into partitions so that many machines can share the load. Events with the same key, say the same customer, go to the same partition, so their order is kept.

Each consumer keeps its own bookmark, called an offset. Billing is at event 900, analytics is at event 1,200, and neither affects the other. A slow or crashed reader just resumes from its bookmark later.

One log, many independent readers An order service appends events to the end of a log. Billing and analytics both read the same log, each from its own position. Order serviceadds events Topic: orders (a log)events kept in order Billingbookmark at 900 Analyticsbookmark at 1,200
The sender only adds to the log. Each reader tracks its own place in it.

To survive machine failures, each partition is copied to other machines as replicas. One copy is the leader that takes new writes, and the others follow it. If the leader's machine dies, a follower that is fully caught up takes over.

The sender writes once. Every reader keeps its own bookmark.

Things this explains

  1. A new feature can read the whole history of events. Events stay in the log for a set retention time, so a new reader just starts from the beginning.
  2. A downstream outage does not lose data or slow the sender. The log keeps filling, and the reader catches up from its bookmark when it returns.
  3. Events about one customer arrive in order, but across customers they may not. Order is only promised inside a single partition.

Sources: Apache Kafka documentation (design section) and Jay Kreps's essay "The Log: What every software engineer should know about real-time data's unifying abstraction". Written from background knowledge; not re-fetched this run.

Docker: a "computer" that is really just a fenced-off process

A teammate sends you an app and says "just run the container." A second later it is running, with its own files, its own network and exactly the software versions it needs, on your laptop. It feels like a tiny virtual computer, but it starts almost instantly. The design challenge: how do you give a program its own private world without paying for a whole second operating system?

Legend: terms used below
Kernel
The core of the operating system. It talks to the hardware and decides which program gets the CPU, memory and files.
Container
An ordinary running program that the kernel has been told to isolate from everything else on the machine.
Namespace
A Linux feature that gives a program its own private view of something, such as the list of running programs, the network or the file system.
Cgroup
A Linux feature that puts a cap on how much CPU and memory a group of programs may use.
Image
The packed-up files a container starts from: the app plus the libraries and tools it needs.
Layer
One step of an image, holding only the files that changed in that step. Layers are stacked to form the full set of files.
Virtual machine
A pretend computer, with its own full operating system, running on top of a real one.

The design

A container is not a small computer. It is a normal program running on your normal kernel, with two kinds of fences put around it.

The first fence controls what it can see. Linux namespaces let the kernel show a program a filtered version of the machine. Inside the container, the app thinks it is the only program running, has its own network address, and sees its own file system as the whole disk. The same machine can show a different view to every container.

The second fence controls what it can use. Cgroups set limits, so one container that goes wild cannot eat all the memory and starve its neighbours.

Containers share one kernel Three containers, each with its own app and files, sit on top of a single shared Linux kernel. Namespaces limit what each container sees and cgroups limit what each can use. The kernel sits on the hardware. Container Aapp + its own files Container Bapp + its own files Container Capp + its own files One shared Linux kernelnamespaces limit what each sees, cgroups limit what each uses
Every container is just a program talking to the same kernel, each inside its own fences.

The other half of Docker is how the files get there. A container starts from an image, and an image is built from stacked layers. One layer might be a base set of system files, the next adds a language runtime, the next adds your app. Each layer stores only what changed.

Because layers are read-only and shared, ten containers from the same image do not copy the files ten times. They all read the same layers, and each gets a thin writable layer on top for its own changes. Edit a file and only that one file is copied up into your private layer.

A container is not a smaller computer. It is a normal program that has been told what it may see and use.

Things this explains

  1. Containers start in about a blink, while virtual machines take a while. There is no operating system to boot, just a program to launch inside its fences.
  2. "Works on my machine" mostly goes away. The image carries the exact libraries and tools the app was tested with, so the container sees the same files everywhere.
  3. Docker on a Mac or Windows laptop quietly runs a small Linux virtual machine. Containers need a Linux kernel to share, so those systems bring one along.

Sources: Linux kernel documentation on namespaces and control groups, and Docker's documentation on images and layers. Written from background knowledge; not re-fetched this run.

Google Maps: the fastest route is a moving target

You ask for directions across a city and get an answer in a blink, along with an arrival time that is usually right. But the "best" route depends on traffic that is changing right now, and the road network has millions of possible paths. The design challenge: how do you search that huge maze quickly, with costs that keep shifting?

Legend: terms used below
Graph
A map reduced to dots and lines. Dots are junctions, lines are the road pieces between them.
Shortest-path search
A method for finding the cheapest way from one dot to another in a graph, where "cheapest" can mean least time.
Road segment
One stretch of road between two junctions, treated as a single unit with its own travel time.
Shortcut
A precomputed jump that skips over many small roads, such as "from this town to that one, via the highway".
Machine-learning model
A program that learns patterns from past examples, here from past traffic, and uses them to make predictions.

The design

Imagine asking a friend the quickest way to the airport. They would not think about every street in the country. They would think: get to the highway, stay on it, then take the airport exit. Maps software does the same, in two steps.

First, the road network is turned into a graph. Each road segment gets a cost, usually its predicted travel time. Finding a route then becomes a shortest-path search.

Second, the search is helped by work done ahead of time. Big roads are the ones almost every long trip uses, so the system can prepare shortcuts between important junctions in advance. When you ask for a route, the search only crawls through small streets near your start and end, and leaps across the middle using the shortcuts.

From traffic to a route Phones on the road report how fast they are moving. A prediction model turns this into a travel time for each road segment. The route finder combines those times with precomputed shortcuts and returns a route and arrival time to you. Phones on roads"moving slowly here" Predictiontime per segment Route finderuses shortcuts Youroute + ETA learns from past traffic too
Live speeds feed a prediction of each road's travel time, and the route finder uses those times plus its shortcuts.

The arrival time is its own problem. A road that is jammed now may be clear by the time you reach it. So Google's research team has described using a machine-learning model that looks at current speeds and at how traffic on neighbouring roads usually behaves, to predict what each segment will be like when you get there, not just what it is like now.

Do the slow thinking before you are asked, then adjust for what is happening now.

Things this explains

  1. Directions come back almost instantly, even for a trip across the country. The search only works hard near the start and end; the middle is covered by precomputed shortcuts.
  2. Maps can reroute you mid-drive when a crash happens ahead. New speed reports change the cost of those segments, and the search runs again with the updated costs.
  3. The arrival time sometimes changes even though you are on the same road. The estimate is a prediction about roads still ahead, and it gets revised as conditions shift.

Sources: Google DeepMind's blog post on traffic prediction with graph neural networks, and academic work on route planning with precomputed shortcuts (contraction hierarchies). Written from background knowledge; not re-fetched this run.

DNS: a phone book nobody owns

Every time you open a website, your device first has to turn a name like example.com into a numeric address. Billions of devices do this all day, and no single computer holds the whole list. The design challenge: how do you answer that question fast, for everyone, with no central owner?

Legend: terms used below
IP address
The number that identifies a machine on the internet. Computers use these, not names, to reach each other.
DNS
The Domain Name System. The shared system that turns names into IP addresses.
Resolver
A helper server, usually run by your internet provider or a company like Google or Cloudflare, that does the looking-up on your behalf.
Cache
A saved copy of an earlier answer, kept so the same question does not have to be asked again.
TTL
"Time to live". A number attached to an answer saying how long others may keep their saved copy before asking again.
UDP
A simple way to send small messages over the internet: fire it off, no handshake first, no promise it arrives.

The design

When you type example.com, your device needs its IP address. Your device does not go hunting for it. It asks a resolver, and the resolver does the work.

The names in DNS are organised like a tree, read right to left. The resolver starts at the top, at the root servers, and asks who handles .com. A .com server then says who handles example.com. Finally that server, the one the site owner chose, gives the actual address.

Each step only points to the next one. No server knows everything, and each one knows only its own slice. That is what lets the system have no central owner: whoever owns a name controls the answers for it.

How a resolver looks up a name Your device asks a resolver. The resolver asks a root server, which points to a .com server. The resolver asks the .com server, which points to the site's own server. The resolver asks that one and gets the address, then returns it to your device. Your deviceexample.com? Resolverdoes the legwork Root servers"ask a .com server" .com servers"ask example.com's server" example.com's server"the address is …" answer saved in cache
The resolver walks down the tree one step at a time. Each server only says who to ask next, until the last one gives the address.

That walk would be slow if it happened every time, so the second half of the design is caching. The resolver remembers answers. If thousands of people on the same provider look up the same popular site, only the first one triggers the walk. Everyone else gets the saved copy straight away.

Each answer comes with a TTL, chosen by the site owner, that says how long the saved copy is allowed to live. Your own device and browser keep a cache too.

No one server knows the answer. Everyone knows who to ask next.

Things this explains

  1. A site you just moved can look broken for some people but not others. Different resolvers hold old saved answers until their TTL runs out.
  2. Switching your DNS provider can make browsing feel snappier. A busy resolver is more likely to already have the answer cached, so it skips the walk.
  3. When DNS has an outage, it feels like "the internet is down" even though servers are fine. Without the lookup you have no address to connect to, so nothing starts.

Sources: RFC 1034 and RFC 1035 (the original DNS specifications), and Cloudflare's learning pages on DNS. Written from background knowledge; not re-fetched this run.

Node.js: one worker, thousands of waiting customers

A chat server or API might have ten thousand people connected at once, and most of them are doing nothing at any given moment. The design challenge: how do you serve all of them without paying for ten thousand threads that mostly sit idle?

Legend: terms used below
Thread
One line of work running inside a program. A program can have many threads running at the same time, but each one costs memory and switching between them costs time.
Blocking
When a thread has to stop and wait for something slow, like a disk read or a reply from another server, and can do nothing else meanwhile.
Event loop
A loop that keeps asking "has anything finished yet?" and, when something has, runs the code that was waiting for it.
Callback
A function you hand over saying "run this when the slow thing is done".
Operating system (OS)
The software that manages the computer. It handles the network card and the disk, and can tell a program when data has arrived.
libuv
The library inside Node.js that runs the event loop and talks to the operating system.

The design

Think about what a web server actually does for one request. It reads a little data, asks a database a question, waits, gets an answer, and sends a reply. Nearly all of the time is waiting. The server's own work takes a tiny slice.

The classic approach gives every connection its own thread. When that thread hits a slow step it is blocked, and the other threads carry on. It works, but ten thousand mostly-asleep threads eat a lot of memory.

Node.js does something different. It runs your JavaScript on one thread, and that thread never waits. When your code says "read this file" or "query this database", Node hands the job to the operating system, along with a callback, and moves on to the next piece of work.

Running underneath is the event loop, built into a library called libuv. It keeps asking the OS "did anything finish?". When a network reply has arrived, it takes the matching callback and runs it on the main thread.

The event loop hands waiting to the OS Many clients send requests to the single JavaScript thread. When a request needs something slow, the thread hands it to the operating system and keeps going. When the slow work finishes, the result returns to the event loop, which runs the waiting callback on the same thread. Many clientsrequests arrive Event loopone JavaScript thread hand off OS does the waitnetwork, disk done: run the callback
The JavaScript thread only does quick work. Anything slow is handed off and comes back later as a callback.

One detail worth knowing: not everything is handed to the OS in the same way. Network connections can be watched efficiently by the OS itself. Some other jobs, like many file operations, are run on a small pool of helper threads that Node keeps behind the scenes. Your own JavaScript still stays on the single main thread either way.

Don't make a thread wait. Tell the OS what you're waiting for, and keep going.

Things this explains

  1. A tiny Node server can hold a huge number of open connections. Idle connections cost almost nothing because no thread is sitting on each one.
  2. One heavy loop can make a whole server unresponsive. All callbacks share one thread, so a long calculation delays every other request in line.
  3. You see callbacks, promises and async everywhere in Node code. They are how you say "carry on with this when the slow thing is done" instead of stopping to wait.

Sources: the Node.js docs page The Node.js Event Loop and the libuv documentation. Written from background knowledge without re-fetching during this run; treat as starting points.

Shazam: naming a song from ten noisy seconds

You hold your phone up in a loud cafe and a few seconds later it names the song. The design challenge: your recording is full of chatter and clinking cups, it starts at a random moment, and the app has to find a match among tens of millions of tracks almost instantly.

Legend: terms used below
Audio fingerprint
A small, compact summary of a piece of audio that stays the same even when the audio is noisy or quiet. It is not the sound itself.
Frequency
How high or low a sound is. A bass note is a low frequency and a cymbal is a high one.
Spectrogram
A picture of a sound with time going left to right and frequency going bottom to top. Brighter spots mean louder.
Peak
A spot on the spectrogram that is louder than everything around it.
Hash
A short code computed from some data. The same data always gives the same code, so codes can be looked up quickly.
Index
A lookup table built ahead of time, so you can jump straight to the entries you want instead of scanning everything.

The design

The obvious idea is to compare your recording against every song, wave against wave. That fails right away. Your clip has background noise, the phone microphone squashes the sound, and you started recording mid-song.

Shazam's approach, described in a 2003 paper by one of its founders, is to throw most of the sound away. First the app turns the clip into a spectrogram. Then it keeps only the peaks, the loudest spots in each small patch of time and frequency. What remains looks like a scatter of dots, like stars on a night sky.

Loud spots are a good thing to keep because they tend to survive noise. A chatty cafe can drown out quiet details, but the strongest notes of the song still poke through.

Single dots are not distinctive enough, since many songs share a loud note. So the app links dots in pairs: one dot, plus a few nearby dots that come just after it. Each pair becomes a small code made from the two frequencies and the time gap between them. That code is the audio fingerprint, or really a bag of hundreds of them.

From a recording to a song name On the phone, a short recording is reduced to loudest peaks and then to small codes. The codes are sent to a server, which looks them up in a prebuilt index of songs and returns the song with the most consistent matches. Recordinga few seconds Peaksloudest dots only Codessent to server Indexall songs Song
The phone does the shrinking. Only the small codes travel to the server, not the audio.

On the server side, every known song went through the same process ahead of time, and all its codes were stored in a giant index, keyed by the code. Each stored entry also remembers which song it came from and when in the song it happened.

When your codes arrive, each one is looked up and returns a list of songs that contain it. Many are coincidences. The trick is timing. If your clip really is from song X, then the codes line up: every match sits at the same offset, say "your clip starts 73 seconds into the song". Coincidences scatter all over the place. The song with the most matches agreeing on one offset wins.

Don't compare the sound. Compare a few loud landmarks and when they happen.

Things this explains

  1. It works when you start mid-song. Codes are matched by their gap to each other, not by where your clip began.
  2. It can work in a loud room but not for a cover. Loud peaks survive noise, yet a different performance has different peaks.
  3. Results come back fast. Only compact codes are sent, and each is a direct lookup instead of a scan over the catalogue.

Sources: Avery Wang, "An Industrial-Strength Audio Search Algorithm" (ISMIR 2003). Written from background knowledge without re-fetching during this run; treat as a starting point.

One address, hundreds of buildings: Cloudflare's anycast

Cloudflare sits in front of a huge share of the web, soaking up traffic and attacks. The design challenge: every visitor needs to reach a nearby machine, and if a building goes dark or a flood of junk traffic arrives, nobody should notice. And ideally nobody has to decide where each visitor goes.

Legend: terms used below
Anycast
Many machines in many places all claim the same IP address, and each visitor gets sent to whichever one is closest in network terms.
IP address
The number that identifies a machine on the internet, a bit like a phone number.
Data center
A warehouse full of servers with fast internet connections. Cloudflare has them in hundreds of cities.
BGP
The way networks tell each other "you can reach this address through me". It is how the internet's routers learn the map.
Router
A machine whose job is to pass internet traffic along, one hop at a time, toward its destination.
DDoS attack
Someone aims a flood of fake traffic at a site to knock it over.

The design

Picture a pizza chain with one phone number. You dial it and the phone network connects you to the shop nearest your house. You never pick a shop, and the chain never needs to know where you live.

That is anycast. Normally an IP address belongs to one place. With anycast, Cloudflare's data centers all around the world announce the same address at the same time. They do it using BGP, the system networks use to tell each other which addresses they can deliver to.

Every router on the way picks the best path it knows. So a visitor in Mumbai tends to end up at a Mumbai building and one in Paris at a Paris building, with no special logic and no lookup table of users.

One address, many data centers Two visitors on the left send traffic to the same address. Each is carried by the internet to a different nearby data center on the right, and both data centers announce that same address. Visitor A Visitor B same destination address same destination address Data center 1nearest to A Data center 2nearest to B
Both visitors aim at the same address. The internet's own routing decides which building each one reaches.

Failure handling comes almost for free. If a data center goes dark, it stops announcing the address. Routers elsewhere forget that path, and traffic that used to land there quietly slides to the next-nearest building.

Nobody sends you to the nearest building. The internet's routing just does it.

Things this explains

  1. Public DNS like 1.1.1.1 is easy to remember. One short address works worldwide, because every location answers to it.
  2. Big sites survive outages you never hear about. A failed building just stops announcing itself and traffic flows around it.
  3. Attacks rarely take a whole network down. The flood is chopped up by geography before it reaches any single machine.

Sources: Cloudflare's anycast explainer and engineering blog posts tagged anycast. Written from background knowledge without re-fetching during this run; treat as starting points.

Git is a filing cabinet that names things by their contents

Millions of developers use Git to save every version of their code, jump back in time, and work on separate copies without stepping on each other. The design challenge: keep the full history of a huge project, cheaply, and notice instantly if anything was ever tampered with or corrupted.

Legend: terms used below
Hash
A short fingerprint computed from some data. The same data always gives the same fingerprint, and even a one-letter change gives a completely different one.
Content-addressable
Stored and looked up by a fingerprint of the content itself, instead of by a name you picked.
Commit
One saved snapshot of the whole project, plus a note about who saved it, when and why.
Branch
A movable label that points at one commit. Making a new one just means adding a label.
Delta
Storing only what changed between two versions, not a full copy of each.

The design

Imagine a filing cabinet where you never choose a label. Instead, a clerk reads each document, works out its hash, and files it under that fingerprint. Ask for the fingerprint, get the exact document back. That is Git's core: a content-addressable store.

Everything is built from just a few kinds of items filed this way. A file's contents. A folder, which is a list of names pointing at file fingerprints. And a commit, which points at the top folder and at the previous commit.

Notice the trick: a commit's fingerprint depends on the fingerprints inside it, including its parent's. So the history is a chain where each link vouches for everything before it. Change one old file and every fingerprint after it changes too.

Commits chained by fingerprints Three commits in a row, each pointing back at the one before. Each commit points at a snapshot folder, and unchanged files are shared between snapshots. Two branch labels point at commits. Commit 1 Commit 2 Commit 3 parent parent Snapshot A Snapshot B Snapshot C unchanged files are shared, not copied
Each commit points at a full snapshot and at its parent. Walking the parents is "viewing history".

Does saving a full snapshot every time eat your disk? No, because of the filing rule. If a file didn't change, its fingerprint didn't change, so the new snapshot simply points at the copy already in the cabinet. Only edited files add anything new.

A branch is then almost free. It is a sticky note with a commit's fingerprint on it. Creating one writes a tiny note; no files are copied. Committing just moves the note forward.

Git doesn't track changes. It stores snapshots, and works out the changes when you ask.

Things this explains

  1. Creating a branch feels instant. It is one tiny label, not a copy of your project.
  2. Those long random-looking commit IDs. They are the fingerprints, and they are the commit's real name.
  3. "Rewriting history" breaks teammates' copies. A rewritten commit has a new fingerprint, so everyone else's copy suddenly disagrees about what the past was.

Sources: Pro Git book, Git Objects and Packfiles; Branches in a Nutshell.

A whole database in one file: SQLite

Your phone's contacts, your browser's history and countless apps all keep their data in a real database, yet none of them runs a database server. SQLite is a database that is just a library and a file. The design challenge: stay correct even when the power dies in the middle of a save.

Legend: terms used below
Database server
A separate program that owns the data. Other programs connect to it over a network and ask it to read or change things. Postgres and MySQL work this way.
Library
Code that gets built into your own program, so it runs inside it and not as a separate program.
Page
A fixed-size chunk of the file. The database reads and writes the file one page at a time.
Transaction
A group of changes that must happen all together or not at all, like moving money between two accounts.
Journal
A safety copy kept on the side while changes are being made, so a crash can be undone cleanly.
WAL (write-ahead log)
A mode where new changes are first added to the end of a separate log file, and only copied into the main file later.
Checkpoint
The moment the log's changes are copied into the main database file and the log is cleared.

The design

Most databases work like a restaurant. You sit at a table (your app), and a kitchen (the database server) does the cooking. SQLite is more like a cookbook on your own shelf. You read it and cook right there in your own kitchen.

Technically, SQLite is a library. When your app asks a question in SQL, the code runs inside your app's own process and reads one ordinary file on disk. No network, no setup, no password. Copying the database means copying the file.

Inside that file, the data is cut into equal-sized pages, and each table is organised as a tree of pages, so looking something up means hopping down a few levels instead of reading everything.

Server database versus SQLite Top row: an app talks over a network to a database server, which reads the data files. Bottom row: an app with SQLite built in reads the single database file directly. App Database server Data files network AppSQLite built in One file no middleman
A normal database has a middleman program. SQLite removes it: the app reads the file itself.

That raises the hard question. If your app writes straight into the file, what happens when the phone dies halfway through saving? You could be left with half-old, half-new data.

SQLite's answer is the transaction. Before changing a page, it first saves a safety copy in a journal. If the power dies, the next program to open the file sees the leftover journal and rolls the file back to how it was. A save either fully happened or never did.

Modern setups often use a different trick, called WAL mode. Instead of copying old pages aside, new changes are simply added to the end of a log file. Readers look at the main file plus the log, so a writer never blocks them. Now and then a checkpoint tidies the log into the main file.

Write-ahead log mode A writer appends changes to the log file. Readers read both the main file and the log. Later a checkpoint copies the log contents into the main file. Writer Log filenew changes added Main file checkpoint Readers readers check both, and never wait for the writer
The writer only ever adds to the end of the log. Later, a checkpoint moves those changes into the main file.
The best database server is the one you never have to run.

Things this explains

  1. Apps recover fine after a crash or dead battery. The leftover journal or log tells SQLite how to roll back the half-finished save the next time the file opens.
  2. Backing up an app's data can be as easy as copying one file. The whole database lives in it. (Copy it while nobody is writing, or use SQLite's backup tool, to avoid grabbing a half-finished state.)
  3. It's a poor fit for a busy multi-user website. Writers queue behind one another, and sharing a database file across a network is risky. That's what database servers are for.

Sources: SQLite documentation, Appropriate Uses For SQLite; Atomic Commit In SQLite; Write-Ahead Logging; Database File Format.

One message, 200,000 readers: inside Discord

Imagine a group chat with 200,000 people. Someone says "hi" and every phone lights up almost instantly. Discord also remembers every message ever sent and can find any of them when you scroll back. It manages both with one simple idea: split the work up so no single worker ever gets overwhelmed.

Legend: terms used below
Server (guild)
What Discord calls a community. Each one has channels like #general. Discord's code calls it a "guild".
WebSocket
A connection between your app and Discord's computers that stays open, so Discord can push a message to you the moment it arrives instead of waiting for you to ask.
Process
A tiny worker inside a program that does one job and talks to other workers by sending messages. Discord's system runs millions of these at once.
Elixir / Erlang
Programming languages built for running huge numbers of these tiny workers. Discord's live chat system is written in Elixir, which runs on Erlang's engine.
Node
One machine (or one copy of the program) in a cluster of many machines working together.
Fan-out
Taking one message and delivering a copy to many recipients.
Partition
A slice of a database stored together. Splitting data into partitions lets many machines share the work.
Hot partition
A slice that gets far more traffic than the others, like one checkout lane with a huge queue while the rest sit empty.
Request coalescing
When many people ask for the same thing at the same moment, do the work once and share the answer.
p99 latency
How slow the slowest 1 in 100 requests is. It shows what unlucky users experience, not just the average.

The design

First, the live part. When you open Discord, your app keeps a WebSocket open to Discord's computers. Every connection gets its own tiny worker (a process), and every server gets one too. Think of it as a switchboard operator for that community. Send a message and it goes to the operator, who passes it on to everyone who is online. All of this runs on Elixir, a language made for exactly this kind of job.

The obvious approach is for the operator to send copies one at a time. That's fine for ten friends. For a giant server it's a traffic jam, because the operator can only do one hand-off at a time. Discord's answer: the operator sends just one copy to each machine (a node), and a helper on that machine passes it to the people connected there. It's still fan-out, but the work is shared between many workers.

Real-time fan-out of one Discord message A message goes from the sender to the HTTP API to the guild process. The guild process sends one message to each Erlang node, and each node fans out locally to the WebSocket sessions of the online members. You HTTP API Guild processone per server Node A1 send Node B1 send Sessionsmany, local Sessionsmany, local HTTPS group recipients by node WebSocket
One message comes in, and the server's operator sends just one copy per machine. Each machine then delivers it to its own connected members, so the work is shared out instead of piling up on one worker.

Now the remembering part. Messages are stored like papers in a filing cabinet: one folder for each channel and stretch of time, with the messages inside kept in order. Every message ID includes the time it was sent, so "show me the latest messages" just means opening the right folder and reading the end.

In front of the database sits a helper layer called the data services. Picture a librarian who gets asked the same question by a big crowd. They look it up once and read the answer out to everyone. That's request coalescing. It works because all questions about one channel go to the same librarian.

Request coalescing in Discord's data services Three API servers ask for the same channel's messages. They are routed by channel ID to the same Rust data service, which sends a single query to the database and returns the one result to all three. API pod 1 API pod 2 API pod 3 Data serviceRust · coalescessame channel ScyllaDB(channel_id, bucket)ordered by message ID route by hash(channel_id) 1 query
Three requests for the same channel arrive. The data service asks the database once (the big pink dot) and shares the answer with all three.
A send is cheap. Thirty thousand sends from one process is a queue.

Things this explains

  1. Big servers only show part of the member list. Updating all 200,000 names for everyone would cause the same traffic jam, so you only get updates for the names on your screen.
  2. Jumping to an old message is fast. Message IDs include the time, so Discord knows which folder to open. (This is my own reasoning from how the storage works, not something Discord says directly.)
  3. An @everyone ping doesn't break things. Thousands of people open the channel at once and ask for the same recent messages. The librarian answers once for all of them.

Sources: Discord Engineering, How Discord Scaled Elixir to 5,000,000 Concurrent Users; Using Rust to Scale Elixir for 11 Million Concurrent Users; How Discord Stores Trillions of Messages.