Antwort A: OpenAI GPT-5.6
Systemdesign: skalierbarer URL-Shortener
Annahmen
- Der Weiterleitungsverkehr erreicht Spitzen von 10.000 Anfragen pro Sekunde. Ein nominales Lese-Schreib-Verhältnis von 100:1 impliziert bei diesem Spitzenwert etwa 100 Erstellungen pro Sekunde.
- Dreißig Milliarden Links in fünf Jahren erfordern im Durchschnitt etwa 190 Erstellungen pro Sekunde. Daher werden Speicher und Schreibpfad für mindestens 1.000 Erstellungen pro Sekunde ausgelegt, um diese Zahl zu erreichen und Spitzen abzufangen.
- Links sind standardmäßig unveränderlich. Wenn Löschung oder Zielbearbeitung später unterstützt wird, erfolgt dies über...
Vollständige Antwort anzeigen ▼
Systemdesign: skalierbarer URL-Shortener
Annahmen
-
Der Weiterleitungsverkehr erreicht Spitzen von 10.000 Anfragen pro Sekunde. Ein nominales Lese-Schreib-Verhältnis von 100:1 impliziert bei diesem Spitzenwert etwa 100 Erstellungen pro Sekunde.
-
Dreißig Milliarden Links in fünf Jahren erfordern im Durchschnitt etwa 190 Erstellungen pro Sekunde. Daher werden Speicher und Schreibpfad für mindestens 1.000 Erstellungen pro Sekunde ausgelegt, um diese Zahl zu erreichen und Spitzen abzufangen.
-
Links sind standardmäßig unveränderlich. Wenn Löschung oder Zielbearbeitung später unterstützt wird, erfolgt dies über explizite Versionierung und Cache-Invalidierung.
-
Grundlegende Analysen können letztendlich konsistent sein und während katastrophaler Ausfälle eine sehr geringe Anzahl von Ereignissen verlieren. Die Korrektheit der Weiterleitung hängt nicht von den Analysen ab.
-
Weiterleitungsantworten verwenden HTTP 302 oder 307 anstelle von permanenten 301-Weiterleitungen, um die operative Kontrolle zu erhalten und die Sichtbarkeit der Analysen zu verbessern.
-
Der Dienst läuft aktiv-aktiv in mindestens drei geografischen Regionen und verwendet eine global replizierte Link-Datenbank.
-
Architekturübersicht
Komponenten sind globale DNS- oder Anycast-Weiterleitung, regionale Lastausgleichsmechanismen, zustandslose Weiterleitungsdienste, zustandslose Erstellungsdienste, lokale In-Prozess-Caches, regionale verteilte Caches, eine partitionierte Link-Datenbank, ein dauerhafter Ereignisstrom sowie Analyseprozessoren und -speicher.
Erstellungspfad
- Ein Client sendet die lange URL und optional einen benutzerdefinierten Alias an die nächstgelegene gesunde Region.
- Die API authentifiziert oder begrenzt die Anfragen des Aufrufers, validiert die URL-Syntax, begrenzt die URL-Länge, erlaubt nur unterstützte Schemata wie HTTP und HTTPS und prüft reservierte Aliase.
- Für einen automatisch generierten Link erstellt der Dienst einen kryptografisch zufälligen Code. Für einen benutzerdefinierten Alias normalisiert er den Alias gemäß einer dokumentierten, Groß-/Kleinschreibung beachtenden oder ignorierenden Richtlinie.
- Der Erstellungsdienst führt eine bedingte Einfügung in die autoritative Datenbank durch: Einfügen nur, wenn der Code oder Alias noch nicht existiert.
- Bei einer zufälligen Kollision generiert er einen weiteren Code und versucht es erneut. Bei einer Kollision mit einem benutzerdefinierten Alias gibt er HTTP 409 zurück, ohne den angeforderten Alias stillschweigend zu ändern.
- Nachdem die Datenbank den Schreibvorgang bestätigt hat, fügt der Dienst die neue Zuordnung in den lokalen regionalen Cache ein und sendet eine Cache-Füll- oder Invalidierungsnachricht an andere Regionen.
- Er gibt die Kurz-URL zurück. Ein Anforderungs-Idempotenzschlüssel kann wiederholte Client-Anfragen demselben Ergebnis zuordnen.
Der Schreibvorgang wird erst nach einem Quorum- oder Konsens-Commit bestätigt. Dies erhöht die Latenz bei übergreifenden Zonen und, je nach Datenbankkonfiguration, übergreifenden Regionen, schafft aber eine autoritative globale Eindeutigkeitsgarantie. Die Erstellung ist weitaus weniger latenzempfindlich als der Weiterleitungsverkehr.
Weiterleitungspfad
- Die globale Weiterleitung leitet die Anfrage an die nächstgelegene gesunde Region weiter.
- Der Weiterleitungsdienst validiert und extrahiert den Code.
- Er prüft einen kleinen In-Prozess-Cache. Wenn nicht vorhanden, prüft er den regionalen verteilten Cache.
- Bei einem Cache-Miss führt er eine Punktabfrage in einer lokalen Datenbankreplik durch, wobei der Code als Primärschlüssel verwendet wird.
- Wenn gefunden und aktiv, füllt er beide Cache-Ebenen, sendet asynchron ein Klickereignis und gibt sofort eine 302- oder 307-Antwort mit dem Ziel zurück.
- Wenn nicht gefunden, gibt er 404 zurück. Negative Ergebnisse werden nur kurzzeitig zwischengespeichert.
Der Weiterleitungspfad hat keine synchrone Analyseoperation und unter normalen Bedingungen keinen übergreifenden Netzwerk-Hop. Zustandslose Dienste skalieren horizontal hinter regionalen Lastausgleichsmechanismen.
- Generierung und Eindeutigkeit von Kurzcodes
Ein siebenstelliger Base62-Raum enthält 62^7, etwa 3,52 Billionen, Werte und kann technisch 30 Milliarden Links speichern. Bei 30 Milliarden gespeicherten Links sind jedoch nur etwa 0,85 Prozent dieses Namensraums belegt. Ein zufälliger Massenscanner würde daher etwa einen gültigen Link pro 117 Vermutungen entdecken, was nicht die Anforderung erfüllt, dass Codes schwer zu erraten sind.
Der Standardcode verwendet daher 11 URL-sichere Base62-Zeichen, die aus einer kryptografisch sicheren Zufallsquelle generiert werden. Dies bietet etwa 65,5 Bit und 5,2 × 10^19 Möglichkeiten. Bei 30 Milliarden aktiven Links gelingt eine zufällige Vermutung mit einer Wahrscheinlichkeit von etwa 5,8 × 10^-10. Ratenbegrenzung und Missbrauchserkennung schränken die Enumeration weiter ein. Der Kompromiss ist ein vier Zeichen längerer Link. Siebenstellige Aliase können weiterhin erlaubt sein, wenn sie ausdrücklich von Benutzern gewählt werden, aber sie erhalten nicht die gleiche Garantie der Nicht-Enumerierbarkeit.
Die Zufallsgenerierung vermeidet die Offenlegung der Erstellungsreihenfolge und verteilt die Schlüssel gleichmäßig. Eine bedingte Primärschlüsseleinfügung ist die endgültige Eindeutigkeitsautorität. Geburtstags-Kollisionen über die gesamte Historie hinweg sind in einem Zufallssystem zu erwarten, aber nur gleichzeitige Kandidaten-Kollisionen sind betrieblich relevant: Jeder Einfügungsversuch wird geprüft und wiederholt. Bei der geplanten Belegung des 11-stelligen Raums sind Wiederholungen praktisch nicht vorhanden.
Eine Alternative wäre die Verschlüsselung oder Anwendung einer schlüsselbasierten Permutation auf eine Sequenznummer. Dies garantiert eindeutige generierte Eingaben, erfordert aber die Verwaltung des Schlüssel-Lebenszyklus und die Zuweisung von Sequenzen. Zufallsgenerierung plus bedingte Einfügung ist einfacher, entfernt die zentrale ID-Zuweisung und ist bei dieser Namensraumgröße ausreichend effizient.
Benutzerdefinierte Aliase teilen sich denselben Primärschlüssel-Namensraum wie generierte Codes. Die Alias-Normalisierung erfolgt vor der Einfügung, und eine global konsistente bedingte Einfügung entscheidet über den Gewinner von gleichzeitigen Anfragen. Reservierte Pfade wie Gesundheit, API, Admin und statisch werden abgelehnt. Wenn Aliase Groß-/Kleinschreibung ignorieren, ist die normalisierte Kleinbuchstabenform der Schlüssel, während die angeforderte Anzeigeform separat gespeichert werden kann.
- Datenmodell und Datenbank
Die Felder des autoritativen Link-Datensatzes sind:
code: Primärschlüssel
long_url: Ziel-URL
created_at: Zeitstempel
owner_id: optionale Konto-ID
status: aktiv, deaktiviert oder gelöscht
ttl_or_expiry: optional
version: monoton steigender Wert für Cache-Invalidierung
custom_alias: boolesch
Klickzählungen werden bei jeder Weiterleitung nicht in diesem Datensatz aktualisiert, da dies beliebte Links zu Schreib-Hotspots machen würde.
Der Link-Speicher ist eine verteilte, partitionierte Schlüssel-Wert-Datenbank, die für den Primärschlüsselzugriff optimiert ist, wie z. B. DynamoDB, Bigtable, Cassandra mit sorgfältig verwalteter Konsistenz oder ein äquivalentes intern betriebenes System. Für global eindeutige bedingte Schreibvorgänge muss die ausgewählte Implementierung eine linearisierbare bedingte Erstellung für einen Schlüssel bieten, entweder nativ oder über Shard-weite Konsensführer. Relationale Joins und Bereichsscans sind auf dem Weiterleitungspfad nicht erforderlich.
Der primäre Partitionsschlüssel ist ein Hash des vollständigen Codes. Die Hash-Verteilung verhindert chronologische Hotspots und verteilt sowohl generierte Codes als auch benutzerdefinierte Aliase gleichmäßig. Der logische Schlüsselraum ist in Tausende von virtuellen Shards unterteilt, die neu zugewiesen werden, wenn Knoten hinzugefügt werden. Jeder Shard hat mindestens drei Replikate über Verfügbarkeitszonen hinweg, mit zusätzlichen übergreifenden regionalen Replikaten.
Kapazitätsschätzung
Angenommen, eine durchschnittliche URL von 400 Bytes und etwa 200 Bytes für Schlüssel, Metadaten, Kodierung, Indizes und Overhead der Speicher-Engine. Bei etwa 600 Bytes pro Datensatz benötigen 30 Milliarden Datensätze etwa 18 TB logische Daten. Unter Berücksichtigung längerer URLs, Kompaktierungs-Overhead, Tombstones und operativen Spielraums budgetieren wir 30 TB logische Daten. Drei dauerhafte Replikate erfordern etwa 90 TB, und Backups sowie übergreifende Kopien können die Flottenzuweisung auf etwa 150–250 TB erhöhen. Dies liegt gut im beabsichtigten Bereich von horizontal partitionierten Schlüssel-Wert-Speichern, ist aber für eine einzelne herkömmliche Datenbankinstanz ungeeignet.
Bei 10.000 Weiterleitungen pro Sekunde erzeugt selbst ein vollständiger Cache-Ausfall nur 10.000 zufällige Punktlesevorgänge pro Sekunde. Die Datenbank ist für mindestens 20.000–30.000 Lesevorgänge pro Sekunde pro bedienender Region während eines Failovers und mindestens 1.000 bedingte Erstellungen pro Sekunde ausgelegt. Die Kapazität wird mehr durch die Datensatzgröße, Replikation und Failover-Reserve als durch den normalen Anfrage-Durchsatz bestimmt.
Analysen verwenden separaten Speicher. Ein Stream-Prozessor schreibt pro Code, zeitlich gebündelte Zählungen in einen Analyse-Schlüssel-Wert- oder spaltenorientierten Speicher mit einem Modell wie Code plus Tag oder Stunde als Schlüssel und Zählung als Wert. Eine kompakte Summe kann asynchron aufrechterhalten werden. Die Trennung der Analysen verhindert, dass Zähler für beliebte Links mit Weiterleitungsabfragen konkurrieren.
- Caching-Strategie
Jeder Weiterleitungsprozess verfügt über einen begrenzten LRU- oder TinyLFU-In-Memory-Cache für die heißesten Zuordnungen. Ein regionaler Redis- oder Memcached-kompatibler Cluster bildet die zweite Ebene. Zwischengespeicherte Werte umfassen Ziel, Status, Ablaufdatum und Datensatzversion.
Ein repräsentatives Ziel ist eine regionale Cache-Trefferquote von 95–99 Prozent. Zipf-ähnliche URL-Popularität macht dies im Allgemeinen machbar, auch wenn der gesamte Korpus sehr groß ist. Der Cache speichert heiße Objekte, nicht alle 30 Milliarden Links. Zum Beispiel verbrauchen 100 Millionen Einträge zu je etwa 600 Bytes vor Cache-Overhead und vielleicht 100–150 GB in der Praxis, verteilt über einen regionalen Cache-Cluster.
Zuordnungen sind standardmäßig unveränderlich, daher können positive Einträge eine lange TTL haben, z. B. 6–24 Stunden mit Jitter. Wenn Bearbeitung, Deaktivierung oder Löschung unterstützt wird, wird der autoritative Schreibvorgang zuerst committet und dann eine Invalidierung mit dem Code und der neuen Version an alle Regionen gesendet. Kürzere TTLs begrenzen die Zeit für die Auslieferung veralteter Daten, falls eine Invalidierung verloren geht. Sicherheitskritische Deaktivierungsoperationen können auch eine kleine globale Sperrliste in jedem Weiterleitungsprozess platzieren.
Negative Ergebnisse werden etwa 5–30 Sekunden lang zwischengespeichert, um wiederholte Scans abzuwehren. Der Erstellungspfad invalidiert negative Cache-Einträge, nachdem ein Code erfolgreich beansprucht wurde. Die kurze negative TTL begrenzt ein Rennen, bei dem eine andere Region kurzzeitig einen Miss zwischengespeichert hat, bevor die Replikation oder Invalidierung eintraf.
Bei einem Cache-Miss liest der Weiterleitungsdienst die regionale Datenbankreplik und füllt beide Cache-Ebenen. Anforderungskoaleszenz stellt sicher, dass gleichzeitige Misses für einen neu beliebten Code eine Datenbankanfrage statt Tausende auslösen. TTL-Jitter vermeidet synchronisierte Abläufe. Die Datenbank ist so dimensioniert, dass sie die gesamte Last von 10.000 Anfragen pro Sekunde tragen kann, wenn der verteilte Cache ausfällt, wobei eine etwas höhere Latenz akzeptiert wird, während sie funktionsfähig bleibt.
Der Kompromiss von langen Cache-TTLs ist die potenzielle Veralterung nach Bearbeitungen. Unveränderlichkeit, versionierte Invalidierungen und begrenzte TTLs machen diesen Kompromiss explizit. Die Korrektheit der Weiterleitung für neu erstellte Links kann durch synchrone Füllung der erstellenden Region und Weiterleitung einer sofortigen Leseanfrage an diese Region bei Bedarf verbessert werden.
- Skalierung und Latenz
Weiterleitungsdienste sind zustandslos und skalieren horizontal basierend auf Anfragen pro Sekunde, CPU und p99-Latenz. Wenn eine Instanz sicher 1.000 Anfragen pro Sekunde verarbeitet, könnte jede Region mindestens 15–20 Instanzen für eine regionale Failover-Last von 10.000 Anfragen pro Sekunde betreiben, zuzüglich Headroom für Bereitstellung und Zonenfehler. Die tatsächliche Dimensionierung wird durch Lasttests ermittelt.
Ein normales Latenzbudget für Cache-Treffer beträgt etwa 2–5 ms für Lastausgleich und Anwendungsarbeit, 1–3 ms für eine In-Prozess-Suche oder 2–8 ms für eine regionale verteilte Cache-Suche und einige Millisekunden für die Erstellung der Antwort. Ein Cache-Miss-Budget weist etwa 10–25 ms für eine lokale replizierte Datenbank-Punktabfrage zu. Diese Budgets lassen Raum, um die p99-Latenz auf der Serverseite unter 50 ms zu halten.
Strikte Hop-zu-Hop-Timeouts verhindern, dass ein beschädigter Cache oder eine beschädigte Replik das gesamte Latenzbudget verbraucht. Der Cache-Zugriff kann auf etwa 8 ms und der Datenbankzugriff auf etwa 25–30 ms begrenzt sein, mit Wiederholungsversuchen nur, wenn noch genügend Budget vorhanden ist. Hedged Reads zu einer zweiten lokalen Replik können für das langsamste Perzentil verwendet werden, sind aber verzögert und ratenbegrenzt, um die normale Last nicht zu verdoppeln.
Schlüssel werden über virtuelle Shards hash-partitioniert. Zufällig generierte Codes gleichen den Datenverkehr natürlich aus, während ein außergewöhnlich heißer einzelner Link durch In-Prozess- und regionale Caches absorbiert wird. Wenn ein heißer Schlüssel die Datenbank erreicht, verhindern Anforderungskoaleszenz und replizierte Lesevorgänge, dass ein Speicher-Knoten zum Engpass wird.
Autoskalierung sorgt für ausreichende Kapazität für den Verlust einer gesamten Verfügbarkeitszone und mindestens eine Region, die Weiterleitungsverkehr von einem ausgefallenen Partner empfängt. Regionen laufen unter etwa 50–60 Prozent der Spitzenkapazität. Der Kompromiss ist höhere Leerlaufkosten im Austausch für das Verfügbarkeitsziel von 99,99 Prozent.
- Zuverlässigkeit und Fehlerbehandlung
Verfügbarkeitsziel
Ein monatliches Ziel von 99,99 Prozent erlaubt etwa 4,4 Minuten Nichtverfügbarkeit in einem 30-Tage-Monat. Kein einzelner Cache-Knoten, keine Anwendungsinanz, keine Verfügbarkeitszone oder Region darf für Weiterleitungen erforderlich sein.
Ausfall einer Anwendungsinanz oder -zone
Health Checks entfernen ausgefallene Instanzen und Lastausgleichsmechanismen verteilen Anfragen über mindestens drei Zonen. Dienste verwenden Rolling- oder Canary-Deployments, Connection Draining und automatisiertes Rollback. Die regionale Kapazität übersteht den Verlust einer Zone.
Ausfall eines Cache-Knotens oder -Clusters
Cache-Knoten werden innerhalb einer Region geshardet und repliziert. Wenn ein einzelner Knoten ausfällt, übernimmt seine Replik. Wenn der gesamte Cache nicht verfügbar ist, verwenden Weiterleitungsdienste Circuit Breaker, überspringen Cache-Aufrufe und fragen die Datenbank direkt ab. Datenbankkapazität und Anwendungspool sind explizit für diesen Modus ausgelegt. Admission Control schützt die Datenbank vor unbegrenztem Scanner-Verkehr.
Ausfall eines Datenbank-Knotens
Jeder Shard wird über Zonen hinweg mit Quorum oder Konsens repliziert. Ein ausgefallener Leader wird automatisch ersetzt; Lesevorgänge verwenden eine andere gesunde lokale Replik. Bedingte Erstellungen bleiben während der kurzen Wahl für einen Shard nicht verfügbar, anstatt doppelte Eigentümerschaft zu riskieren. Weiterleitungen können von Replikaten und Caches fortgesetzt werden. Dies bevorzugt die Korrektheit bei der Erstellung, während die Lese-Verfügbarkeit erhalten bleibt.
Ausfall einer Region
Die globale gesundheitsbasierte Weiterleitung entfernt die ausgefallene Region und leitet den Verkehr an die nächstgelegene gesunde Region weiter. Jede bedienende Region verfügt über eine replizierte Kopie der Link-Daten und eine unabhängige Infrastruktur für Weiterleitung, Cache und Ereigniserfassung. Die Cache-Trefferquote ist nach einem Failover zunächst niedriger, daher behalten Standby-Regionen warme Caches für global heiße Links und genügend Datenbank-/Lese-Kapazität für den Kalt-Cache-Anstieg bei.
Bei generierten Codes kann die globale Replikation nach einer konsensgestützten autoritativen Einfügung asynchron erfolgen, wenn die Datenbankarchitektur jeden Schlüssel an einen Home-Shard weiterleitet. Bei benutzerdefinierten Aliassen muss die autoritative bedingte Einfügung global serialisiert bleiben. Wenn ein neu erstellter Link eine überlebende Region vor einem katastrophalen Verlust nicht erreicht hat, kann der Dienst kurzzeitig einen wiederholbaren Fehler anstelle einer falschen Zuordnung zurückgeben. Eine stärkere synchrone Multi-Region-Replikation reduziert dieses Recovery-Point-Fenster, erhöht aber die Erstellungslatenz. Die bevorzugte Konfiguration committet die Link-Erstellung über Replikate in mindestens zwei Regionen, da Schreibvorgänge relativ geringvolumig sind.
Backups und Korruption
Die Datenbank verwendet Prüfsummen, Point-in-Time-Wiederherstellung, unveränderliche Snapshots und regelmäßig getestete Wiederherstellungsverfahren. Löschungen verwenden Tombstones und eine Aufbewahrungsfrist anstelle einer sofortigen physischen Entfernung. Backups schützen vor logischer Korruption, sind aber kein Teil des normalen Weiterleitungs-Failovers.
Verhalten bei Überlastung
Ratenbegrenzungen gelten nach Quelle, Konto und verdächtigen Code-Scanning-Mustern. Erstellungs- und Analyse-Traffic haben eine niedrigere Priorität als Weiterleitungen. Load Shedding lehnt missbräuchliche oder übermäßige Erstellungsanfragen ab, bevor die Weiterleitungs-Kapazität beeinträchtigt wird. Circuit Breaker, begrenzte Warteschlangen und Timeouts verhindern kaskadierende Fehler.
- Klick-Analysen
Nach Auswahl des Weiterleitungsziels erstellt der Dienst ein kompaktes Ereignis mit einer Ereignis-ID, einem Code, einem Zeitstempel, einer Region und optional groben Verweis- oder User-Agent-Feldern. Er platziert das Ereignis in einen begrenzten lokalen asynchronen Puffer und gibt die Weiterleitung zurück, ohne auf die Bestätigung der Analysen zu warten.
Ein regionaler Collector bündelt Ereignisse in einen dauerhaften replizierten Stream wie Kafka, Pulsar oder Kinesis. Stream-Prozessoren aggregieren Ereignisse nach Code und Zeit-Bucket und schreiben dann gebündelte Inkremente in den Analyse-Speicher. Regelmäßige Kompaktierung erzeugt Gesamt-Klickzahlen. Dashboards und APIs lesen den Analyse-Speicher, niemals die autoritative Weiterleitungs-Tabelle.
Ereignis-IDs ermöglichen die nachgelagerte Deduplizierung, wenn Collector erneut versuchen. Die Partitionierung des Streams direkt nach Code würde einen viralen Link auf eine Partition konzentrieren, daher kann der Ingestionsschlüssel Code plus ein zufälliges Stripe sein. Prozessoren aggregieren zuerst gestreifte Zähler und verschmelzen sie dann. Dies ermöglicht die horizontale Skalierung von Hot-Link-Analysen.
Ein rein asynchroner In-Memory-Puffer kann Ereignisse verlieren, wenn ein Weiterleitungsprozess abstürzt. Wenn eine stärkere Dauerhaftigkeit erforderlich ist, kann jeder Host oder Sidecar Batches in ein lokales Write-Ahead-Log anhängen, bevor er sie weiterleitet, aber Weiterleitungsantworten sollten immer noch nicht auf den zentralen Stream warten. Der akzeptierte Kompromiss für grundlegende Analysen ist die endgültige Konsistenz und eine kleine, gemessene Unterzählung während schwerer Ausfälle, im Austausch für die Beibehaltung der Weiterleitungs-Latenz und -Verfügbarkeit.
Ergebnis
Der normale Weiterleitungspfad ist eine lokale Cache-Suche, gefolgt, nur bei Misses, von einer lokalen partitionierten Schlüssel-Wert-Suche. Zufällige 11-stellige Codes verhindern sequentielle Offenlegung und machen erfolgreiches Raten im großen Stil unpraktisch. Bedingte Einfügungen sorgen für Eindeutigkeit, Hash-Partitionierung unterstützt den 30-Milliarden-Datensatz-Korpus, aktiv-aktive regionale Bedienung eliminiert regionale Single Points of Failure und asynchrone gestreifte Analysen halten Zähler-Schreibvorgänge vollständig vom Latenz-kritischen Pfad fern.
Ergebnis
Siegstimmen
3 / 3
Durchschnittsscore
Gesamtpunktzahl
Gesamtkommentar
Antwort A ist ein außergewöhnlich gründliches und technisch fundiertes Design-Dokument. Sie knüpft jede Hauptentscheidung an die angegebenen Einschränkungen: Sie leitet die Schreibrate sowohl aus dem Verhältnis 100:1 als auch aus der Angabe 30B/5 Jahre ab und gleicht die Diskrepanz aus, berechnet explizit, dass ein 7-stelliger Speicherplatz bei 0,85% Belegung (ungefähr 1 Treffer pro 117 Vermutungen) aufzählbar wäre und geht daher zu 11-stelligen Zufallscodes über, liefert eine begründbare Speicherplatzschätzung pro Datensatz und auf Flottenebene (ca. 18 TB logisch, 90 TB repliziert, 150-250 TB mit Backups), gibt ein konkretes Latenzbudget für p99, aufgeteilt in Allokationen pro Hop mit Timeouts und abgesicherten Lesevorgängen, und übersetzt 99,99% in 4,4 Minuten/Monat mit geschichteter Fehlerbehandlung für Instanzen, Caches, Datenspeicher-Shards und ganze Regionen. Kompromisse werden durchweg ehrlich benannt (längere Codes vs. Aufzählbarkeit, schreibende Latenz über Regionen hinweg vs. globale Einzigartigkeit, Leerlaufkapazität vs. Spielraum für Failover, Analyse-Untererfassung vs. Weiterleitungslatenz). Schwächen sind geringfügig: Die Antwort ist lang und dicht, einige Zahlen zur Dimensionierung werden behauptet statt abgeleitet, und eine Zusammenfassung im Diagrammformat würde die Scanbarkeit verbessern. Insgesamt übertrifft sie die Benchmark-Erwartungen in fast jeder Hinsicht.
Bewertungsdetails anzeigen ▼
Architekturqualität
Gewichtung 30%Kohärente Active-Active-Multi-Region-Architektur mit klar getrennten Erstellungs-/Weiterleitungspfaden, bedingten Einfügungen zur Einzigartigkeit, zweistufigem Caching mit Anforderungsbündelung und einer korrekten quantifizierten Ablehnung von 7-stelligen Codes (0,85% Belegung macht Massenratenraten möglich), was zu 11-stelligen CSPRNG-Codes führt. Jede Komponentenentscheidung ist an eine Einschränkung gebunden. Geringfügige Abzüge für Dichte und einige behauptete statt abgeleitete Dimensionierungszahlen.
Vollständigkeit
Gewichtung 20%Alle sieben nummerierten Anforderungen werden mit konkreten Details behandelt: Annahmen werden vorab dargelegt, Schreibraten-Abgleich, vollständige Code-Generierungsanalyse mit Alias-Kollisionsrichtlinie, Speicherberechnung für 30 Milliarden Datensätze, explizites Cache-Miss- und Invalidierungsverhalten, Latenzbudget pro Hop für p99 unter 50 ms, Fehlerbehandlung auf jeder Ebene, die auf das Budget von 4,4 Minuten/Monat abgebildet wird, und gestreifte asynchrone Analysen mit Durabilitäts-Kompromissen.
Trade-off-Analyse
Gewichtung 20%Kompromisse werden durchweg benannt und quantifiziert: 4 zusätzliche Zeichen vs. Aufzählbarkeit mit tatsächlicher Wahrscheinlichkeitsmathematik, Latenz bei der Konsensschreibung über Regionen hinweg vs. globale Einzigartigkeit, lange TTLs vs. Veralterung, die durch versionierte Invalidierungen begrenzt ist, Leerlaufkapazität unter 50-60% Auslastung vs. Verfügbarkeit und akzeptierte Analyse-Untererfassung vs. Weiterleitungslatenz. Alternativen (Schlüsselpermutation von Sequenzen) werden mit Gründen erwogen und abgelehnt.
Skalierbarkeit und Zuverlässigkeit
Gewichtung 20%Konkrete Skalierungsgeschichte: Hash-partitionierte virtuelle Shards, Instanzdimensionierung mit Failover-Spielraum, Datenspeicher, der so bereitgestellt ist, dass er die vollen 10K RPS bei einem vollständigen Cache-Ausfall absorbieren kann, abgesicherte Lesevorgänge und Timeouts pro Hop, Übersetzung von 99,99% in 4,4 Minuten/Monat und geschichtete Fehlerbehandlung, die Instanz-, Zonen-, Cache-, Shard-Leader-Wahl und vollständigen Regionsverlust mit Warm-Standby-Caches abdeckt. RPO-Kompromiss für die regionsübergreifende Replikation wird explizit diskutiert.
Klarheit
Gewichtung 10%Gut organisiert mit nummerierten Abschnitten, die der Aufforderung entsprechen, expliziten Annahmen und einer abschließenden Zusammenfassung. Der Text ist dicht und lang, und einige Abschnitte packen viele Zahlen in Absätze, wo Tabellen oder Aufzählungszeichen helfen würden, aber der Argumentationsfluss ist immer nachvollziehbar.
Gesamtpunktzahl
Gesamtkommentar
Antwort A ist ein sehr starkes, konkretes Systemdesign. Es verknüpft die Architektur explizit mit den 10.000 RPS, dem Lese-/Schreibverhältnis von 100:1, p99 unter 50 ms, dem 30 Milliarden Links umfassenden Korpus, dem Verfügbarkeitsziel von 99,99 % und der Anforderung der Nicht-Erratbarkeit. Es bietet kohärente Lese- und Schreibflüsse, eine starke Kurzcode-Strategie, plausible Speichergrößen, detailliertes Caching-Verhalten, Partitionierung, Multi-Region-Zuverlässigkeit und asynchrone Analysen. Seine Hauptschwäche ist, dass es etwas aufwendig ist, aber die Details sind größtenteils relevant und gut begründet.
Bewertungsdetails anzeigen ▼
Architekturqualität
Gewichtung 30%Antwort A liefert eine kohärente End-to-End-Architektur mit separaten Erstellungs- und Umleitungspfaden, lokalem und verteiltem Caching, autoritativem Schlüssel-Wert-Speicher, Event-Streaming, aktiven/aktiven Regionen und klaren normalen und Fehleranforderungsflüssen. Die Designentscheidungen passen zur Workload und den Latenzbeschränkungen.
Vollständigkeit
Gewichtung 20%Antwort A behandelt jeden erforderlichen Abschnitt im Detail: Schreib-/Leseflüsse, Einzigartigkeit, Kollisionen benutzerdefinierter Aliase, Datenspeicher- und Kapazitätsschätzung, Cache-Miss- und Invalidierungsverhalten, Skalierung und Sharding, Ausfälle von Knoten/Caches/Regionen und asynchrone Analysen. Sie gibt auch Annahmen klar an.
Trade-off-Analyse
Gewichtung 20%Antwort A nennt durchweg Kompromisse, wie z. B. längere Codes gegenüber der Widerstandsfähigkeit gegen Enumeration, Latenz bei Schreibvorgängen im Quorum oder in mehreren Regionen gegenüber der Einzigartigkeit, Veralterung des Cache-TTL gegenüber der Geschwindigkeit, Kosten für zusätzliche Kapazität gegenüber der Verfügbarkeit und Risiko von Analyse-Verlusten gegenüber der Umleitungslatenz.
Skalierbarkeit und Zuverlässigkeit
Gewichtung 20%Antwort A liefert glaubwürdige Skalierungs- und Zuverlässigkeitsdetails: zustandslose horizontale Skalierung, Hash-Partitionierung mit virtuellen Shards, Cache-Größenbestimmung und Fallback, Bereitstellung von Datenspeichern für Cache-Ausfälle, aktive/aktive Multi-Region-Bereitstellung, regionales Failover, Quorum-/Konsensverhalten und asynchrone Analysen, die Hot-Path-Schreibvorgänge vermeiden.
Klarheit
Gewichtung 10%Antwort A ist gut organisiert, strukturiert nach den erforderlichen Abschnitten und verwendet konkrete Zahlen und Mechanismen. Sie ist lang, aber die Struktur macht das Design leicht verständlich.
Gesamtpunktzahl
Gesamtkommentar
Antwort A bietet ein herausragendes und umfassendes Systemdesign. Sie zeichnet sich dadurch aus, dass sie jede Einschränkung direkt mit spezifischen, gut begründeten technischen Entscheidungen anspricht. Ihre Analyse der Erratbarkeit kurzer Codes und der Vorschlag eines 11-stelligen Zufallscodes ist eine Kernstärke. Die Kapazitätsplanung ist detailliert und realistisch, und die Multi-Region-Active-Active-Architektur bietet einen glaubwürdigen Weg zur Erreichung des Verfügbarkeitsziels von 99,99 %. Die Diskussion von Fehlermodi auf jeder Ebene (Knoten, Cache, Region) ist gründlich und zeigt ein tiefes Verständnis für den Aufbau robuster Systeme.
Bewertungsdetails anzeigen ▼
Architekturqualität
Gewichtung 30%Die Architektur ist ausgezeichnet. Sie schlägt von Anfang an korrekt ein Multi-Region-Active-Active-Setup vor, was für die globale Natur und die hohen Verfügbarkeitsanforderungen angemessen ist. Die Komponenten sind gut definiert, und die Anfrageflüsse für Lese- und Schreibpfade sind detailliert und logisch.
Vollständigkeit
Gewichtung 20%Die Antwort ist außergewöhnlich vollständig und behandelt alle sieben erforderlichen Abschnitte mit erheblicher Detailtiefe. Jede funktionale und nicht-funktionale Anforderung wird mit einer spezifischen Designentscheidung abgedeckt.
Trade-off-Analyse
Gewichtung 20%Die Abwägung von Kompromissen ist eine Hauptstärke dieser Antwort. Für fast jede signifikante Entscheidung (z. B. Code-Länge, Wahl des Datenspeichers, Cache-TTL, Replikationsstrategie) wird der spezifische Kompromiss explizit angegeben und im Kontext der Anforderungen begründet.
Skalierbarkeit und Zuverlässigkeit
Gewichtung 20%Dies ist der stärkste Teil der Antwort. Sie identifiziert korrekt, dass 7-stellige Codes bei einer Skala von 30 Milliarden erratbar werden, und schlägt eine robuste Lösung vor. Die Kapazitätsschätzung ist gründlich und realistisch. Der Zuverlässigkeitsplan ist ausgezeichnet und deckt Ausfälle auf Instanz-, Zonen-, Cache-, Datenspeicher- und regionaler Ebene ab, was einen glaubwürdigen Weg zur Erreichung einer Verfügbarkeit von 99,99 % bietet.
Klarheit
Gewichtung 10%Das Dokument ist sehr gut strukturiert, klar und technisch dicht. Es folgt präzise dem geforderten Format, was die Bewertung des Designs anhand der Anforderungen erleichtert.