In einem System-Design-Interview oder einem Designdokument macht das Diagramm die Überlegungen sichtbar. Eine Box mit der Aufschrift „Cache“ ist schnell gezeichnet; lesenswert wird das Diagramm erst, wenn es zeigt, warum sie da ist, wie viel Traffic sie abfängt und was passiert, wenn der Cache kalt ist.
Dieser Guide führt durch eine klassische Übung, einen URL-Shortener, von den Anforderungen bis zum fertigen System-Design-Diagramm. Es geht nicht um den Shortener selbst, sondern um die Methode: erst Anforderungen und Zahlen, dann API und Daten, dann die Boxen, und jede Entscheidung steht dort, wo alle sie sehen.
Schritt 1: Anforderungen
Funktional:
- Einen Kurzlink für eine lange URL erstellen, optional mit eigenem Alias und Ablaufdatum.
- Einen Kurzlink auf seine lange URL weiterleiten.
- Klicks pro Link zählen.
Nicht-funktional:
- Redirects müssen schnell und hochverfügbar sein; beim Erstellen von Links ist mehr Latenz vertretbar.
- Das System ist leselastig: Links werden einmal erstellt und oft angeklickt.
- Kurzcodes dürfen sich nicht leicht enumerieren lassen.
Schritt 2: Überschlagsrechnung
Nimm 100 Millionen neue Links pro Monat und 100 Redirects pro erstelltem Link an:
| Größe | Schätzung |
|---|---|
| Schreibzugriffe | 100M / 2,6M Sekunden pro Monat ≈ 40 pro Sekunde im Schnitt |
| Lesezugriffe | 100 × 40 ≈ 4.000 Redirects pro Sekunde; plane Spitzen von 10× ein, also 40.000 pro Sekunde |
| Links nach 5 Jahren | 100M × 12 × 5 = 6 Milliarden |
| Speicher | 6 Milliarden × ~500 Bytes ≈ 3 TB, ohne Replikate |
| Codelänge | 7 Zeichen base62 ergeben 62⁷ ≈ 3,5 Billionen Codes |
Die Zahlen prägen das Design bereits: Lesezugriffe dominieren, also bekommt der Lesepfad einen Cache; 3 TB passen nicht für immer auf eine kleine Datenbank, also muss sich das Datenmodell sauber sharden lassen; und 7 Zeichen lassen reichlich Spielraum.
Schritt 3: API
POST /api/links
{ "url": "https://example.com/a/very/long/path", "alias": "launch", "expiresAt": "2027-01-01" }
→ 201 { "code": "launch", "shortUrl": "https://s.example/launch" }
GET /{code}
→ 302 Location: https://example.com/a/very/long/path
Eine Entscheidung verdient eine eigene Zeile im Diagramm: 301 oder 302? Ein 301 ist permanent, also cachen Browser ihn, und wiederholte Besuche erreichen dich nie. Das spart Traffic, kostet aber die Klickzahlen. Ein 302 schickt jeden Klick durch den Redirect-Service, und genau das braucht Analytics. Dieses Design nutzt 302.
Schritt 4: Datenmodell und IDs
Die zentrale Tabelle ist einfach: code (Primärschlüssel), long_url, owner_id, created_at, expires_at. Jeder Lesezugriff ist ein Lookup über code, also funktioniert ein Key-Value-Store ebenso wie eine relationale Datenbank mit Primärschlüssel, und Sharding nach einem Hash von code verteilt die Last gleichmäßig.
Spannend wird es bei der Erzeugung der Codes:
| Ansatz | Vorteile | Nachteile |
|---|---|---|
| Zähler + base62 | Keine Kollisionen | Fortlaufende Codes lassen sich leicht enumerieren; braucht Koordination |
| Zufällige 7 Zeichen | Schwer zu erraten, keine Koordination | Kollisionen müssen beim Einfügen geprüft werden |
| Hash der URL | Gleiche URL ergibt gleichen Code | Kollisionen durch Kürzen; Aliasse brauchen Sonderbehandlung |
Hier reserviert sich die Write-API ID-Bereiche bei einem Allocator für ID-Bereiche, zum Beispiel jeweils eine Million, und verwürfelt jede ID vor der base62-Kodierung mit einer umkehrbaren Permutation. So sind die Codes ohne Kollisionsprüfung eindeutig und für Außenstehende nicht fortlaufend.
Schritt 5: Das Diagramm
Trenne die Pfade, die unterschiedliche Anforderungen haben. Der Schreibpfad hat wenig Volumen und muss korrekt sein; der Lesepfad hat viel Volumen und muss schnell sein; Analytics darf hinterherhinken.
Diagramminhalt
- Users
- Load balancer
- ID range allocator
- Write API
- Redirect service
- Cache: code → URL
- Links DB (sharded by code)
- click events
- Analytics workers
- Analytics store
- HTTPS
- POST · 40/s
- GET · 4k/s, peak 40k/s
- lease ID range
- INSERT link
- GET code
- on cache miss
- click event
- consume
- counts
So liest du es:
- Schreibpfad (oben). Der Load Balancer leitet
POST /api/linksan die Write-API weiter, die eine ID aus ihrem reservierten Bereich nimmt, sie kodiert und den Link in die Datenbank schreibt. - Lesepfad (Mitte).
GET /{code}geht an den Redirect-Service, der zuerst Redis abfragt. Solange die häufig abgerufenen Links in den Speicher passen, erreichen die meisten Redirects die Datenbank nie. Bei einem Cache-Miss liest er aus der Datenbank und füllt den Cache. - Analytics (unten). Jeder Redirect schickt ein Klick-Event an Kafka, und Analytics-Worker aggregieren die Zahlen im Analytics-Store. Der Redirect wartet nie auf Analytics.
Zeichne so, dass die Überlegungen sichtbar werden
- Schreib Zahlen an die Kanten.
40/san der Schreibkante und4k/s, peak 40k/san der Lesekante erklären den Cache besser als jedes Label. - Schreib Annahmen neben die Boxen. „Ziel für die Cache-Hit-Rate: 90 %“, „302 für Analytics“, „IDs in Blöcken von 1M reserviert“.
- Trenne synchron und asynchron. Durchgezogene Kanten für den Request-Pfad, gestrichelte für Klick-Events.
- Zeig, was bei einem Ausfall passiert. Fällt Redis aus, weichen Redirects mit höherer Latenz auf die Datenbank aus; schreib das ins Diagramm.
- Lass die Schätzungen auf dem Canvas. Eine kleine Zahlentabelle neben dem Diagramm macht es zum Designdokument.
Deep Dives, auf die du dich vorbereiten solltest
- Caching. Beliebte Links folgen einer Long-Tail-Verteilung, daher deckt ein LRU-Cache mit moderater TTL den Großteil des Traffics ab. Invalidiere beim Löschen und beim Ablauf.
- Datenbank skalieren. Read Replicas helfen hier weniger als der Cache; Sharding nach Code lässt Schreiblast und Speicher gleichmäßig wachsen.
- Ablauf. Prüfe
expires_atbeim Lesen und räume im Hintergrund auf, statt einen riesigen Lösch-Job laufen zu lassen. - Missbrauch. Begrenze die Link-Erstellung pro Nutzer per Rate-Limit und prüfe Ziel-URLs gegen Malware-Listen.
In Archboard nachbauen
- Melde dich mit Google oder GitHub an und leg ein Diagramm an.
- Füge für die Nutzer einen Internet-Node aus dem Netzwerk-Pack und für den Load Balancer einen Cloud-Lastverteiler aus dem Cloud-Pack hinzu.
- Füge die Write-API, den Redirect-Service, den ID-Allocator und die Analytics-Worker als Container-Nodes aus dem C4-Modell-Pack hinzu, mit der Programmiersprache im Feld Technologie.
- Füge aus dem Daten-Pack Redis für den Cache, Postgres für die Link-Datenbank, ein Thema für die Klick-Events und ein Datenlager für Analytics hinzu.
- Beschrifte die Kanten mit Operationen und Raten, stell die Klick-Events gestrichelt dar und leg die Schätzungen in einen Markdown-Block aus dem Basis-Pack.
Das Beispiel nutzt 11 Diagramm-Nodes, den Markdown-Block mit den Schätzungen eingeschlossen, und bleibt damit im Free-Plan. Die allgemeine Methode hinter jedem Architekturdiagramm findest du unter Wie du ein Softwarearchitektur-Diagramm zeichnest.
FAQ
Wie detailliert sollte ein System-Design-Diagramm im Interview sein? So detailliert, dass Lese- und Schreibpfad, Datenspeicher, Cache und ein asynchroner Teil zu sehen sind. Geh nur dort tiefer, wo im Interview nachgefragt wird.
SQL oder NoSQL für die Links-Tabelle? Für einen Lookup per Primärschlüssel funktioniert beides. Entscheide danach, wie du sharden willst und was dein Team gut betreibt, und schreib die Begründung ins Diagramm.
Sollte ich ein CDN einzeichnen? Nur, wenn du Redirects am Edge cachst. Mit 302 und Klickzählung ist Edge-Caching nur begrenzt nützlich, deshalb lassen viele Designs es weg.
Warum nicht überall 301? Ein 301 spart Traffic, aber Browser fragen dich nicht mehr; du verlierst also Klickdaten und kannst das Ziel für wiederkehrende Besucher nicht mehr ändern.
Wohin gehören die Zahlen? Auf den Canvas, neben das Diagramm, damit alle, die das Design reviewen, die Annahmen hinter den Boxen prüfen können.