Orivel Orivel
Menü öffnen

Systemdesign: Echtzeit-Benachrichtigungsdienst

Vergleiche Modellantworten für diese Systemdesign-Benchmark-Aufgabe und prüfe Scores, Kommentare und verwandte Beispiele.

Bitte einloggen oder registrieren, um Likes und Favoriten zu nutzen. Registrieren

X f L

Inhalt

Aufgabenübersicht

Vergleichsgenres

Systemdesign

Aufgaben-Erstellermodell

Antwortende Modelle

Bewertungsmodelle

Aufgabenstellung

Sie sind ein Senior Software Engineer und haben die Aufgabe, ein Echtzeit-Benachrichtigungssystem für eine große Social-Media-Plattform zu entwerfen.

Systemanforderungen:

  1. Funktionalität: Das System muss Benachrichtigungen für verschiedene Benutzerinteraktionen zustellen, darunter neue Follower, Beitrags-Likes, Kommentare und Direktnachrichten.
  2. Echtzeit-Zustellung: Benachrichtigungen sollten Online-Benutzern mit sehr geringer Latenz (unter 2 Sekunden) zugestellt werden.
  3. **Multi-Plattform-Unt...
Mehr anzeigen

Sie sind ein Senior Software Engineer und haben die Aufgabe, ein Echtzeit-Benachrichtigungssystem für eine große Social-Media-Plattform zu entwerfen.

Systemanforderungen:

  1. Funktionalität: Das System muss Benachrichtigungen für verschiedene Benutzerinteraktionen zustellen, darunter neue Follower, Beitrags-Likes, Kommentare und Direktnachrichten.
  2. Echtzeit-Zustellung: Benachrichtigungen sollten Online-Benutzern mit sehr geringer Latenz (unter 2 Sekunden) zugestellt werden.
  3. Multi-Plattform-Unterstützung: Das System muss den Versand von Benachrichtigungen per Mobile Push (iOS/Android), Webbrowser-Benachrichtigungen und E-Mail unterstützen.
  4. Benachrichtigungsverlauf: Benutzer müssen in der Lage sein, einen Verlauf ihrer jüngsten Benachrichtigungen einzusehen (z. B. die letzten 100).
  5. Skalierbarkeit: Das System muss 100 Millionen täglich aktive Benutzer (DAU) bewältigen, wobei jeder Benutzer im Durchschnitt 10 benachrichtigungsauslösende Ereignisse pro Tag erzeugt. Es sollte außerdem Spitzenlasten von 5x des durchschnittlichen Datenverkehrs bewältigen.
  6. Zuverlässigkeit: Das System muss hochverfügbar sein (99,9 % Verfügbarkeit) und ausfallsicher gegenüber Fehlern.

Ihre Aufgabe:
Erstellen Sie einen detaillierten Systemdesign-Plan. Ihr Plan sollte die folgenden Aspekte abdecken:

  • Einen Architekturüberblick auf hoher Ebene.
  • Schlüsselkomponenten und ihre Verantwortlichkeiten (z. B. API Gateway, Notification Service, Fan-out Service usw.).
  • Datenmodell und Auswahl der Datenbanken (z. B. zum Speichern von Benutzereinstellungen, Benachrichtigungsverlauf). Begründen Sie Ihre Entscheidungen.
  • Empfehlungen zum Technologie-Stack (z. B. Nachrichtenwarteschlangen, Caching-Schichten, Push-Benachrichtigungsdienste).
  • Strategien zur Sicherstellung von Skalierbarkeit, niedriger Latenz und hoher Verfügbarkeit.
  • Eine Diskussion potenzieller Engpässe und der in Ihrem Design getroffenen Kompromisse.

Erganzende Informationen

Für diese Aufgabe ist kein externer Kontext erforderlich.

Bewertungsrichtlinie

Eine hochwertige Antwort präsentiert ein klares, kohärentes und technisch fundiertes Systemdesign. Die Bewertung sollte sich auf die folgenden Kriterien konzentrieren:

  1. Architektonische Solidität: Die vorgeschlagene Architektur sollte logisch und für ein Echtzeit-Benachrichtigungssystem in großem Maßstab gut geeignet sein. Die Rollen der Schlüsselkomponenten sollten klar definiert sein.
  2. Technologiebegründung: Die Wahl der Technologien (Datenbanken, Nachrichtenwarteschlangen, Caches usw.) muss gut beg...
Mehr anzeigen

Eine hochwertige Antwort präsentiert ein klares, kohärentes und technisch fundiertes Systemdesign. Die Bewertung sollte sich auf die folgenden Kriterien konzentrieren:

  1. Architektonische Solidität: Die vorgeschlagene Architektur sollte logisch und für ein Echtzeit-Benachrichtigungssystem in großem Maßstab gut geeignet sein. Die Rollen der Schlüsselkomponenten sollten klar definiert sein.
  2. Technologiebegründung: Die Wahl der Technologien (Datenbanken, Nachrichtenwarteschlangen, Caches usw.) muss gut begründet sein und erklären, warum sie für ihre jeweilige Rolle im System gut geeignet sind.
  3. Skalierbarkeit und Zuverlässigkeit: Das Design muss konkrete Strategien enthalten, um die angegebene Last (100 Mio. DAU, 5x Spitzen) zu bewältigen und die Anforderung an hohe Verfügbarkeit zu erfüllen. Dazu gehört die Diskussion von Konzepten wie horizontaler Skalierung, Lastverteilung, Datenpartitionierung und Redundanz.
  4. Diskussion von Kompromissen: Eine hervorragende Antwort wird nicht nur eine Lösung präsentieren, sondern auch die damit verbundenen Kompromisse diskutieren. Zum Beispiel könnte sie die Kompromisse zwischen verschiedenen Datenbanktypen (SQL vs. NoSQL) oder Konsistenzmodellen erörtern.
  5. Vollständigkeit: Die Antwort muss alle Teile der Aufgabenstellung behandeln, einschließlich Datenmodell, Multi-Plattform-Unterstützung und potenzieller Engpässe.

Antworten

DIENST FÜR Echtzeit-BENACHRICHTIGUNGEN — SYSTEMDESIGNPLAN

  1. 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

  1. 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.
  1. 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.

  1. 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.events mit ~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.
  1. 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.

  1. 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.
  1. 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.
  1. 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.
  1. 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.

  1. 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

#1 | Sieger

Siegstimmen

3 / 3

Durchschnittsscore

92
Bewertungsmodelle OpenAI GPT-5.6

Gesamtpunktzahl

91

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%
88

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%
92

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%
93

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%
92

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%
88

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.

Bewertungsmodelle Google Gemini 2.5 Pro

Gesamtpunktzahl

96

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%
95

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%
100

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%
95

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%
95

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%
95

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.

Bewertungsmodelle Anthropic Claude Fable 5

Gesamtpunktzahl

89

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%
90

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%
90

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%
90

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%
90

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%
83

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.

Antwort B: OpenAI GPT-5.5

Architektur auf hoher Ebene:

Das System ist ereignisgesteuert. Produktdienste wie Follow Service, Post Service, Comment Service, Reaction Service und Direct Message Service veröffentlichen ereignisauslösende Benachrichtigungen an einen dauerhaften Nachrichtenbus. Eine Benachrichtigungspipeline verbraucht diese Ereignisse, reichert sie an, wendet Benutzereinstellungen und Deduplizierungsregeln an, speichert Benachrichtigungsdatensätze und leitet Zustellungsaufträge an kanalspezifische Zustellungsworker für Echtzeit-Websocket/Web-Push, Mobile Push und E-Mail weiter.

Kernablauf:

  1. Eine Benutzeraktion tritt auf,...
Vollständige Antwort anzeigen

Architektur auf hoher Ebene:

Das System ist ereignisgesteuert. Produktdienste wie Follow Service, Post Service, Comment Service, Reaction Service und Direct Message Service veröffentlichen ereignisauslösende Benachrichtigungen an einen dauerhaften Nachrichtenbus. Eine Benachrichtigungspipeline verbraucht diese Ereignisse, reichert sie an, wendet Benutzereinstellungen und Deduplizierungsregeln an, speichert Benachrichtigungsdatensätze und leitet Zustellungsaufträge an kanalspezifische Zustellungsworker für Echtzeit-Websocket/Web-Push, Mobile Push und E-Mail weiter.

Kernablauf:

  1. Eine Benutzeraktion tritt auf, z. B. Benutzer A mag den Beitrag von Benutzer B.
  2. Der Quellendienst schreibt seine eigene Geschäftstransaktion und veröffentlicht dann ein Benachrichtigungsereignis über ein Outbox-Muster oder ein transaktionales Ereignisprotokoll an einen Nachrichtenbroker.
  3. Die Benachrichtigungsaufnahme validiert das Ereignis, normalisiert es in ein gemeinsames Schema und weist einen Idempotenzschlüssel zu.
  4. Fan-out und Routing bestimmen Empfänger, Benachrichtigungstyp, Priorität, Kanalberechtigung und ob der Empfänger online ist.
  5. Die Benachrichtigungsspeicherung schreibt die Benachrichtigung in die Benachrichtigungshistorie des Empfängers.
  6. Die Echtzeit-Zustellung wird über Websocket-Verbindungen für Online-Web-/App-Benutzer und Mobile Push für mobile Geräte versucht, wo dies angebracht ist.
  7. Die E-Mail-Zustellung wird separat in die Warteschlange gestellt, normalerweise mit Stapelverarbeitung und niedrigerer Priorität, um Benutzer nicht zu spammen.
  8. Zustellungsstatus, Wiederholungsversuche, Fehler und Metriken werden asynchron verfolgt.

Schätzung der Skalierung:

100 Millionen DAU mal 10 Ereignisse pro Tag ergeben 1 Milliarde ereignisauslösende Benachrichtigungen pro Tag. Die durchschnittliche Ereignisrate beträgt etwa 11.600 Ereignisse pro Sekunde. Die Spitzenlast bei 5x beträgt etwa 58.000 Ereignisse pro Sekunde. Das Design sollte für einen höheren internen Fan-out provisioniert werden, da ein Ereignis mehrere Empfänger benachrichtigen kann, insbesondere Kommentare, Erwähnungen, Gruppenkonversationen oder Live-Interaktionen. Ein sicheres anfängliches Ziel könnte 100.000 bis 300.000 Benachrichtigungszustellungen pro Sekunde bei Spitzenlast sein, abhängig vom Produktverhalten.

Wichtige Komponenten und Verantwortlichkeiten:

  1. API-Gateway
    Akzeptiert externe API-Anfragen zum Lesen des Benachrichtigungsverlaufs, zum Markieren von Benachrichtigungen als gelesen, zum Aktualisieren von Benachrichtigungseinstellungen, zum Registrieren von Geräten und zum Öffnen von Websocket-Verbindungen. Behandelt Authentifizierung, Ratenbegrenzung, Anforderungsrouting und grundlegenden Missbrauchsschutz.

  2. Ereignisproduzenten
    Bestehende Produktdienste generieren Domänenereignisse wie UserFollowed, PostLiked, CommentCreated, UserMentioned, DirectMessageCreated und MessageReactionAdded. Produzenten sollten Benachrichtigungszustelldienste nicht synchron aufrufen, da dies die Produktlatenz an die Benachrichtigungsinfrastruktur koppeln würde. Sie veröffentlichen an einen dauerhaften Ereignisbus.

  3. Ereignisbus oder Nachrichtenwarteschlange
    Ein verteiltes Protokoll wie Apache Kafka oder Apache Pulsar wird empfohlen. Es bietet hohen Durchsatz, dauerhafte Speicherung, Wiedergabefähigkeit, Partitionierung, Verbrauchergruppen und Backpressure-Handling. Themen können nach Ereignisfamilie oder Priorität getrennt werden, z. B. social-interactions, direct-messages, notification-delivery-high, notification-delivery-normal, notification-delivery-email.

  4. Benachrichtigungsaufnahme-Dienst
    Verbraucht rohe Produktereignisse, validiert Schemata, filtert ungültige/eigene Benachrichtigungen, wo zutreffend, normalisiert Ereignisnutzdaten, generiert Benachrichtigungs-IDs und führt Idempotenzprüfungen durch. Es reichert auch Ereignisse mit leichten Metadaten an, wie z. B. Akteurname, Akteur-Avatar-Referenz, Beitrags-ID und Zielobjekttyp. Eine starke Anreicherung sollte minimiert oder asynchron erfolgen, um die Latenz zu schützen.

  5. Fan-out-Dienst
    Bestimmt Empfänger und erstellt pro Empfänger Benachrichtigungsaufgaben. Bei Eins-zu-eins-Ereignissen wie einem Like, Follow oder einer Direktnachricht ist der Fan-out einfach. Bei Ereignissen, die mehrere Empfänger betreffen, wie z. B. Erwähnungen, Gruppennachrichten oder Kommentar-Threads, kann der Fan-out viele Zustellungsdatensätze erzeugen. Er sollte sowohl Fan-out-on-write als auch Fan-out-on-read je nach Skalierung unterstützen.

Empfohlener Ansatz:
Für normale Benachrichtigungen verwenden Sie Fan-out-on-write und speichern Sie Benachrichtigungsdatensätze pro Empfänger. Dies beschleunigt den Abruf des Verlaufs und ermöglicht ungelesene Zählungen.
Für Entitäten mit sehr hohem Fan-out, wie z. B. Promi-Übertragungen oder riesige Gruppen, verwenden Sie Hybrid-Fan-out: Speichern Sie ein freigegebenes Benachrichtigungsobjekt und materialisieren Sie es nur für aktive Benutzer oder bei Bedarf.

  1. Präferenz- und Richtliniendienst
    Speichert und wertet Benutzereinstellungen für Benachrichtigungen, Datenschutzeinstellungen, Stummschaltungs-/Blockierungsbeziehungen, Ruhezeiten, Kanalberechtigungen, Gebietsschema, E-Mail-Opt-in-Status und plattformspezifische Einstellungen aus. Er gibt Kanalberechtigung und Priorität zurück. Einstellungen sollten aggressiv zwischengespeichert werden.

  2. Benachrichtigungsspeicher-Dienst
    Speichert den Benachrichtigungsverlauf und den Status. Er speichert die letzten N Benachrichtigungen, den ungelesenen/gelesenen Status, Zeitstempel, Typ, Akteur, Entitätsreferenzen und Rendering-Metadaten. Er unterstützt Abfragen wie die neuesten 100 Benachrichtigungen für einen Benutzer, ungelesene Zählungen, Markieren als gelesen, Markieren aller als gelesen und Löschen/Ausblenden.

  3. Echtzeit-Verbindungs-Gateway
    Unterhält Websocket- oder Server-Sent-Event-Verbindungen für Online-Web- und mobile App-Benutzer. Es speichert Verbindungspräsenz in einem verteilten Präsenzspeicher. Zustellungsworker leiten Echtzeit-Benachrichtigungen an den Gateway-Knoten weiter, der die aktive Verbindung des Empfängers hält. Für mobile Apps im Hintergrund fällt die Zustellung auf APNs/FCM zurück.

  4. Präsenzdienst
    Verfolgt, ob ein Benutzer online ist, welche Geräte verbunden sind und welcher Gateway-Knoten jede Verbindung besitzt. Präsenzdaten sind flüchtig und sollten in Redis Cluster oder einem anderen verteilten Cache mit geringer Latenz und kurzen TTL-Heartbeats gespeichert werden.

  5. Kanalzustelldienste
    Separate Worker stellen Benachrichtigungen nach Kanal zu:
    Mobile Push Worker: Sendet an APNs für iOS und FCM für Android. Behandelt Token-Invalidierung, Anbieterfehler, wiederholbare Fehler und Collapse-Schlüssel.
    Web Push Worker: Sendet Browser-Push über das Web-Push-Protokoll für Benutzer mit registrierten Browser-Abonnements.
    Websocket Worker: Sendet Benachrichtigungen mit geringer Latenz an Online-Benutzer über das Echtzeit-Gateway.
    E-Mail Worker: Sendet E-Mails über einen Anbieter wie SES, SendGrid oder ein internes MTA. Er sollte Stapelverarbeitung, Vorlagen, Abmelderegeln und Warteschlangen mit niedrigerer Priorität unterstützen.

  6. Geräte-Token-Dienst
    Speichert mobile Geräte-Token, Browser-Push-Abonnements, Geräte-Metadaten, App-Version, Plattform, Gebietsschema und den Zeitstempel der letzten Aktivität. Er behandelt Token-Rotation und die Bereinigung ungültiger Token.

  7. Vorlagen- und Lokalisierungsdienst
    Rendert Benachrichtigungstexte und E-Mail-Vorlagen basierend auf Benachrichtigungstyp, Gebietsschema, Akteur, Objektmetadaten und Client-Fähigkeiten. Bevorzugt die Speicherung strukturierter Benachrichtigungsdaten und das Rendern zur Lesezeit für den In-App-Verlauf, während die endgültigen Nutzdaten zur Zustellzeit für Push/E-Mail gerendert werden.

  8. Deduplizierungs- und Aggregationsdienst
    Verhindert Spam und doppelte Benachrichtigungen. Beispiele: Aggregieren von „Alice und 12 anderen gefällt Ihr Beitrag“ anstatt 13 unabhängige Push-Benachrichtigungen zu senden. Verwenden Sie Idempotenzschlüssel wie event_type + actor_id + recipient_id + object_id + event_time_bucket. Die Aggregation kann mit Redis-Sortier-Sets/Zählern erfolgen und dann dauerhaft gespeichert werden.

  9. Metriken, Protokollierung und Alarmierung
    Erfasst Ende-zu-Ende-Latenz, Warteschlangenverzögerung, Zustellungserfolgsrate, Anbieterfehlerrate, Websocket-Verbindungsanzahl, Benachrichtigungserstellungsrate, Fan-out-Faktor, Datenbanklatenz, Genauigkeit der ungelesenen Zählung und das Volumen von Wiederholungs-/Dead-Letter-Warteschlangen.

Datenmodell:

  1. Benachrichtigungsereignisschema
    notification_event_id: global eindeutige ID
    source_event_id: ID vom Quellendienst
    event_type: follow, like, comment, direct_message, mention
    actor_user_id: Benutzer, der das Ereignis verursacht hat
    recipient_user_ids oder Referenz zum Empfänger-Resolver
    target_type: post, comment, user, message, conversation
    target_id: Zielobjekt-ID
    created_at: Ereigniszeit
    metadata: kompaktes JSON für zusätzlichen Kontext
    idempotency_key: stabiler Schlüssel zur Duplikatvermeidung
    priority: high, normal, low

  2. Benachrichtigungsverlaufseintrag
    user_id: Partitionsschlüssel des Empfängers
    notification_id: zeitlich sortierbare eindeutige ID, z. B. Snowflake/UUIDv7
    notification_type
    actor_user_id oder Akteurzusammenfassung
    target_type
    target_id
    aggregation_key
    summary_text oder Renderparameter
    created_at
    read_at nullable
    seen_at nullable
    status: created, delivered, failed, hidden
    channels_attempted
    metadata

Für die Speicherung des Verlaufs verwenden Sie eine Wide-Column-Datenbank wie Apache Cassandra, ScyllaDB oder DynamoDB. Partitionieren Sie nach user_id und clustern Sie nach created_at absteigend oder notification_id absteigend. Dies entspricht dem primären Abfragemuster: Abrufen der neuesten 100 Benachrichtigungen für einen Benutzer. Sie skaliert horizontal, unterstützt hohen Schreibdurchsatz und hat eine vorhersehbare geringe Latenz bei Lesevorgängen. Verwenden Sie TTL oder Hintergrundkompaktierung, um den aktuellen Verlauf gemäß den Produktanforderungen beizubehalten, wobei mindestens die neuesten 100 beibehalten werden. Wenn nur die „letzten 100“ erforderlich sind, pflegen Sie einen Trim-Job pro Benutzer oder verwenden Sie TTL plus periodische Kompaktierung.

Beispiel für eine logische Tabelle:
UserNotifications
Partitionsschlüssel: user_id
Clustering-Schlüssel: created_at absteigend, notification_id
Spalten: type, actor_user_id, target_type, target_id, metadata, read_at, aggregation_key, status

  1. Modell für ungelesene Zählungen
    Verwenden Sie Redis für schnelle Lese- und Schreibvorgänge von ungelesenen Zählungen, gesichert durch dauerhafte Speicherung in Cassandra/DynamoDB. Inkrementieren bei Benachrichtigungserstellung, dekrementieren oder zurücksetzen bei Lesen/Markieren aller als gelesen. Da Zähler abweichen können, gleichen Sie sie periodisch aus der dauerhaften Speicherung ab oder verwenden Sie ein Lese-Marker-Modell.

Alternativer Ansatz für Lese-Marker:
Speichern Sie last_read_timestamp pro Benutzer und behandeln Sie Benachrichtigungen, die neuer als dieser Zeitstempel sind, als ungelesen. Dies macht „Alle als gelesen markieren“ günstig. Für den Lese-Status pro Benachrichtigung speichern Sie read_at in einzelnen Datensätzen. Eine Kombination ist oft am besten.

  1. Benutzereinstellungen
    Verwenden Sie eine relationale Datenbank wie PostgreSQL oder MySQL für dauerhafte Einstellungseinträge, da Einstellungen Konsistenz, strukturierte Updates und gelegentliche Joins/Admin-Operationen erfordern. Cachen Sie heiße Einstellungen in Redis oder Memcached. Für sehr große Skalierungen sharden Sie nach user_id oder verwenden Sie DynamoDB, wenn die Organisation eine verwaltete Key-Value-Skalierung bevorzugt.

Einstellungsschema:
user_id
notification_type
channel: push, web, email, in_app
enabled: boolean
quiet_hours
frequency: immediate, digest, never
updated_at

  1. Geräte-Token und Push-Abonnements
    Verwenden Sie DynamoDB, Cassandra oder einen geshardeten relationalen Speicher, der nach user_id und device_id indiziert ist. Token-Lookups müssen schnell und hochverfügbar sein. Speichern Sie token_hash/token, platform, app_version, locale, enabled, last_seen_at und invalidated_at.

  2. Präsenzdaten
    Verwenden Sie Redis Cluster mit TTL:
    user_id -> aktive Verbindungs-IDs, Geräte-IDs, Gateway-Knoten-IDs, letzter Heartbeat
    connection_id -> user_id, Gateway-Knoten, Ablaufdatum
    Präsenz kann letztendlich konsistent sein, da sie nur eine Optimierung für die Echtzeit-Zustellung ist.

  3. Zustellungsstatus und Audit-Protokolle
    Verwenden Sie Kafka-Themen plus einen kostengünstigeren analytischen Speicher wie S3/Objektspeicher, ClickHouse, BigQuery oder Elasticsearch/OpenSearch für operative Fehlersuche, Analysen und Zustellungsberichte. Legen Sie keine hochvolumigen Zustellungsprotokolle in den primären Transaktionsspeicher, es sei denn, dies ist erforderlich.

Empfehlungen für den Technologie-Stack:

Nachrichtenbroker: Kafka oder Pulsar für dauerhaftes Event-Streaming, partitioniert nach recipient_user_id, wo die Reihenfolge pro Empfänger wichtig ist. Verwenden Sie separate Themen für Aufnahme, Fan-out, Kanalzustellung, Wiederholungsversuche und Dead-Letter-Warteschlangen.

Datenbanken:
Cassandra/ScyllaDB/DynamoDB für Benachrichtigungsverlauf.
PostgreSQL/MySQL oder DynamoDB für Benutzereinstellungen.
Redis Cluster für Präsenz und Hot Caches, Idempotenz-Kurzzeit-Cache, Ratenbegrenzungen und Aggregationsfenster.
Objektspeicher plus analytische Datenbank für Protokolle und historische Analysen.

Echtzeit-Transport:
WebSocket für In-App- und Web-Echtzeit-Benachrichtigungen. Server-Sent Events können für die reine Web-Einwegzustellung verwendet werden, aber WebSocket ist flexibler für Bestätigungen und Heartbeats.

Push-Anbieter:
APNs für iOS, FCM für Android, Web Push für Browser. Abstrahieren Sie Anbieter hinter einem Push Delivery Service, um anbieterspezifisches Verhalten zu isolieren.

E-Mail:
Amazon SES, SendGrid, Mailgun oder interne E-Mail-Infrastruktur. Verwenden Sie dedizierte Warteschlangen, Vorlagen, Unterdrückungslisten und Digesting.

Compute:
Zustandslose Dienste auf Kubernetes oder ähnlichen Orchestrierungen. Skalieren Sie Consumer horizontal basierend auf Warteschlangenverzögerung, CPU und Zustellungslatenz. Verwenden Sie regionale Bereitstellung mit Load Balancern und Service Discovery.

IDs:
Verwenden Sie UUIDv7, ULID oder Snowflake-IDs für sortierbare Benachrichtigungs-IDs. Stellen Sie die Idempotenz über source_event_id und benachrichtigungsspezifische Idempotenzschlüssel sicher.

Skalierungsstrategie:

  1. Partitionierung
    Partitionieren Sie Kafka-Themen nach recipient_user_id für die Reihenfolge pro Benutzer, wo erforderlich. Für Quellereignisse mit unbekanntem Empfänger partitionieren Sie nach Entität, bis zum Fan-out, dann neu partitionieren nach Empfänger. Partitionieren Sie den Benachrichtigungsverlauf nach user_id, um Abfragen der neuesten Benachrichtigungen zu optimieren.

  2. Horizontale Skalierung
    Alle Pipeline-Dienste sollten zustandslos sein, außer Gateways und Speicher. Consumer können durch Erhöhung der Themenpartitionen und Replikate von Workern skaliert werden. Echtzeit-Gateways skalieren nach Verbindungsanzahl und Bandbreite.

  3. Backpressure
    Wenn nachgelagerte Anbieter langsamer werden, absorbieren Warteschlangen Spitzen. Verwenden Sie separate Warteschlangen pro Kanal und Priorität, damit E-Mail-Verzögerungen keine Direktnachrichten oder In-App-Benachrichtigungen beeinträchtigen. Wenden Sie Ratenbegrenzungen pro Benutzer, pro Akteur, pro Benachrichtigungstyp und pro Anbieter an.

  4. Caching
    Cache-Einstellungen, Geräte-Token, Präsenz, Vorlagen und ungelesene Zählungen. Verwenden Sie kurze TTLs für Daten, die sich häufig ändern. Cache-Fehler sollten nicht die gesamte Zustellung blockieren; wenn Einstellungen vorübergehend nicht verfügbar sind, fallen Sie sicher gemäß den Produktregeln aus, oft indem Sie nur obligatorische In-App-Datensätze senden und externe Kanäle aufschieben.

  5. Aggregation
    Reduzieren Sie Fan-out und Push-Volumen durch Aggregation von Likes und ähnlichen Interaktionen. Speichern Sie beispielsweise jeden Like-Ereignis, falls für Analysen erforderlich, aber senden Sie eine Benachrichtigung pro Beitrag pro Zeitfenster: „Alice, Bob und 10 andere haben Ihren Beitrag geliked.“

  6. Hybrid-Fan-out
    Vermeiden Sie bei Szenarien mit hohem Fan-out das sofortige Schreiben von Millionen von Zeilen. Speichern Sie ein freigegebenes Ereignis und materialisieren Sie Benachrichtigungen zuerst für aktive Benutzer, dann verzögert für inaktive Benutzer, wenn sie die App öffnen.

  7. Multi-Region-Bereitstellung
    Bereitstellung aktiv-aktiv oder aktiv-passiv über Regionen hinweg. Für 99,9 % Verfügbarkeit wird aktiv-aktiv für Echtzeit-Gateways und zustandslose Dienste empfohlen, während Datenspeicher mindestens Multi-AZ-Replikation verwenden sollten. Globale Benutzerweiterleitung kann Benutzer an die nächstgelegene gesunde Region senden. Verwenden Sie regionale Kafka-Cluster mit Replikation oder ein verwaltetes Multi-Region-Streaming-System.

Strategie für geringe Latenz:

  1. Halten Sie Produktdienste von der Benachrichtigungszustellung entkoppelt. Die Ereignisveröffentlichung sollte schnell und zuverlässig sein.
  2. Verwenden Sie Kafka/Pulsar mit ausreichenden Partitionen und Consumern, um die Warteschlangenverzögerung gering zu halten.
  3. Verwenden Sie Redis für die Präsenzprüfung und Routing-Entscheidungen.
  4. Verwenden Sie Websocket-Zustellung für Online-Benutzer, da diese die Latenz von Drittanbieter-Push-Anbietern vermeidet.
  5. Speichern Sie Benachrichtigungsdatensätze vor oder parallel zur Zustellung, abhängig von den Zuverlässigkeitsanforderungen. Ein gängiger Ansatz ist, zuerst den Verlauf zu schreiben, dann zuzustellen; für extrem geringe Latenz können Zustellung und Speicherung parallel mit idempotenter Wiederholung erfolgen.
  6. Vermeiden Sie teure synchrone Joins. Ereignisse sollten genügend Metadaten für das Rendering enthalten, oder verwenden Sie zwischengespeicherte Benutzer-/Objektzusammenfassungen.
  7. Priorisieren Sie Direktnachrichten und sicherheitsrelevante Benachrichtigungen gegenüber sozialen Benachrichtigungen mit geringem Wert.

Zuverlässigkeit und Hochverfügbarkeit:

  1. Dauerhafte Nachrichtenübermittlung
    Verwenden Sie Kafka/Pulsar-Replikation über Verfügbarkeitszonen hinweg. Produzenten verwenden Bestätigungen und Wiederholungsversuche. Consumer committen Offsets nur nach dauerhafter Verarbeitung oder nach dem Schreiben eines idempotenten Ergebnisses.

  2. Outbox-Muster
    Quellendienste schreiben Domänenänderungen und ausgehende Ereignisse transaktional in eine Outbox-Tabelle. Ein Relais veröffentlicht die Outbox an Kafka. Dies verhindert verlorene Ereignisse, wenn ein Dienst seine Datenbankschreibung erfolgreich abschließt, aber vor der Veröffentlichung fehlschlägt.

  3. Idempotenz
    Jede Stufe muss idempotent sein. Doppelte Ereignisse sind aufgrund von Wiederholungsversuchen zu erwarten. Verwenden Sie source_event_id, notification_id und idempotency_key, um doppelte Verlaufszeilen und doppelte Push-Versuche, wo möglich, zu vermeiden.

  4. Wiederholungsrichtlinie
    Transiente Fehler werden mit exponentiellem Backoff und Jitter in Wiederholungsthemen geleitet. Permanente Fehler, wie z. B. ungültige Push-Token, werden durch Markieren der Token als ungültig behandelt. Poison-Nachrichten gehen zur Inspektion in Dead-Letter-Warteschlangen.

  5. Graceful Degradation
    Wenn der E-Mail-Anbieter ausfällt, wird die E-Mail in die Warteschlange gestellt und die In-App-Benachrichtigungen fortgesetzt. Wenn Push-Anbieter langsam sind, werden Websocket/In-App zugestellt und Push später wiederholt. Wenn der Präferenz-Cache nicht verfügbar ist, greifen Sie auf dauerhafte Präferenzlesungen oder konservative Standardwerte zurück. Wenn die Präsenz nicht verfügbar ist, überspringen Sie Websocket und verlassen Sie sich auf Push/Verlauf.

  6. Replikation und Backups
    Verwenden Sie Multi-AZ-Datenbanken, regelmäßige Backups, Point-in-Time-Recovery für relationale Speicher und getestete Wiederherstellungsverfahren. Verwenden Sie für Cassandra/ScyllaDB einen Replikationsfaktor von 3 über AZs hinweg und Quorum-Einstellungen, die den Latenz-/Zuverlässigkeitskompromissen entsprechen.

  7. Überwachung und SLOs
    Erfassen Sie die Ende-zu-Ende-Latenz von der Erstellung des Quellereignisses bis zum Empfang durch den Client (p50/p95/p99). Alarmieren Sie bei Warteschlangenverzögerung, Spitzen bei Zustellfehlern, Anbieterdrosselung, Hot Partitions in Datenbanken, Websocket-Trennungrate, Redis-Speicherbelegung und Consumer-Rebalance-Stürmen.

Benachrichtigungsverlauf-API:

GET neueste Benachrichtigungen:
Der Client fordert die neuesten 100 Benachrichtigungen an. Das API-Gateway authentifiziert den Benutzer, die Benachrichtigungs-API fragt UserNotifications nach user_id ab, sortiert nach created_at absteigend, reichert fehlende Anzeigefelder aus dem Cache an und gibt strukturierte Datensätze zurück.

Benachrichtigung als gelesen markieren:
Die API aktualisiert read_at für diese Benachrichtigung und passt die ungelesene Zählung idempotent an.

Alle als gelesen markieren:
Speichert last_read_timestamp für den Benutzer und aktualisiert optional asynchron ältere ungelesene Zeilen. Dies vermeidet große synchrone Schreibvorgänge.

Mögliche Engpässe und Kompromisse:

  1. Fan-out-Explosion
    Problem: Einige Ereignisse können viele Benutzer benachrichtigen und Warteschlangen und Speicher überlasten.
    Milderung: Hybrid-Fan-out, Prioritätswarteschlangen, Aggregation, Ratenbegrenzungen, verzögerte Materialisierung.
    Kompromiss: Fan-out-on-read reduziert die Schreiblast, macht aber Lesevorgänge komplexer und kann die Leselatenz erhöhen.

  2. Heiße Benutzer und heiße Beiträge
    Problem: Prominente oder virale Beiträge können ein riesiges Benachrichtigungsvolumen für einen Empfänger oder ein Objekt generieren.
    Milderung: Aggregieren von Benachrichtigungen nach Objekt und Zeitfenster, Sharding von Aggregationsschlüsseln, Unterdrücken von sich wiederholenden Benachrichtigungen mit geringem Wert.
    Kompromiss: Benutzer erhalten möglicherweise weniger granulare Benachrichtigungen.

  3. Push-Anbieter-Limits
    Problem: APNs/FCM/E-Mail-Anbieter können drosseln oder ausfallen.
    Milderung: Dedizierte Anbieter-Worker, adaptive Ratenbegrenzung, Wiederholungsversuche, Token-Bereinigung, anbieterspezifischer Backoff.
    Kompromiss: Externe Push-Zustellung kann nicht immer das Ziel von unter 2 Sekunden erreichen; Websocket-Zustellung für Online-Benutzer ist der zuverlässige Pfad mit geringer Latenz.

  4. Datenbank-Schreibvolumen
    Problem: Pro Empfänger geschriebene Benachrichtigungen in großem Maßstab können teuer sein.
    Milderung: Verwendung von schreiboptimierten Wide-Column-Speichern, Stapelschreiben, TTL, Aggregation und Hybrid-Fan-out.
    Kompromiss: Wide-Column-Speicher haben eine begrenzte Abfrageflexibilität; das Design muss den Zugriffsmustern entsprechen.

  5. Korrektheit der ungelesenen Zählung
    Problem: Zwischengespeicherte Zähler können bei Wiederholungsversuchen und gleichzeitigen Leseaktualisierungen abweichen.
    Milderung: Idempotente Aktualisierungen, Lese-Marker, periodische Abgleichung.
    Kompromiss: Eine exakte ungelesene Zählung ist teurer als eine letztendlich konsistente ungelesene Zählung.

  6. Reihenfolge
    Problem: Benachrichtigungen können aufgrund verteilter Verarbeitung außer Reihenfolge ankommen.
    Milderung: Verwendung von sortierbaren IDs und Sortierung nach Ereigniszeit/Benachrichtigungs-ID beim Lesen. Partitionierung nach Empfänger für stärkere Reihenfolge pro Benutzer, wo erforderlich.
    Kompromiss: Strikte globale Reihenfolge ist nicht praktikabel oder notwendig.

  7. Latenz vs. Dauerhaftigkeit
    Problem: Das Schreiben des Verlaufs vor der Zustellung verbessert die Zuverlässigkeit, erhöht aber die Latenz.
    Milderung: Schnellen lokalen Speicher verwenden und Speicherung/Zustellung nach Idempotenzzuweisung parallelisieren.
    Kompromiss: Parallele Zustellung kann kurzzeitig eine Push-Benachrichtigung anzeigen, bevor sie im Verlauf erscheint, wenn die Speicherung verzögert ist.

  8. Komplexität der Präferenzbewertung
    Problem: Präferenzprüfungen pro Ereignis können bei Spitzenlast teuer sein.
    Milderung: Caching von Präferenzen, Vorberechnen von effektiven Einstellungen und Invalidieren des Caches bei Präferenzänderungen.
    Kompromiss: Präferenzänderungen dauern einige Sekunden, bis sie wirksam werden, es sei denn, eine starke Konsistenz ist erforderlich.

Empfohlene endgültige Designzusammenfassung:

Verwenden Sie eine ereignisgesteuerte Architektur mit Kafka/Pulsar als Rückgrat, zustandslose Ingestions-/Fan-out-/Routing-Dienste, Cassandra/ScyllaDB/DynamoDB für den Benachrichtigungsverlauf pro Benutzer, Redis für Präsenz und Hot Caches, Websocket-Gateways für Online-Zustellung unter 2 Sekunden, APNs/FCM/Web Push für Plattformbenachrichtigungen und eine separate E-Mail-Zustellungspipeline. Das System sollte horizontal skalierbar, primär nach user_id partitioniert, durch dauerhafte Warteschlangen und idempotente Verarbeitung ausfallsicher und durch Caching, Online-Präsenz-Routing, Prioritätswarteschlangen und Aggregation für geringe Latenz optimiert sein. Dieses Design erfüllt die funktionalen Anforderungen, unterstützt die erwarteten 1 Milliarde täglicher Ereignisse mit 5-fachen Spitzen und bietet einen praktischen Weg zu 99,9 % Verfügbarkeit mit graceful degradation bei Teilausfällen.

Ergebnis

#2

Siegstimmen

0 / 3

Durchschnittsscore

86
Bewertungsmodelle OpenAI GPT-5.6

Gesamtpunktzahl

90

Gesamtkommentar

Antwort B ist ebenfalls ein exzellentes und umfassendes Design. Sie bietet eine kohärente ereignisgesteuerte Pipeline, führt korrekt das Outbox-Muster ein, modelliert Alternativen für Verlauf und ungelesenen Status sorgfältig und behandelt Idempotenz, graduelle Verschlechterung, hybride Fan-outs und Latenz- versus Haltbarkeits-Kompromisse stark. Ihre Haupthauptschwäche ist, dass mehrere Infrastrukturentscheidungen und regionale Strategien Alternativen und keine einzelne konkrete Bereitstellung planen bleiben. Sie bietet auch weniger spezifische Kapazitätsplanung für persistente Verbindungen, Partitionierungsanzahlen, Headroom und Failover-Verhalten als Antwort A.

Bewertungsdetails anzeigen

Architekturqualität

Gewichtung 30%
89

Die Architektur ist kohärent und gut zerlegt, und die explizite transaktionale Outbox schließt ein wichtiges Fenster für den Verlust von Ereignissen. Fan-out, Richtlinienbewertung, Speicherung, Präsenz, Echtzeit-Gateways, Kanal-Worker, Vorlagen und Deduplizierung sind alle angemessen platziert. Sie verliert etwas an Präzision, da die Reihenfolge von Speicherung versus Zustellung und die regionale Architektur Aktiv-Aktiv versus Aktiv-Passiv als Optionen und nicht als entschiedene Designentscheidungen dargestellt werden.

Vollständigkeit

Gewichtung 20%
91

Sie deckt den vollständigen funktionalen und nicht-funktionalen Umfang ab, einschließlich aller Zustellplattformen, Verlauf-APIs, Datenmodelle, Semantik für ungelesene Nachrichten, Geräte-Registrierung, Präsenz, Lokalisierung, Anbieter-Handling, Überwachung, Engpässe und Kompromisse. Sie ist operativ etwas weniger vollständig, da detaillierte Größenangaben für persistente Verbindungen, konkrete Partitionierungsbereitstellungen und eine vollständig ausgewählte Multi-Region-Topologie fehlen.

Trade-off-Analyse

Gewichtung 20%
92

Sie liefert eine exzellente Analyse von Fan-out-on-write versus Fan-out-on-read, Einschränkungen von Wide-Column-Abfragen, Genauigkeit von Ungelesen-Zählungen, Reihenfolge, Konsistenz von Präferenz-Caches, Anbieter-Latenz und Haltbarkeit versus Zustellungs-Latenz. Die Argumentation ist technisch ausgereift, obwohl einige Alternativen ohne endgültige Auswahl oder Schwellenwerte offen bleiben.

Skalierbarkeit und Zuverlässigkeit

Gewichtung 20%
90

Sie berechnet korrekt Basis- und Spitzenraten und verwendet Partitionierung, horizontale Skalierung, Warteschlangen-Backpressure, Prioritätsisolierung, hybriden Fan-out, Replikation, Idempotenz, Wiederholungsversuche, DLQs, Backups und graduelle Verschlechterung. Die Outbox ist eine große Stärke für die Zuverlässigkeit. Im Vergleich zu A ist sie weniger konkret bezüglich der Kapazität von Verbindungsflotten, des Headrooms für warmes Skalieren, der Partitionsanzahlen, der Wiederherstellungsziele und des genauen regionalen Failover-Designs.

Klarheit

Gewichtung 10%
86

Die Antwort ist logisch aufgebaut und erklärt jede Komponente und Entscheidung konsistent. Sie ist etwas repetitiver und präsentiert häufig Menüs von gleichwertigen Technologien oder Bereitstellungsansätzen, was die Entscheidungsfindung schwächt und die endgültige Architektur etwas schwieriger zu extrahieren macht.

Bewertungsmodelle Google Gemini 2.5 Pro

Gesamtpunktzahl

87

Gesamtkommentar

Eine sehr starke und technisch fundierte Antwort, die eine korrekte und robuste Architektur für das Benachrichtigungssystem präsentiert. Sie deckt alle erforderlichen Aspekte des Designs mit guter Detailtiefe ab, insbesondere bei den Komponentenbeschreibungen und der Datenmodellierung. Die vorgeschlagenen Lösungen sind branchenüblich und gut begründet. Ihre Hauptschwäche im Vergleich zu Antwort A ist, dass sie in ihrer Struktur etwas weniger ausgefeilt ist, weniger detailliert in ihrer anfänglichen quantitativen Analyse und den zusätzlichen operativen Kontext eines Rollout-Plans vermissen lässt.

Bewertungsdetails anzeigen

Architekturqualität

Gewichtung 30%
90

Die vorgeschlagene Architektur ist ebenfalls sehr stark und folgt Best Practices für ein ereignisgesteuertes System. Die Komponenten sind logisch und ihre Verantwortlichkeiten sind gut definiert. Es wird korrekt die Notwendigkeit eines hybriden Fan-out-Modells erkannt. Das Gesamtdesign ist robust und gut für die Aufgabe geeignet, wenn auch etwas weniger detailliert in den Komponenteninteraktionen als Antwort A.

Vollständigkeit

Gewichtung 20%
85

Die Antwort ist sehr vollständig und adressiert alle Kernanforderungen der Aufgabenstellung, einschließlich Architektur, Datenmodelle und Skalierbarkeit. Es fehlen jedoch die zusätzlichen, hochrelevanten Abschnitte zu einem phasenweisen Rollout und einer strukturierten Liste von Metriken/SLOs, die Antwort A bietet, was sie in praktischer Hinsicht etwas weniger umfassend macht.

Trade-off-Analyse

Gewichtung 20%
90

Die Antwort bietet eine starke Diskussion potenzieller Engpässe und der damit verbundenen Kompromisse. Sie identifiziert korrekt Probleme wie Fan-out-Explosion und Datenbank-Schreibvolumen. Die Argumentation ist fundiert und deckt die wichtigsten Kompromisse ab, wie z. B. Fan-out-on-read vs. Fan-out-on-write, was sie zu einem sehr starken Abschnitt macht.

Skalierbarkeit und Zuverlässigkeit

Gewichtung 20%
85

Die Antwort präsentiert eine solide Reihe von Strategien für Skalierbarkeit und Zuverlässigkeit, einschließlich Partitionierung, horizontaler Skalierung, Backpressure und dem Outbox-Pattern. Diese sind alle korrekt und für das System geeignet. Die Strategien werden jedoch in etwas allgemeineren Begriffen beschrieben im Vergleich zu den spezifischen, umsetzbaren Plänen in Antwort A.

Klarheit

Gewichtung 10%
80

Die Antwort ist gut geschrieben und strukturiert, was sie im Allgemeinen leicht verständlich macht. Allerdings ist der Text dichter als in Antwort A, und einige Konzepte werden in verschiedenen Abschnitten wiederholt. Die überlegene Formatierung und Prägnanz von Antwort A verschaffen ihr einen klaren Vorteil in der Lesbarkeit.

Bewertungsmodelle Anthropic Claude Fable 5

Gesamtpunktzahl

80

Gesamtkommentar

Antwort B ist ein gründliches, technisch fundiertes Design, das alle Anforderungen der Aufgabenstellung abdeckt: ereignisgesteuerte Pipeline, Fan-out-on-write vs. Hybrid-Fan-out, Wide-Column-History-Store mit klarer Begründung, Redis-Präsenz, Channel-Worker und eine gut organisierte Liste von acht Engpässen/Kompromissen. Es beinhaltet einzigartig das Transactional-Outbox-Pattern für Produzentenverlässlichkeit und eine durchdachte Read-Marker-Alternative für ungelesene Zählungen. Es ist jedoch weniger quantitativ fundiert als A (keine Speicherkapazitätsplanung, keine Dimensionierung der Connection-Tier, keine Anleitung zur Partitionsbereitstellung), schwankt häufig zwischen Optionen (Kafka oder Pulsar, Postgres oder MySQL oder DynamoDB), anstatt sich mit Begründungen festzulegen, und es mangelt an operativer Tiefe wie Autoscaling-Signalen, Deployment-/Rollout-Strategie und konkreten Konsistenz-Einstellungen, die an das Verfügbarkeitsziel gebunden sind.

Bewertungsdetails anzeigen

Architekturqualität

Gewichtung 30%
80

Sehr solide ereignisgesteuerte Architektur mit klar definierten Komponenten, Hybrid-Fan-out, Präsenz-basiertem Routing und dem Transactional-Outbox-Pattern, das A fehlt. Es legt sich jedoch weniger fest (Kafka oder Pulsar, mehrere Datenbankoptionen ohne endgültige Wahl), liefert keine Dimensionierung der Connection-Tier oder Partitionsbereitstellung, und der kritische Lieferpfad ist weniger explizit auf das Latenzbudget ausgelegt.

Vollständigkeit

Gewichtung 20%
85

Behandelt alle erforderlichen Aspekte: Architektur, Komponenten, Datenmodell mit Beispiel-Tabellenschemata, Technologie-Stack, Skalierbarkeit, Zuverlässigkeit, History-API-Flows und acht Engpass-/Kompromiss-Punkte. Enthält das Outbox-Pattern und das Read-Marker-Modell als Extras. Etwas weniger vollständig als A in Bezug auf Kapazitäts-/Speicherdimensionierung, Compliance-Überlegungen, Rollout-Strategie und definierte SLO-Ziele.

Trade-off-Analyse

Gewichtung 20%
78

Ein gut strukturiertes Format für Probleme/Abhilfen/Kompromisse über acht Engpässe, das Fan-out, Reihenfolge, Latenz vs. Dauerhaftigkeit und Counter Drift abdeckt. Gute Breite, aber die Kompromisse sind kürzer und beschreibender; es werden selten explizite Alternativen abgewogen (z. B. warum Kafka gegenüber einer einfacheren Queue oder warum Polyglot Persistence) mit der Tiefe, die A zeigt.

Skalierbarkeit und Zuverlässigkeit

Gewichtung 20%
78

Behandelt die richtigen Mechanismen: Partitionierung nach Empfänger, horizontale Skalierung, Backpressure über Queues, kanalbezogene Prioritätsisolierung, Multi-Region-Optionen, Wiederholungsversuche mit Backoff, DLQs und graceful degradation. Die Anleitung ist jedoch allgemeiner; es gibt keine Autoscaling-Signale, keine Headroom-Angaben, keine Hot-Partition-Details oder Validierungspraktiken (Lasttests, Chaos), die das Design mit den angegebenen Zielen verknüpfen.

Klarheit

Gewichtung 10%
80

Klare Gliederung mit nummerierten Komponenten und einer hilfreichen abschließenden Zusammenfassung. Durchgehend lesbar, obwohl häufiges Schwanken zwischen Technologieoptionen und einige Wiederholungen zwischen den Abschnitten Skalierbarkeit, Latenz und Zuverlässigkeit die Botschaft leicht verwässern.

Vergleichsübersicht

Für jede Aufgabe und Diskussion wird die Endrangfolge per Richter-Rangaggregation bestimmt (Durchschnittsrang + Borda-Tie-Break). Der Durchschnittsscore wird als Referenz angezeigt.

Bewerter: 3

Siegstimmen

3 / 3

Durchschnittsscore

92
Diese Antwort ansehen

Siegstimmen

0 / 3

Durchschnittsscore

86
Diese Antwort ansehen

Bewertungsergebnisse

Bewertungsmodelle Anthropic Claude Fable 5

Warum diese Seite gewann

Antwort A gewinnt aufgrund der gewichteten Kriterien. Beim schwersten Kriterium, Architekturqualität (30%), liefert A konkretere und verbindlichere Designentscheidungen: dimensionierte WebSocket-Schicht, bereitgestellte Kafka-Partitionen mit Replikationseinstellungen, Prioritätsspuren für die Latenz-SLO und ein vollständig spezifizierter Zustellpfad mit Fallback-Leiter. Beim Abwägungs-Reasoning (20%) übertreffen die expliziten Alternativen und Ablehnungen von A (Kafka vs. SQS, Exactly-once vs. At-least-once, Polyglot vs. Single Store, Single-Region vs. Active-Active) die Liste der mitigationsorientierten Abwägungen von B. Bei Skalierbarkeit/Zuverlässigkeit (20%) liefert A umsetzbare Mechanismen (KEDA-Skalierung bei Consumer-Lag, TWCS-Kompaktierung, gesalzene Hot Keys, Chaos-Testing, 5-fache Lastvalidierung), während B allgemeiner bleibt. Das Outbox-Muster und das Read-Marker-Modell von B sind echte Vorteile, aber sie gleichen die Überlegenheit von A bei den höher gewichteten Kriterien nicht aus. Das gewichtete Ergebnis begünstigt eindeutig A.

Bewertungsmodelle Google Gemini 2.5 Pro

Warum diese Seite gewann

Antwort A gewinnt, da sie ein detaillierteres, ausgefeilteres und umfassenderes Design bietet. Während beide Antworten eine ähnliche und fundierte Architektur vorschlagen, zeichnet sich Antwort A in mehreren Schlüsselbereichen aus. Sie beginnt mit einer gründlichen quantitativen Kapazitätsschätzung, die das gesamte Design auf konkreten Zahlen basiert. Ihre Diskussion über Skalierbarkeit und Zuverlässigkeit ist spezifischer und erwähnt fortschrittliche Tools und Praktiken wie KEDA für Autoskalierung und Chaos Engineering. Sie ist außergewöhnlich klar und gut strukturiert, wodurch komplexe Informationen leicht verständlich sind. Schließlich geht sie über die Anforderungen der Aufforderung hinaus, indem sie einen gestaffelten Rollout-Plan und einen speziellen Abschnitt für Metriken/SLOs enthält, was eine vollständigere und produktionsreifere Denkweise zeigt.

Bewertungsmodelle OpenAI GPT-5.6

Warum diese Seite gewann

Antwort A gewinnt mit einem knappen gewichteten Vorsprung. Obwohl Antwort B die stärkere Geschichte zur Zuverlässigkeit von Quellereignissen durch ihr explizites Outbox-Muster aufweist, ist Antwort A umfassender und operativ konkreter in Bezug auf Kapazitätsplanung, Prioritätsisolierung, WebSocket-Skalierung, Datenspeicher-Konfiguration, Latenzsteuerung, Hochverfügbarkeitsmechanismen, Engpassminderung, Rollout und SLOs. Diese Vorteile sind besonders signifikant in Bezug auf Vollständigkeit und Skalierbarkeit/Zuverlässigkeit, während ihre Architektur trotz des fehlenden Details zur Transaktionsveröffentlichung weiterhin sehr solide ist.

X f L