Antwort A: Anthropic Claude Opus 5
DIENST FÜR Echtzeit-BENACHRICHTIGUNGEN — SYSTEMDESIGNPLAN
- ANFORDERUNGSÜBERSICHT UND KAPAZITÄTSPLANUNG
Traffic-Mathematik:
- 100 Mio. DAU x 10 Ereignisse/Tag = 1 Mrd. benachrichtigungsauslösende Ereignisse pro Tag.
- Durchschnitt = 1 Mrd. / 86.400 ≈ 11.600 Ereignisse/Sek. Spitzenwert bei 5x ≈ 58.000 Ereignisse/Sek.
- Fan-out-Multiplikator: Die meisten Ereignisse (Like, Kommentar, Follow, DM) zielen auf genau einen Empfänger, daher ist der Fan-out ~1:1. Ereignisse von Accounts mit vielen Followern (Prominente posten) können jedoch Millionen von Empfängern erreichen; behandeln Sie diese als separaten „Bulk-Fan-...
Vollständige Antwort anzeigen ▼
DIENST FÜR Echtzeit-BENACHRICHTIGUNGEN — SYSTEMDESIGNPLAN
- ANFORDERUNGSÜBERSICHT UND KAPAZITÄTSPLANUNG
Traffic-Mathematik:
- 100 Mio. DAU x 10 Ereignisse/Tag = 1 Mrd. benachrichtigungsauslösende Ereignisse pro Tag.
- Durchschnitt = 1 Mrd. / 86.400 ≈ 11.600 Ereignisse/Sek. Spitzenwert bei 5x ≈ 58.000 Ereignisse/Sek.
- Fan-out-Multiplikator: Die meisten Ereignisse (Like, Kommentar, Follow, DM) zielen auf genau einen Empfänger, daher ist der Fan-out ~1:1. Ereignisse von Accounts mit vielen Followern (Prominente posten) können jedoch Millionen von Empfängern erreichen; behandeln Sie diese als separaten „Bulk-Fan-out“-Pfad. Gehen Sie von einer effektiven Spitzenlieferung von 80.000–100.000 Benachrichtigungen/Sek. aus, einschließlich Massenkampagnen.
- Speicher: Verlauf der letzten 100 Benachrichtigungen pro Benutzer. Angenommen ~400 Bytes pro Zeile -> 100 x 400 Byte = 40 KB/Benutzer -> 100 Mio. Benutzer ≈ 4 TB Hot-History, plus Replikationsfaktor 3 ≈ 12 TB. Problemlos teilbar.
- Verbindungen: Angenommen, 20–25 % der DAU sind gleichzeitig online im Spitzenbereich ≈ 20–25 Mio. Live-WebSocket-Verbindungen. Mit ~100.000 Verbindungen pro Gateway-Knoten (getuntes Linux, epoll) sind das 200–250 Knoten plus Puffer.
Nicht-funktionale Ziele:
- Ende-zu-Ende-Latenz p99 unter 2 s für Online-Benutzer (gemessen von der Ereignisaufnahme bis zur Client-Bestätigung).
- 99,9 % Verfügbarkeit = ~43 Minuten Ausfallzeit pro Monat.
- Mindestens einmalige Zustellung mit idempotenter Deduplizierung auf Client-/Serverseite.
- HOCHPEGELARCHITEKTUR
Das Design ist eine ereignisgesteuerte Pipeline mit einer klaren Trennung zwischen dem Ingestion-Pfad (schnell, langlebig, schreiboptimiert) und dem Zustellungspfad (kanalabhängig, wiederholbar).
Fluss:
Produzentendienste (Post Service, Social Graph Service, Comment Service, Messaging Service)
-> Notification API / Gateway (gRPC + REST, Authentifizierung, Ratenbegrenzung, Schema-Validierung, Idempotenzschlüssel)
-> Kafka-Topic notification.events (partitioniert nach recipient_user_id, falls bekannt, sonst nach actor_id)
-> Fan-out-Dienst (ermittelt Empfänger, erweitert Promi-Ereignisse, wendet Aggregationsregeln an)
-> Kafka-Topic notification.deliveries (eine Nachricht pro Empfänger)
-> Präferenz- & Richtliniendienst (Inline-Lookup über Cache: Kanal-Opt-ins, Ruhezeiten, Stummschaltung/Blockierung, Digest vs. Sofort)
-> Router / Dispatcher schreibt in kanal-spezifische Topics:
deliver.websocket, deliver.mobile_push, deliver.web_push, deliver.email
-> Kanal-Worker:
WebSocket-Dispatcher -> Connection Registry Lookup -> Echtzeit-Gateway-Knoten -> Client
Mobile Push-Worker -> APNs (iOS) / FCM (Android)
Web Push-Worker -> VAPID/Web Push-Protokoll über Browser-Push-Dienste
E-Mail-Worker -> SES / SendGrid, mit Vorlagen-Rendering und Digest-Batching
-> Parallel verbraucht ein History Writer Consumer jede Zustellung im Notification History Store und erhöht die Zähler für ungelesene Nachrichten.
Übergreifende Komponenten: Template Service, Device Registry, Connection Registry, Dedup Store, Dead Letter Queues, Observability Stack und eine Admin/Analytics-Ebene, die dieselben Kafka-Streams verbraucht.
- SCHLÜSSELKOMPONENTEN UND VERANTWORTLICHKEITEN
Notification API Gateway
- Zentraler Einstiegspunkt für interne Produzenten (gRPC, Protobuf-Schemas in einem Registry) und für Client-Lese-APIs (REST/GraphQL für Verlauf, als gelesen markieren, Präferenzen).
- Verantwortlichkeiten: Authentifizierung (mTLS Service-to-Service, JWT für Clients), Ratenbegrenzung/Kontingente pro Mandant und pro Produzent, Anforderungsvalidierung, Annahme von Idempotenzschlüsseln und sofortiges, dauerhaftes Anhängen an Kafka. Es gibt schnell 202 Accepted zurück; es führt keine Zustellungsarbeit inline durch.
Ereignisaufnahme / Kafka
- Langlebiges, wiederholbares Protokoll.
notification.eventsmit ~256 Partitionen, Replikationsfaktor 3, min.insync.replicas=2, acks=all, Aufbewahrung 7 Tage für Wiederholung und Vorfallwiederherstellung. - Bietet natürliche Rückstauung und Pufferung für den 5-fachen Spitzenwert, entkoppelt Produzenten von langsamen Drittanbieter-Anbietern.
Fan-out-Dienst
- Löst ein Ereignis in eine Empfängerliste auf. Für 1:1-Ereignisse ist es ein Durchlauf. Für 1:N-Ereignisse (neuer Beitrag für Follower, Gruppen-Thread-Aktivität) ruft es den Social Graph Service seitenweise ab und gibt Empfängernachrichten in Batches aus.
- Hybride Fan-out-Strategie: Push-basiert (Schreiben pro Empfänger) für normale Accounts; Pull-basiert/verzögert für Accounts über einem Follower-Schwellenwert (z. B. 1 Mio.+), bei denen ein einzelner „Feed-Marker“ geschrieben wird und Empfänger beim Lesen materialisiert werden. Dies verhindert, dass ein Promi-Ereignis einen Schreibsturm von 50 Mio. Nachrichten auf dem Hot Path verursacht.
- Ratenbegrenzt Massenexpansionen auf ein separates Low-Priority-Kafka-Topic, damit diese interaktive Benachrichtigungen niemals aushungern.
- Wendet Aggregation/Zusammenführung an: „Alice und 24 andere mochten deinen Beitrag“ anstelle von 25 Zeilen, unter Verwendung eines kurzen gleitenden Fensters (z. B. 30–60 s), das nach (Empfänger, post_id, Typ) in Redis geschlüsselt ist.
Präferenz- & Richtliniendienst
- Speichert und liefert benutzerspezifische Kanalpräferenzen, Opt-ins auf Kategorieebene, Ruhezeiten mit Zeitzone, gerätespezifische Einstellungen, Stummschaltungs-/Blockierlisten und rechtliche Zustimmungsflags (DSGVO/CAN-SPAM).
- Lesepfad wird in Redis mit Write-Through-Invalidierung zwischengespeichert; p99-Lookup-Ziel unter 5 ms. Wahrheitsquelle in einem relationalen Speicher.
- Erzwingt Frequenzbegrenzungen (z. B. maximal N Pushs/Stunde pro Benutzer), um Benutzererfahrung und Anbieterkontingente zu schützen.
Router / Dispatcher
- Ordnet eine genehmigte Zustellung kanal-spezifischen Arbeitselementen zu. Entscheidet „In-App + WebSocket nur, wenn online; andernfalls Mobile Push“ unter Verwendung des Connection Registry und plant E-Mail-Digests anstelle von Sofortsendungen, wenn die Präferenzen dies vorsehen.
Echtzeit-Gateway (WebSocket-Schicht)
- Zustandsbehaftete Ebene, die persistente WebSocket-Verbindungen hält (Fallback: Server-Sent Events, dann Long Polling).
- Bei Verbindung: Authentifizieren, Registrieren (user_id, device_id) -> gateway_node_id im Connection Registry (Redis Cluster, TTL + Heartbeat-Aktualisierung), dann jeden ungelesenen Rückstand pushen.
- Bei Zustellung: Dispatcher sucht Knoten, sendet über einen internen gRPC-Stream oder einen pro-Knoten Kafka/Redis Pub/Sub-Kanal; das Gateway schreibt in den Socket und wartet auf eine Client-Bestätigung.
- Heartbeats alle 30 s; verpasste Heartbeats löschen den Registry-Eintrag und zukünftige Benachrichtigungen fallen automatisch auf Mobile Push zurück.
Kanal-Worker
- Mobile Push-Worker: Stapelt zu APNs (HTTP/2 multiplexed, token-basierte Authentifizierung) und FCM. Behandelt anbieter-spezifische Nebenläufigkeitsgrenzen, exponentielle Backoff mit Jitter und bereinigt ungültige/nicht registrierte Gerätetoken aus dem Device Registry.
- Web Push-Worker: Web Push-Protokoll mit VAPID-Schlüsseln und Payload-Verschlüsselung.
- E-Mail-Worker: Rendert Vorlagen, unterstützt Sofort-, Stunden- und Tages-Digests; behandelt Bounces/Beschwerden über Anbieter-Webhooks und pflegt eine Unterdrückungsliste.
- Alle Worker sind idempotente Consumer, die nach notification_id schlüsseln und den Endstatus zurück in ein
delivery.status-Topic schreiben.
History Writer & Read Path
- Consumer, der Benachrichtigungen speichert und ungelesene Zähler in Redis pflegt (autoritativer Zähler, der periodisch aus dem Speicher abgeglichen wird).
- Read API liefert die letzten 100 Benachrichtigungen aus dem History Store, mit einem Redis-Cache der ersten Seite pro Benutzer für typische Lesevorgänge unter 10 ms.
Unterstützende Dienste
- Template Service: versionierte, lokalisierte Vorlagen mit variabler Interpolation; entkoppelt Kopieränderungen von Code-Deployments.
- Device Registry: device_token, platform, app_version, locale, timezone, last_seen.
- Dedup Store: Redis mit 24h TTL auf (producer_id, idempotency_key), um at-least-once effektiv als once zu verhalten.
- Scheduler: für verzögerte/geplante Benachrichtigungen und Digest-Fenster (zeitlich gruppierte Warteschlangen in Redis-Sortierten Sätzen oder ein dedizierter Scheduler wie eine Kafka-Delay-Topic-Leiter).
- DLQ + Replayer: Poison-Nachrichten werden geparkt und nach Korrekturen wiederholbar.
- DATENMODELL UND DATENBANKWAHLEN
a) Benachrichtigungsverlauf — Cassandra (oder ScyllaDB / DynamoDB)
Tabelle: notifications_by_user
- Partitionsschlüssel: user_id
- Clustering-Schlüssel: created_at DESC, notification_id
- Spalten: type, actor_id(s), target_type, target_id, aggregated_count, preview_text, image_url, deep_link, read_at, channels_sent, created_at
- TTL: 90 Tage; Anwendung begrenzt Lesevorgänge auf 100 Zeilen.
Begründung: Das Zugriffsmuster ist ein einzelner, gut bekannter Partitionsschlüssel mit einem zeitlich geordneten Slice — genau Cassandras Spezialgebiet. Es bietet lineare Schreibskalierbarkeit (wir benötigen 60–100.000 Schreibvorgänge/Sek. nachhaltig), Masterless-Replikation über mehrere Regionen für Verfügbarkeit, abstimmbare Konsistenz (Schreiben QUORUM/LOCAL_QUORUM, Lesen LOCAL_ONE für den Feed) und native TTL für die Aufbewahrung. Wir benötigen hier keine Joins oder Transaktionen über mehrere Zeilen, daher würde ein relationaler Speicher nur Sharding-Probleme und das Risiko von Schreibverstärkungen hinzufügen.
b) Ungelesene Zähler und Hot First Page — Redis Cluster
unread:{user_id}Integer-Zähler;notif:page0:{user_id}zwischengespeicherte JSON-Liste.
Begründung: Zähler werden bei jedem App-Öffnen gelesen (extrem hohe QPS, geringer Wert pro Lesevorgang) und müssen Single-Digit-Millisekunden haben. Redis bewältigt dies kostengünstig; Cassandra-Zähler sind vergleichsweise teuer und fehleranfällig. Zähler werden asynchron abgeglichen, sodass Drift sich selbst behebt.
c) Benutzereinstellungen und Gerätetoken — PostgreSQL (geteilt nach user_id) mit Read-Through-Cache in Redis
Tabellen: user_preferences(user_id, category, channel, enabled, quiet_hours_start, quiet_hours_end, timezone, updated_at), devices(device_id, user_id, platform, push_token, locale, last_seen, active), suppression_list(email, reason, created_at).
Begründung: Diese Daten sind geringvolumig, Lese-intensiv, relational (Benutzer -> Geräte -> Einstellungen pro Kategorie) und profitieren von Transaktionen und Constraints für Korrektheit und Nachvollziehbarkeit (Zustimmungsdatensätze haben Compliance-Gewicht). Das Volumen ist gering genug (~100 Mio. Zeilen), um es problemlos zu teilen und fast vollständig zwischenzuspeichern.
d) Connection Registry — Redis Cluster
conn:{user_id}-> Set von {device_id, gateway_node_id, connected_at}, TTL 90s, aktualisiert durch Heartbeat.
Begründung: Ephemer, extrem hohe Fluktuation, muss schnell sein; Haltbarkeit ist unnötig, da ein verlorener Eintrag anmutig auf Push-Fallback zurückfällt.
e) Dedup / Idempotenz — Redis mit TTL, gesichert durch nichts (Verlust birgt nur das Risiko einer seltenen Duplizierung).
f) Vorlagen und Konfiguration — PostgreSQL + Objektspeicher für Assets, am Edge zwischengespeichert.
g) Analysen — Ereignisse werden von Kafka in einen Data Lake (S3/Parquet) und ein Data Warehouse (Snowflake/BigQuery) gestreamt für Berichte über Zustellungsrate, Öffnungsrate und Latenz; ClickHouse für nahezu Echtzeit-Betriebs-Dashboards.
- EMPFEHLUNGEN ZUR TECHNOLOGIEAUSWAHL
- Sprache/Laufzeit: Go für das Gateway, Echtzeit-Gateway und Worker (Goroutinen und geringer Speicher pro Verbindung eignen sich für Millionen von Sockets); Java/Kotlin akzeptabel für Kafka Streams-intensive Aggregation.
- Messaging: Apache Kafka (verwaltet: MSK/Confluent) als Rückgrat; separate Topics pro Kanal und pro Prioritätsklasse. Kafka Streams oder Flink für fensterbasierte Aggregation/Zusammenführung.
- Echtzeit-Transport: WebSocket über TLS mit SSE und Long-Poll-Fallbacks; NLB/L4-Lastverteilung mit Verbindungsentleerung; Sticky Routing nicht erforderlich, da das Registry den Knoten identifiziert.
- Caching: Redis Cluster (oder Elasticache/MemoryDB) für Zähler, Präferenzen, Registry, Dedup, Ratenbegrenzungen.
- Datenspeicher: Cassandra/ScyllaDB für Verlauf; PostgreSQL (Aurora) für Präferenzen/Geräte; S3 + Data Warehouse für Analysen.
- Push-Anbieter: APNs, FCM, Web Push (VAPID); E-Mail über SES mit SendGrid als sekundärem Anbieter hinter einer Anbieter-Abstraktionsschicht für Failover.
- Infrastruktur: Kubernetes mit HPA/KEDA-Skalierung nach Kafka-Consumer-Verzögerung (nicht nur CPU), Envoy/Istio Service Mesh für mTLS und Wiederholungsversuche, Terraform für IaC.
- Beobachtbarkeit: OpenTelemetry-Tracing (Trace-ID vom Produzentenereignis bis zur Client-Bestätigung weitergeleitet), Prometheus + Grafana-Metriken, strukturierte Logs in Loki/ELK, PagerDuty-Alarmierung bei SLOs.
- Resilienzbibliotheken: Circuit Breaker und Bulkheads pro externem Anbieter, Token-Bucket-Ratenbegrenzer, exponentielle Backoff mit Jitter.
- SKALIERBARKEITS-, LATENZ- UND VERFÜGBARKEITSSTRATEGIEN
Skalierbarkeit
- Jede zustandslose Komponente (API, Fan-out, Router, Worker) skaliert horizontal; die Kafka-Partitionsanzahl ist die Obergrenze für die Parallelität, also provisionieren Sie Partitionen für das 5- bis 10-fache des aktuellen Spitzenwerts von Anfang an (Neupartitionierung ist betrieblich schmerzhaft).
- Autoskalierung bei Consumer-Verzögerung mit KEDA, sodass ein 5-facher Anstieg die Skalierung innerhalb von Sekunden auslöst; halten Sie einen warmen Puffer von 30–40 % vor, da die Skalierung nicht sofort erfolgt.
- Sharding nach user_id konsistent über Cassandra, Postgres und Redis, sodass die Daten eines einzelnen Benutzers lokalisiert sind und die Behandlung von Hot Partitions einheitlich erfolgt.
- Prioritätsspuren: Interaktive Benachrichtigungen (DM, Kommentar zu meinem Beitrag) verwenden ein High-Priority-Topic mit dedizierten Consumer-Gruppen; Bulk-/Marketing-/Promi-Fan-out verwendet eine gedrosselte Low-Priority-Spur. Dies garantiert das 2-Sekunden-SLO für die Benachrichtigungen, die Benutzer tatsächlich bemerken.
- Promi-/Hot-Key-Handling über den oben beschriebenen hybriden Push/Pull-Fan-out, plus gesalzene Partitions-Schlüssel für extrem heiße Ziele.
Niedrige Latenz (unter 2 s p99)
- Der kritische Pfad ist bewusst kurz gehalten: API-Anhang -> Kafka -> Fan-out -> Präferenz-Cache-Treffer -> Registry-Lookup -> WebSocket-Schreiben. Alle Lookups sind Redis (unter 5 ms); keine synchronen Datenbank-Schreibvorgänge blockieren die Zustellung.
- Speicherung des Verlaufs und Analysen erfolgen asynchron, abseits des Zustellpfads.
- Kafka-Produzenten sind mit linger.ms=5 und Komprimierung (lz4) abgestimmt, um Batching gegen Latenz abzuwägen; Consumer verwenden manuelle Commits nach der Verarbeitung.
- Multi-Region-Bereitstellung mit Benutzern, die der nächstgelegenen Region zugeordnet sind, um die RTT zu reduzieren; WebSocket-Verbindungen werden an regionalen Rändern beendet.
- Aggregationsfenster sind pro Typ konfigurierbar und für latenzkritische Typen wie DMs deaktiviert.
- Kontinuierliche synthetische Sonden messen die tatsächliche Ende-zu-Ende-Latenz pro Region und pro Kanal.
Hohe Verfügbarkeit (99,9 %+)
- Keine Single Points of Failure: Multi-AZ für jede Ebene, Kafka RF=3 mit min.insync.replicas=2, Cassandra RF=3 mit LOCAL_QUORUM-Schreibvorgängen, Postgres mit synchronem Standby und automatischem Failover.
- Active-Active Multi-Region für die Echtzeit- und Zustellungsebenen; Cassandra repliziert asynchron über Regionen hinweg, Postgres verwendet regionale Read-Replicas mit einer designierten Schreibregion.
- Anmutige Degradationsleiter: Wenn der WebSocket-Pfad fehlerhaft ist, wird auf Mobile Push zurückgegriffen; wenn der Präferenz-Cache ausfällt, wird auf Postgres und dann auf konservative Standardwerte zurückgegriffen; wenn Cassandra-Schreibvorgänge fehlschlagen, wird die Zustellung in Echtzeit fortgesetzt und die Verlaufsschreibvorgänge werden anschließend aus Kafka wiederholt.
- Wiederholungsversuche mit exponentiellem Backoff plus Jitter, begrenzte Versuche, dann DLQ mit Alarmierung und einem Wiederholungstool.
- Circuit Breaker pro externem Anbieter, damit ein APNs-Ausfall keine Worker-Threads erschöpft und E-Mails blockiert.
- Mindestens einmalige Zustellung plus notification_id-Dedup auf Server und Client; Clients deduplizieren auch beim Wiederverbinden, wenn der ungelesene Rückstand wiederholt wird.
- Zuverlässigkeitspraktiken: Chaos-/Game-Day-Übungen (einen Gateway-Knoten töten und Push-Fallback überprüfen), Lasttests bei 5-fachem Spitzenwert, Blue-Green- und Canary-Deployments, Feature-Flags für kanal-spezifische Kill-Switches, Backpressure-Ablenkung von Low-Priority-Traffic vor High-Priority-Traffic.
- ENGPÄSSE UND KOMPROMISSE
Häufige Engpässe
- Drittanbieter (APNs/FCM/E-Mail): die härteste Grenze, da der Durchsatz nicht uns gehört. Abhilfe durch Verbindungspooling über HTTP/2, Batching, anbieter-spezifische Ratenbegrenzer, Multi-Anbieter-Failover für E-Mail und Warteschlangen-basierte Glättung von Spitzen.
- Promi-Fan-out: Ein einzelner Beitrag kann zig Millionen Zustellungen generieren. Abhilfe durch hybrides Push/Pull, gedrosselte Bulk-Spuren und Aggregation.
- WebSocket-Verbindungsebene: Speicher und Dateideskriptoren pro Knoten, plus Thundering-Herd-Wiederverbindungen nach einem Deploy oder Netzwerk-Glitch. Abhilfe durch abgestimmte Kernel-Limits, gestaffelte Wiederverbindung mit Jitter und exponentiellem Backoff auf Client-Seite und langsame Verbindungsentleerung während Deploys.
- Redis Hot Keys: ein Aggregationsschlüssel eines viralen Beitrags oder ein gemeinsam genutzter Zähler. Abhilfe durch Schlüssel-Salting, lokale In-Prozess-Caches mit kurzen TTLs und Client-seitiges Sharding.
- Cassandra-Schreibverstärkung und Kompaktierungsdruck bei 100.000 Schreibvorgängen/Sek. Abhilfe durch Zeitfenster-Kompaktierung (TWCS), die für Zeitreihen-TTL-Daten geeignet ist, und indem überhaupt keine Benachrichtigungstypen mit geringem Wert im Verlauf gespeichert werden.
- Kafka-Partitions-Skew, wenn nach einem Schlüssel mit geringer Kardinalität partitioniert wird; immer nach recipient_user_id auf dem Zustellungs-Topic partitionieren.
Explizite Kompromisse
- Mindestens einmalige Zustellung gegenüber genau einmaliger Zustellung: Genau einmalige Zustellung über heterogene externe Anbieter hinweg ist unpraktisch und kostspielig. Wir akzeptieren seltene Duplikate und lösen sie mit Idempotenzschlüsseln und Client-seitiger Dedup – billiger und weitaus verfügbarer.
- Eventual Consistency für Zähler und Verlauf gegenüber starker Konsistenz: Eine ungelesene Markierung, die momentan um eins abweicht, ist akzeptabel; Latenz von mehreren Sekunden, um sie zu garantieren, ist es nicht. Abgleichjobs begrenzen die Abweichung.
- Polyglotte Persistenz gegenüber einer einzelnen Datenbank: Dies erhöht den Betriebsaufwand (drei Datenspeicher plus Redis), aber jede Arbeitslast erhält die richtige Engine. Ein einzelner Postgres-Cluster würde bei 1 Mrd. Schreibvorgängen/Tag zum Engpass werden; ein einzelner Cassandra-Cluster würde Präferenzen und die Überprüfung der Zustimmung umständlich machen.
- Push-basierte Fan-out für die meisten Benutzer, Pull-basiert für Prominente: erhöhte Code-Komplexität, aber es ist der einzige Weg, unbegrenzte Schreibstürme zu vermeiden.
- Aggregation verbessert die Benutzererfahrung und reduziert das Zustellungsvolumen drastisch, fügt aber bis zu einem Fenster Latenz für aggregierbare Typen hinzu. Wir halten die Fenster kurz und befreien DMs.
- Multi-Region Active-Active erhöht die Kosten und führt zu Feinheiten bei der übergreifenden Konsistenz, die durch die Verfügbarkeits- und Latenzziele gerechtfertigt sind. Wenn das Budget begrenzt wäre, würde eine Haltung in einer einzelnen Region mit warmem Standby immer noch 99,9 % erreichen, aber mit einer längeren RTO.
- Kafka gegenüber einer einfacheren verwalteten Warteschlange (SQS): mehr Betriebsaufwand, aber wir benötigen Wiederholung, geordnete Partitionen pro Schlüssel, mehrere unabhängige Consumer-Gruppen und eine 7-tägige Aufbewahrung zur Wiederherstellung von Vorfällen.
- Speicherung nur der letzten ~100 Benachrichtigungen mit einer 90-tägigen TTL tauscht Archivvollständigkeit gegen Kosten und Leseleistung; Langzeitdaten leben im Analytics Lake, falls jemals benötigt.
- ROLLOUT-PLAN (PHASENWEISE)
Phase 1: Ingestion API + Kafka + History Writer + Read API (nur In-App-Benachrichtigungen). Etabliert das dauerhafte Rückgrat.
Phase 2: Echtzeit-Gateway, Connection Registry, ungelesene Zähler, WebSocket-Zustellung mit Push-Fallback.
Phase 3: Mobile Push- und Web-Push-Worker, Device Registry, Präferenzdienst und Ruhezeiten.
Phase 4: E-Mail Sofort + Digests, Template Service, Unterdrückungsbehandlung.
Phase 5: Aggregation/Zusammenführung, hybrides Promi-Fan-out, Frequenzbegrenzung.
Phase 6: Multi-Region Active-Active, Chaos-Tests, 5x Lastvalidierung, SLO-Dashboards und Fehlerbudgets.
- WICHTIGSTE METRIKEN UND SLOs
- Ende-zu-Ende p50/p95/p99 Latenz pro Kanal (SLO: p99 unter 2 s für WebSocket).
- Zustellungserfolgsrate pro Kanal; Anbieterfehlerraten und Rate ungültiger Token.
- Kafka-Consumer-Verzögerung pro Topic (primäres Signal für Autoskalierung und Paging).
- WebSocket-Verbindungsanzahl, Abwanderungsrate und ACK-Rate.
- Ungelesene Zählerabweichung, die durch den Abgleich erkannt wird.
- DLQ-Tiefe und -Alter.
- Verfügbarkeit pro API, gemessen aus Sicht des Clients, verglichen mit einem monatlichen Fehlerbudget.
Ergebnis
Siegstimmen
3 / 3
Durchschnittsscore
Gesamtpunktzahl
Gesamtkommentar
Antwort A ist ein herausragendes, hochgradig konkretes Design mit quantifizierten Kapazitätsschätzungen, klar getrennten Ingestions- und Auslieferungspfaden, detaillierten Datenmodellen, Prioritätsspuren, Hybrid-Fan-out, kanal-spezifischer Ausfallsicherheit und umsetzbaren Verfügbarkeits- und Latenzmessungen. Seine stärksten Merkmale sind die expliziten Betriebseinstellungen, die WebSocket-Kapazitätsplanung, die Pfade für den Ausfallabbau und die ungewöhnlich gründliche Analyse von Engpässen und Kompromissen. Die Hauptschwäche besteht darin, dass kein explizites Outbox- oder transaktionales Event-Publishing-Muster in den Quell-Services verwendet wird, was eine potenzielle Lücke zwischen der ursprünglichen Geschäftstransaktion und der dauerhaften Kafka-Ingestion hinterlässt. Einige Details zur Konsistenz über mehrere Regionen hinweg werden ebenfalls auf hoher Ebene behandelt.
Bewertungsdetails anzeigen ▼
Architekturqualität
Gewichtung 30%Die dauerhafte ereignisgesteuerte Pipeline, separate Fan-out- und Kanal-Topics, Richtlinien-Routing, Verbindungsregistrierung, Echtzeit-Gateway, asynchroner History Writer und Prioritätsspuren bilden eine logische Architektur mit klaren Verantwortlichkeiten. Die Hauptlücke ist das Fehlen einer expliziten Outbox im Quell-Service, sodass eine Geschäftstransaktion theoretisch committet werden könnte, ohne dass ihre Benachrichtigung an die Ingestions-API gelangt. Die Beziehung zwischen einem logischen History-Datensatz und mehreren Kanal-Auslieferungen könnte ebenfalls präziser dargestellt werden.
Vollständigkeit
Gewichtung 20%Es werden alle angeforderten Bereiche abgedeckt und darüber hinaus mit Kapazitätsschätzungen, Verbindungsgrößen, detaillierten Schemata, Kanalverhalten, Compliance-Kontrollen, Beobachtbarkeit, Rollout-Phasen und messbaren SLOs. Kleinere Auslassungen sind die transaktionale Veröffentlichung durch die Quelle und eine genauere Erklärung, wie der Store eine strikte Last-100-Richtlinie erzwingt, anstatt nur Lesevorgänge zu begrenzen und TTL anzuwenden.
Trade-off-Analyse
Gewichtung 20%Die Antwort untersucht explizit und korrekt die Zustellung mindestens einmal gegenüber genau einmal, die endliche gegenüber der starken Konsistenz, Polyglot-Persistenz, Push- gegenüber Pull-Fan-out, Aggregationslatenz, Kosten für mehrere Regionen, Kafka gegenüber einfacheren Queues und Aufbewahrungslimits. Die Kompromisse werden mit Anforderungen verknüpft und mit Minderungsstrategien versehen, anstatt sie abstrakt aufzulisten.
Skalierbarkeit und Zuverlässigkeit
Gewichtung 20%Das Design quantifiziert durchschnittlichen und Spitzenverkehr, schätzt die gleichzeitige WebSocket-Kapazität, skaliert Consumer nach Kafka-Lag, reserviert warme Headroom, isoliert Prioritätsverkehr, behandelt Celebrity-Fan-out und spezifiziert Multi-AZ-Replikation, Quorum-Einstellungen, Wiederholungsversuche, DLQs, Circuit Breaker, Fallback-Pfade, Lasttests und Chaos-Übungen. Einige aktive-aktive regionale Datenverhalten und die Atomarität von Quellereignissen erfordern weitere Details.
Klarheit
Gewichtung 10%Trotz seiner Länge erleichtern die nummerierte Organisation, der explizite Ablauf, die benannten Komponenten, Schemata und separaten Abschnitte für Skalierung, Verfügbarkeit, Engpässe, Rollout und Metriken die Navigation im Plan. Einige Aussagen sind übermäßig zuversichtlich oder komprimiert, wie z. B. die Bezeichnung von 100-Mio.-Zeilen-Sharding als trivial, und einige Kanal-/Historien-Semantiken könnten sorgfältiger formuliert werden.
Gesamtpunktzahl
Gesamtkommentar
Eine herausragende Antwort, die ein Systemdesign auf Senior-Niveau verkörpert. Sie ist umfassend, gut strukturiert, quantitativ fundiert und zeigt ein tiefes Verständnis von Kompromissen und operativen Realitäten. Das Design ist sehr detailliert, mit spezifischen Technologieentscheidungen und konkreten Strategien für Skalierbarkeit und Zuverlässigkeit. Die Einbeziehung eines gestaffelten Rollout-Plans und eines dedizierten Abschnitts für Metriken/SLOs hebt es über ein rein theoretisches Design hinaus und lässt es wie ein produktionsreifes Dokument wirken.
Bewertungsdetails anzeigen ▼
Architekturqualität
Gewichtung 30%Die Architektur ist außergewöhnlich solide, detailliert und gut artikuliert. Der ereignisgesteuerte Fluss ist klar, und die Trennung der Zuständigkeiten zwischen Komponenten wie der API, dem Fan-out-Dienst und den kanalspezifischen Workern ist ausgezeichnet. Die Einbeziehung einer hybriden Push/Pull-Fan-out-Strategie für Promi-Konten zeigt ein hochentwickeltes Verständnis des Problembereichs.
Vollständigkeit
Gewichtung 20%Diese Antwort ist außergewöhnlich vollständig. Sie behandelt jeden Teil der Aufgabenstellung im Detail und geht darüber hinaus, indem sie eine detaillierte Kapazitätsabschätzung, einen gestaffelten Rollout-Plan und einen dedizierten Abschnitt für wichtige Metriken und SLOs enthält. Dieses Detailniveau entspricht dem, was man von einem Design-Dokument eines leitenden Ingenieurs erwarten würde.
Trade-off-Analyse
Gewichtung 20%Die Diskussion über Engpässe und Kompromisse ist ausgezeichnet. Sie identifiziert nicht nur potenzielle Probleme, sondern listet auch explizit die getroffenen Design-Kompromisse auf, wie z. B. die Wahl von At-least-once-Delivery gegenüber Exactly-once und die Verwendung von Polyglot Persistence. Die Begründung ist scharf, prägnant und zeigt eine reife Ingenieursperspektive.
Skalierbarkeit und Zuverlässigkeit
Gewichtung 20%Die Strategien für Skalierbarkeit und Zuverlässigkeit sind sowohl detailliert als auch konkret. Es werden spezifische Ansätze wie Autoskalierung bei Kafka-Consumer-Lag mit KEDA, die Verwendung von Prioritätsspuren für verschiedene Verkehrstypen und die Implementierung einer Stufenleiter für die schrittweise Herabstufung erwähnt. Die Einbeziehung von Praktiken wie Chaos Engineering zeigt einen proaktiven Ansatz zur Zuverlässigkeit.
Klarheit
Gewichtung 10%Die Antwort ist außergewöhnlich klar und gut strukturiert. Die Verwendung von nummerierten Abschnitten, einem textbasierten Flussdiagramm am Anfang und prägnanten Aufzählungspunkten macht die große Menge an technischen Informationen sehr leicht verständlich und nachvollziehbar. Der logische Fluss von den Anforderungen bis zu den Metriken ist tadellos.
Gesamtpunktzahl
Gesamtkommentar
Antwort A ist ein Entwurfsdokument auf nahezu Mitarbeiterebene. Es beginnt mit konkreten Kapazitätsberechnungen (Ereignisse/Sekunde, Speicherplatzbedarf, WebSocket-Verbindungsanzahl und Knotenschätzungen), geht dann zu einer klaren Aufteilung zwischen Aufnahme und Auslieferung mit spezifischen Konfigurationsdetails (Kafka-Partitionen, Replikationseinstellungen, Acks, Aufbewahrung), einem hybriden Push/Pull-Fan-out für Promi-Konten, Prioritätsspuren zur Einhaltung des 2-Sekunden-SLO, datenbankspezifischen Datenmodellen mit expliziten Begründungen, einer Stufenleiter für die schrittweise Herabstufung, Chaos-/Game-Day-Praktiken, einem gestaffelten Rollout-Plan und SLO-Metriken über. Der Abschnitt über Kompromisse ist außergewöhnlich: Jede Wahl (mindestens einmal vs. genau einmal, Polyglot-Persistenz, Kafka vs. SQS, Kosten für Aggregationslatenz, Kosten für Multi-Region) wird mit der Alternative und dem Grund für ihre Ablehnung aufgeführt. Kleinere Schwächen: Die Dichte kann das Lesen erschweren, und das Outbox-Muster für die Haltbarkeit von Ereignissen auf der Produzentenseite wird nicht diskutiert.
Bewertungsdetails anzeigen ▼
Architekturqualität
Gewichtung 30%Hervorragende Architektur: klare Aufteilung zwischen Aufnahme/Auslieferung, hybrides Push/Pull-Fan-out mit einem konkreten Follower-Schwellenwert, Prioritätsspuren, die das 2-Sekunden-SLO für interaktive Ereignisse garantieren, dimensionierte Verbindungsebene (20-25 Mio. Sockets, ~100.000 pro Knoten) und spezifische Kafka-Topologie (256 Partitionen, RF=3, min.insync.replicas=2, 7-Tage-Aufbewahrung). Die Verantwortlichkeiten der Komponenten sind präzise und der kritische Pfad ist bewusst frei von synchronen DB-Schreibvorgängen gehalten.
Vollständigkeit
Gewichtung 20%Deckt alle gestellten Anforderungen ab, plus Extras: Kapazitätsschätzung mit Speicherberechnungen, vollständige Datenmodelle für sechs Speicher mit Begründungen, alle vier Kanäle, Digests, Compliance (DSGVO/CAN-SPAM, Unterdrückungslisten), Beobachtbarkeit mit SLOs, ein gestaffelter Rollout-Plan und ein eigener Abschnitt für Engpässe/Kompromisse. Nichts aus der Aufgabenstellung fehlt.
Trade-off-Analyse
Gewichtung 20%Außergewöhnlicher Abschnitt über Kompromisse: Jede Entscheidung nennt die Alternative und den Grund für ihre Ablehnung (mindestens einmal vs. genau einmal, Polyglot-Persistenz vs. einzelne DB, Kafka vs. SQS, Push vs. Pull-Fan-out, Kosten für Active-Active vs. Warm-Standby, Aggregationslatenz vs. Volumen). Kompromisse sind durchgehend in die Begründungen eingewoben und nicht auf einen Abschnitt beschränkt.
Skalierbarkeit und Zuverlässigkeit
Gewichtung 20%Konkret und quantifiziert: Begründung für die Überdimensionierung von Partitionen, KEDA-Autoskalierung bei Consumer-Lag mit 30-40 % Warm-Headroom, gesalzene Hot Keys, TWCS-Kompaktierung für die Schreibrate, explizite Cassandra/Postgres/Kafka-Replikations- und Quorum-Einstellungen, schrittweise Herabstufungsleiter, Circuit Breaker pro Anbieter, Chaos-Tests und 5-fache Lastvalidierung sowie DLQ-Wiederholungswerkzeuge. Koppelt Mechanismen direkt an die Ziele von 100 Mio. DAU / 5-fachem Spitzenwert / 99,9 %.
Klarheit
Gewichtung 10%Hervorragende nummerierte Struktur von den Anforderungen über den Rollout bis zu den Metriken; das Flussdiagramm in Textform erleichtert das Verfolgen der Pipeline. Die Detaildichte macht Abschnitte gelegentlich schwer lesbar, aber Überschriften und eine konsistente Formatierung halten sie navigierbar.