Orivel Orivel
Ouvrir le menu

Concevoir un système de notifications en temps réel pour une application de réseau social

Comparez les réponses des modèles pour cette tâche de benchmark en Conception de systèmes et consultez scores, commentaires et exemples liés.

Connectez-vous ou inscrivez-vous pour utiliser les likes et favoris. Inscription

X f L

Sommaire

Vue d’ensemble de la tâche

Genres de comparaison

Conception de systèmes

Modèle créateur de la tâche

Modèles participants

Modèles évaluateurs

Consigne de la tâche

Vous êtes un ingénieur logiciel senior chargé de concevoir un système de notifications en temps réel pour une application de réseau social en forte croissance. Le système doit être hautement évolutif, fiable et délivrer les notifications avec une faible latence. Fournissez une proposition détaillée de conception du système.

Informations complémentaires

L'application de réseau social présente les caractéristiques et exigences suivantes :

Scale:

  • 10 millions d'utilisateurs actifs quotidiens (DAU).
  • Chaque utilisateur reçoit en moyenne 20 notifications par jour.
  • Le trafic de pointe peut atteindre jusqu'à 5 fois le trafic moyen.

Functional Requirements:

  • Notification Types: J'aime, commentaires, nouveaux abonnés, messages directs.
  • Delivery: Les notifications doivent être délivrées en quasi-temps réel (latence inférieure à 2 secondes...
Afficher plus

L'application de réseau social présente les caractéristiques et exigences suivantes :

Scale:

  • 10 millions d'utilisateurs actifs quotidiens (DAU).
  • Chaque utilisateur reçoit en moyenne 20 notifications par jour.
  • Le trafic de pointe peut atteindre jusqu'à 5 fois le trafic moyen.

Functional Requirements:

  • Notification Types: J'aime, commentaires, nouveaux abonnés, messages directs.
  • Delivery: Les notifications doivent être délivrées en quasi-temps réel (latence inférieure à 2 secondes).
  • Channels: Support à la fois des notifications push dans l'application (vers les appareils mobiles) et des notifications par e-mail.
  • History: Les utilisateurs doivent pouvoir consulter leurs 100 dernières notifications.
  • Preferences: Les utilisateurs peuvent activer/désactiver des types de notifications spécifiques.

Non-Functional Requirements:

  • High Availability: Le système doit être hautement disponible avec un temps d'arrêt minimal.
  • Reliability: Aucune notification ne doit être perdue.
  • Scalability: L'architecture doit pouvoir évoluer pour prendre en charge 100 millions d'utilisateurs actifs quotidiens à l'avenir.
  • Cost-Effectiveness: La conception doit être soucieuse des coûts opérationnels.

Votre proposition doit couvrir l'architecture de haut niveau, les composants clés, les choix technologiques, le modèle de données et les stratégies pour assurer l'évolutivité et la fiabilité. Veillez à expliquer les compromis que vous avez pris en compte dans votre conception.

Politique d’évaluation

Une réponse de haute qualité présentera une conception système cohérente et bien argumentée. Évaluez la réponse selon les critères suivants :

  1. Architecture: L'architecture de haut niveau proposée est-elle logique et complète ? Identifie-t-elle clairement les composants majeurs comme les API gateways, les services de notification, les queues de messages, les bases de données et les services de push tiers ?
  2. Technology Choices: Les choix technologiques (par ex., Kafka vs. RabbitMQ, NoSQL vs. SQL, choix...
Afficher plus

Une réponse de haute qualité présentera une conception système cohérente et bien argumentée. Évaluez la réponse selon les critères suivants :

  1. Architecture: L'architecture de haut niveau proposée est-elle logique et complète ? Identifie-t-elle clairement les composants majeurs comme les API gateways, les services de notification, les queues de messages, les bases de données et les services de push tiers ?
  2. Technology Choices: Les choix technologiques (par ex., Kafka vs. RabbitMQ, NoSQL vs. SQL, choix de bases de données spécifiques comme Cassandra ou Redis) sont-ils appropriés aux exigences et les justifications de ces choix sont-elles solides ?
  3. Scalability and Reliability: La conception traite-t-elle efficacement de la manière dont le système s'adaptera pour gérer les charges de pointe et la croissance future ? Les mécanismes de fiabilité et de tolérance aux pannes, tels que les tentatives de nouvelle livraison, les dead-letter queues et la réplication des bases de données, sont-ils clairement expliqués ?
  4. Trade-offs: La réponse démontre-t-elle une compréhension approfondie des principes de conception système en discutant explicitement des compromis effectués (par ex., cohérence vs disponibilité, coût vs performance, mécanismes push vs pull) ?
  5. Completeness: La conception répond-elle à toutes les exigences fonctionnelles et non fonctionnelles spécifiées, y compris l'historique des notifications, les préférences des utilisateurs et les canaux de livraison multiples ?

Réponses

Conception d'un système de notification en temps réel pour une application de médias sociaux

1. Récapitulatif des exigences et estimation sommaire

Estimation du trafic :

  • 10 millions d'utilisateurs actifs par jour × 20 notifications/jour = 200 millions de notifications/jour
  • Taux moyen = 200 millions / 86 400 s ≈ 2 315 notifications/sec
  • Taux de pointe (5x) ≈ 11 500 notifications/sec
  • Pour 100 millions d'utilisateurs actifs par jour (futur) : moyenne ~23 000/s, pointe ~115 000/s

Estimation du stockage :

  • Chaque enregistrement de notification ~500 octets (métadonnées + charge utile)
  • Stocka...
Afficher la réponse complète

Conception d'un système de notification en temps réel pour une application de médias sociaux

1. Récapitulatif des exigences et estimation sommaire

Estimation du trafic :

  • 10 millions d'utilisateurs actifs par jour × 20 notifications/jour = 200 millions de notifications/jour
  • Taux moyen = 200 millions / 86 400 s ≈ 2 315 notifications/sec
  • Taux de pointe (5x) ≈ 11 500 notifications/sec
  • Pour 100 millions d'utilisateurs actifs par jour (futur) : moyenne ~23 000/s, pointe ~115 000/s

Estimation du stockage :

  • Chaque enregistrement de notification ~500 octets (métadonnées + charge utile)
  • Stockage quotidien : 200 millions × 500 octets = 100 Go/jour → ~36 To/an (avant compression/archivage)
  • L'exigence d'historique (100 dernières notifications par utilisateur) correspond à un modèle d'accès « en lecture intensive » à chaud, favorisant une conception où les notifications récentes sont peu coûteuses à récupérer (par exemple, une liste limitée par utilisateur) tandis que l'historique complet est stocké à froid.

Cela confirme que nous avons affaire à un système lourd en écriture, lourd en diffusion (fan-out), sensible à la latence qui doit découpler l'ingestion de la livraison.


2. Architecture générale

[Producteurs d'événements] → [Bus d'événements / Kafka] → [Service de notification (Consommateurs)]
                                                    │
                        ┌───────────────────────────┼───────────────────────────┐
                        ▼                            ▼                           ▼
                 [Service de préférences]     [Rendu/Mise en forme]     [Limiteur de débit/Dédoublonnage]
                        │                            │                           │
                        └───────────────┬────────────┴───────────────────────────┘
                                        ▼
                          [Répartiteur de livraison / Routeur]
                       ┌─────────────┬─────────────┬─────────────┐
                       ▼             ▼             ▼             ▼
                 [Service Push]  [Passerelle WebSocket/  [Service E-mail]  [Écriture dans le magasin
                 (FCM/APNs)]     SSE]           (SES/SendGrid)   en application - DynamoDB/Cassandra]
                       │             │
                  [Appareils Mobiles][Clients Connectés]

Flux :

  1. Un système source (par exemple, Service de J'aime, Service de Commentaires, Service de Suivi, Service de Messagerie) émet un événement (par exemple, user_liked_post) vers un bus de messages durable (Kafka).
  2. L'Orchestrateur de notifications consomme ces événements, vérifie les préférences de l'utilisateur, applique la logique de déduplication/limitation de débit/regroupement (par exemple, « John et 5 autres personnes ont aimé votre publication »), et génère un objet de notification.
  3. L'orchestrateur persiste la notification (pour l'historique) et la pousse vers un Répartiteur de livraison, qui diffuse vers les canaux appropriés en fonction des préférences de l'utilisateur et de l'état de l'appareil (en ligne ou hors ligne).
  4. Les workers de livraison gèrent la transmission réelle : fournisseurs de notifications push (FCM pour Android, APNs pour iOS), WebSocket/SSE pour les mises à jour de badges en temps réel dans l'application, et e-mail via un fournisseur d'e-mails transactionnels.

3. Composants clés

3.1 Couche d'ingestion d'événements — Apache Kafka

  • Tous les services sources publient des événements vers des sujets Kafka (partitionnés par user_id pour préserver l'ordre par utilisateur).
  • Kafka fournit la durabilité (facteur de réplication 3), un débit élevé et un tampon naturel pendant les pics de trafic — essentiel car le trafic de pointe est 5 fois supérieur à la moyenne.
  • Sujets : notification.likes, notification.comments, notification.followers, notification.messages (ou un sujet unique avec un champ de type d'événement, selon les besoins d'évolution du schéma).

Pourquoi Kafka plutôt que SQS/RabbitMQ ? Kafka gère un débit très élevé avec une faible surcharge par message et prend en charge la relecture (utile pour retraiter des lots échoués ou pour le remplissage de données). SQS est plus simple sur le plan opérationnel mais plus difficile à faire évoluer au-delà de 100 000 msg/s de manière rentable et ne prend pas en charge les sémantiques de relecture de groupe de consommateurs de manière aussi claire.

3.2 Orchestrateur de notifications

  • Groupe de consommateurs sans état lisant depuis Kafka.
  • Responsabilités :
    • Vérification des préférences : interroger un magasin clé-valeur rapide (Redis ou DynamoDB) pour les paramètres de notification de l'utilisateur avant de poursuivre le traitement. Cela évite un travail inutile de génération de notifications auxquelles un utilisateur s'est désabonné.
    • Dédoublonnage/Regroupement : utiliser une fenêtre d'agrégation de courte durée (par exemple, des ensembles triés Redis avec TTL) pour regrouper des événements similaires (par exemple, plusieurs « j'aime » sur la même publication en 60 secondes deviennent une seule notification).
    • Diffusion pour les abonnés : pour les événements tels que « nouvelle publication de quelqu'un que vous suivez », cela peut nécessiter une diffusion à des millions d'abonnés (problème de la célébrité). Utiliser un modèle de diffusion hybride :
      • Diffusion à l'écriture pour les utilisateurs réguliers (pousser immédiatement vers le fil de notification de chaque abonné).
      • Diffusion à la lecture pour les célébrités/comptes à fort nombre d'abonnés (calculer au moment de la lecture pour éviter une tempête d'écritures).
  • Évolutif horizontalement — adapter le nombre d'instances de consommateurs en fonction du nombre de partitions Kafka et du décalage.

3.3 Magasin de notifications (Couche de persistance)

  • Magasin principal : une base de données NoSQL à colonnes larges comme Apache Cassandra ou DynamoDB, partitionnée par user_id, groupée/triée par timestamp (décroissant).
    • Ce modèle est idéal car le modèle d'accès dominant est « obtenir les 100 dernières notifications pour l'utilisateur X », ce qui correspond à une simple requête de plage sur une partition — aucune jointure nécessaire.
    • Cassandra offre une cohérence réglable et une évolutivité horizontale bien au-delà de 100 millions d'utilisateurs ; DynamoDB offre une alternative entièrement gérée avec moins de surcharge opérationnelle (compromis : coût plus élevé à très grande échelle, et risque de partition chaude pour les utilisateurs extrêmement actifs, sauf si les clés de partition sont salées).
  • TTL/Archivage : conserver uniquement les notifications récentes (par exemple, 30 à 90 jours) dans le magasin chaud ; les données plus anciennes sont archivées dans un stockage moins cher (S3 + Glacier) pour la conformité/l'audit, le plafond des « 100 dernières » étant appliqué à l'écriture (une liste limitée par utilisateur, ou tronquée par une compaction périodique).

3.4 Répartiteur de livraison

  • Lit l'objet de notification finalisé et détermine les canaux à utiliser en fonction de :
    • Préférences de canaux de l'utilisateur (push/e-mail/les deux/aucun)
    • État de connexion de l'utilisateur (suivi via un service de présence basé sur Redis, mis à jour par WebSocket/battement de cœur)
  • Route vers :
    • Service de notifications push : s'intègre avec FCM (Android) et APNs (iOS). Encapsuler dans une couche d'abstraction interne pour normaliser les nouvelles tentatives, les formats de charge utile et la gestion des jetons d'appareil (jetons stockés dans une table user_devices, rafraîchis au lancement de l'application).
    • Livraison en temps réel dans l'application : pour les utilisateurs activement connectés via WebSocket/SSE, pousser directement vers une passerelle de connexion (par exemple, une flotte de serveurs WebSocket derrière un équilibreur de charge, utilisant quelque chose comme Socket.IO ou un service géré comme AWS API Gateway WebSockets). La correspondance connexion-serveur est suivie dans Redis afin que tout nœud répartiteur puisse trouver quelle instance de passerelle détient la connexion d'un utilisateur.
    • Service d'e-mail : pour les notifications moins sensibles au temps (par exemple, résumé hebdomadaire) ou comme solution de repli pour les utilisateurs hors ligne sur certains types de notifications, s'intégrer avec un fournisseur comme Amazon SES ou SendGrid, en utilisant une file d'attente distincte à priorité plus basse car les SLA de messagerie sont plus souples (quelques secondes à quelques minutes suffisent).

3.5 Service de préférences

  • Service simple basé sur une base de données relationnelle (Postgres) ou DynamoDB, mis en cache de manière agressive dans Redis (les préférences changent rarement, lectures extrêmement fréquentes — candidat idéal pour la mise en cache).
  • Schéma : user_id, notification_type, channel, enabled.

4. Modèle de données

Table des notifications (Cassandra/DynamoDB)

Clé de partition : user_id
Clé de clustering : notification_id (UUID basé sur le temps, trié par ordre décroissant)
Attributs :
  - type (like, comment, follow, message)
  - actor_id (qui l'a déclenché)
  - actor_ids (tableau, pour les notifications groupées)
  - target_object_id (post_id, comment_id, etc.)
  - message_preview
  - created_at
  - read_status (booléen)
  - delivered_channels (tableau : push, email, in-app)

Table des préférences utilisateur

Clé de partition : user_id
Attributs : { likes: {push: true, email: false}, comments: {...}, follows: {...}, messages: {...} }

Table des jetons d'appareil

Clé de partition : user_id
Clé de clustering : device_id
Attributs : platform (ios/android), token, last_active

5. Assurer la fiabilité (« Aucune notification perdue »)

  1. Messagerie durable : Kafka avec un facteur de réplication ≥3 et acks=all sur les producteurs garantit que les événements ne sont pas perdus avant le traitement.
  2. Traitement au moins une fois avec idempotence : les consommateurs peuvent retraiter en cas d'échec/redémarrage, donc les ID de notification sont générés de manière déterministe (par exemple, hachage de l'ID d'événement source + type) pour permettre des écritures idempotentes — évite les notifications dupliquées lors de la nouvelle tentative.
  3. Files d'attente de lettres mortes (DLQ) : les livraisons échouées (par exemple, délai d'attente du fournisseur push) sont envoyées vers un sujet DLQ avec une nouvelle tentative par exponentielle décroissante (par exemple, 3 nouvelles tentatives avec jitter), puis vers une revue manuelle/alerte si l'échec persiste.
  4. Écrire la notification dans le magasin AVANT de tenter la livraison : cela découple « la notification existe » (durabilité/historique) de « la notification a été livrée » (temps réel au mieux).
  5. Modèle de boîte d'envoi (outbox) dans les services sources : pour éviter les problèmes de double écriture (écriture en base de données + publication d'événement), utiliser le modèle de boîte d'envoi transactionnelle afin que lorsqu'un « j'aime » est enregistré dans la base de données du service source, l'événement soit garanti d'être également publié dans Kafka via un outil de capture de données modifiées (CDC) comme Debezium.

6. Stratégie d'évolutivité (10 millions → 100 millions d'utilisateurs actifs par jour)

  • Kafka : augmenter le nombre de partitions (partitionnées par hachage de user_id) — évolue linéairement avec plus de brokers/consommateurs.
  • Orchestrateur et Répartiteur de notifications : sans état, évolutifs horizontalement derrière des groupes de consommateurs ; adapter via HPA Kubernetes en fonction du décalage des consommateurs Kafka.
  • Cassandra : ajouter des nœuds au cluster ; le hachage cohérent distribue la charge automatiquement. Surveiller les partitions chaudes dues au contenu viral/comptes de célébrités — atténuer via le partitionnement (par exemple, diviser la diffusion d'une célébrité sur plusieurs clés de partitionnement).
  • Passerelle WebSocket : adapter horizontalement ; utiliser des sessions collantes via un registre de connexions dans Redis afin que les répartiteurs sachent quel nœud de passerelle possède quelle connexion, quel que soit le nombre de nœuds de passerelle existants.
  • Fournisseurs Push/E-mail : ce sont des services tiers gérés (FCM, APNs, SES) qui évoluent indépendamment ; notre responsabilité est le regroupement et la limitation de débit pour rester dans les quotas des fournisseurs.
  • Mise en cache : la mise en cache agressive dans Redis des préférences et des données de présence réduit la charge de la base de données à mesure que le nombre d'utilisateurs est multiplié par 10.

7. Compromis clés

| Décision | Compromis |
|---|---|
| Kafka vs. file d'attente plus simple (SQS) | Kafka ajoute une complexité opérationnelle (nécessite une expertise dédiée en exploitation, gestion de ZooKeeper/KRaft) mais offre un débit et une capacité de relecture bien supérieurs, nécessaires à cette échelle. |
| Cassandra vs. DynamoDB | Cassandra offre plus de contrôle et potentiellement un coût inférieur à très grande échelle mais nécessite une exploitation interne ; DynamoDB est entièrement géré (plus rapide à construire, moins de charge opérationnelle) mais peut devenir coûteux à une échelle extrême et présente des contraintes plus strictes en matière de taille d'élément/partitionnement de débit. |
| Diffusion à l'écriture vs. diffusion à la lecture | La diffusion à l'écriture offre une latence de lecture plus faible (idéal pour le SLA de 2 secondes) mais risque une tempête d'écritures « troupeau » pour les célébrités ; la diffusion à la lecture évite cela mais ajoute de la latence et du calcul au moment de la lecture. L'approche hybride équilibre les deux mais ajoute de la complexité de conception/code (deux chemins de code). |
| Stockage de l'historique complet vs. 100 notifications limitées à chaud + archive | Réduit les coûts de stockage à chaud et maintient des requêtes rapides, mais nécessite un chemin d'archivage/récupération pour la conformité ou les fonctionnalités « charger plus », ajoutant de la complexité. |
| Livraison au moins une fois + idempotence vs. exactement une fois | Les sémantiques « exactement une fois » dans les systèmes distribués sont coûteuses/complexes (nécessite des consommateurs transactionnels) ; la livraison « au moins une fois » + écritures idempotentes atteint la même garantie pratique (aucune notification visible dupliquée) à un coût opérationnel bien inférieur. |
| Push en temps réel pour tout vs. regroupement/agrégation | L'agrégation de notifications similaires (par exemple, « 10 personnes ont aimé votre photo ») réduit la fatigue des notifications et le volume de livraison, améliorant à la fois l'expérience utilisateur et le coût, au détriment d'une logique d'orchestration légèrement plus complexe et d'un léger délai de mise en mémoire tampon (toujours bien dans le SLA de 2 secondes si la fenêtre est courte, par exemple, 5 à 10 secondes maximum avant vidage). |


8. Surveillance et alertes

  • Suivre le décalage des consommateurs Kafka, le taux de succès/échec de livraison par canal, la latence de bout en bout P50/P95/P99 (ingestion d'événements → livraison à l'appareil), et la profondeur des DLQ.
  • Les tableaux de bord SLA alertent l'astreinte si la latence P95 dépasse 2 secondes ou si la croissance des DLQ indique une défaillance systémique de livraison (par exemple, panne du fournisseur FCM), déclenchant une logique de basculement automatique (par exemple, mise en file d'attente et nouvelle tentative avec exponentielle décroissante plutôt que de rejeter).

Résumé

La conception découple la génération des notifications (pilotée par les événements, basée sur Kafka, idempotente) de la livraison (répartiteur multi-canal avec nouvelle tentative/exponentielle décroissante par canal), soutenue par un magasin à colonnes larges optimisé pour le modèle d'accès « historique récent par utilisateur ». Cette séparation permet au système de respecter le SLA de latence de 2 secondes tout en garantissant l'absence de perte de données, et il évolue horizontalement à chaque niveau (ingestion, traitement, stockage, livraison) pour supporter une croissance 10 fois supérieure avec une surcharge opérationnelle et de coût gérable.

Résultat

#2

Votes gagnants

0 / 3

Score moyen

83
Modèles évaluateurs OpenAI GPT-5.5

Score total

85

Commentaire global

La réponse A est une proposition de conception système solide avec des estimations de capacité précises, une architecture événementielle logique, une utilisation appropriée de Kafka, Cassandra/DynamoDB, Redis, WebSockets, APNs/FCM et des fournisseurs d'e-mails, ainsi qu'une bonne couverture de la persistance, des préférences, des nouvelles tentatives, des DLQ, de l'idempotence, de la surveillance et des compromis. Ses principales faiblesses résident dans le fait que certains domaines sont moins précis qu'ils pourraient l'être, tels que la limite de latence exacte, la stratégie HA/DR, les détails de l'API/du chemin de lecture, la priorisation en cas de surcharge et les sémantiques de livraison nuancées autour des fournisseurs externes.

Afficher le détail de l’évaluation

Qualité de l’architecture

Poids 30%
85

La réponse A présente une architecture cohérente avec des producteurs d'événements, Kafka, l'orchestration des notifications, la vérification des préférences, le stockage, les répartiteurs, la livraison WebSocket, les fournisseurs de poussée et les travailleurs d'e-mails. Le flux est logique et complet, bien que certains détails de séparation du chemin de lecture/API et des commandes de canal soient moins explicites.

Complétude

Poids 20%
83

La réponse A couvre les exigences principales : types de notifications, livraison quasi en temps réel, canaux push/e-mail/en application, historique des 100 derniers, préférences, évolutivité, fiabilité, coût, surveillance et modèles de données. Elle est un peu plus légère sur les détails de l'API, la sécurité/confidentialité, la reprise après sinistre et le comportement opérationnel exact en cas de surcharge ou de pannes de fournisseur.

Analyse des compromis

Poids 20%
84

La réponse A inclut un tableau de compromis utile couvrant Kafka vs SQS, Cassandra vs DynamoDB, fan-out-on-write vs fan-out-on-read, stockage à chaud plafonné vs archive, au moins une fois vs exactement une fois, et livraison par lots vs en temps réel. Le raisonnement est solide, bien que certains compromis soient résumés plutôt que profondément liés aux conséquences opérationnelles.

Scalabilité et fiabilité

Poids 20%
85

La réponse A fournit de solides mécanismes d'évolutivité et de fiabilité : réplication et relecture de Kafka, écritures idempotentes, DLQ, nouvelles tentatives, modèle outbox, mise à l'échelle horizontale, partitionnement Cassandra/DynamoDB, mise en cache Redis et mise à l'échelle WebSocket. Elle est moins détaillée sur la récupération multi-régions, la priorisation en cas de surcharge, la discipline des offsets du consommateur, les limites de livraison du fournisseur et les sémantiques exactes des SLO.

Clarté

Poids 10%
88

La réponse A est clairement structurée, facile à suivre et utilise efficacement des diagrammes, des puces, des schémas et un tableau de compromis concis. Elle communique la conception de manière efficace avec une ambiguïté minimale.

Modèles évaluateurs Anthropic Claude Opus 5

Score total

80

Commentaire global

La réponse A est une proposition de conception soignée et bien structurée qui serait bien reçue lors d'un entretien. Elle maîtrise les calculs de capacité, fournit un diagramme d'architecture lisible, des modèles de données concrets, un tableau des compromis clair et aborde le modèle outbox, l'idempotence, les DLQ et la mise à l'échelle horizontale à tous les niveaux. Ses faiblesses résident dans la profondeur et l'étendue de certains domaines : pas de conception d'API/chemin de lecture, pas de discussion sur la sécurité ou la confidentialité, pas de topologie HA ou de reprise après sinistre, pas d'isolation des priorités entre les classes de notifications, et elle accepte sans critique le SLA de 2 secondes de bout en bout sans noter que les fournisseurs tiers le rendent inapplicable. La suggestion de fan-out-on-read est également un peu mal adaptée à une boîte de réception de notifications.

Afficher le détail de l’évaluation

Qualité de l’architecture

Poids 30%
82

Présente une architecture en couches claire avec un diagramme ASCII, un bus d'événements (Kafka), un orchestrateur, un service de préférences, un répartiteur, une passerelle WebSocket, des workers push/email et un magasin wide-column. Le flux est facile à suivre et les composants sont bien délimités. Légères faiblesses : la discussion sur le fan-out-on-read est quelque peu mal appliquée aux notifications (c'est un concept de flux), et la couche API/chemin de lecture ainsi que la couche API gateway sont à peine abordées malgré leur mention dans la politique de jugement.

Complétude

Poids 20%
76

Couvre l'estimation, les quatre types de notifications, les canaux push/email/in-app, l'historique via une liste limitée plus l'archivage, les préférences avec schéma, les jetons de périphérique, la fiabilité, la scalabilité et la surveillance. Manquant ou faible : conception d'API/chemin de lecture, sécurité et confidentialité, reprise après sinistre et stratégie multi-régions, comptes non lus et topologie HA explicite (répartition AZ).

Analyse des compromis

Poids 20%
80

Un tableau de compromis dédié couvre Kafka vs SQS, Cassandra vs DynamoDB, fan-out à l'écriture vs à la lecture, stockage à chaud vs archive, au moins une fois vs exactement une fois, et batching vs immédiateté. Chaque entrée nomme à la fois l'avantage et le coût, ce qui est clair et lisible. Cependant, les compromis sont principalement conventionnels et énoncés brièvement, avec moins de profondeur sur les limites de cohérence, les garanties d'ordre ou les nuances de définition des SLO.

Scalabilité et fiabilité

Poids 20%
80

Solide : partitionnement et réplication Kafka, acks=all, au moins une fois avec des identifiants idempotents déterministes, DLQ avec backoff exponentiel et jitter, écriture avant livraison, outbox transactionnel avec Debezium, HPA sur le décalage du consommateur, expansion de l'anneau Cassandra, salage des partitions chaudes, et registre de connexions Redis. Manque de HA multi-AZ/multi-régions explicite, de procédures de DR/basculement, de backpressure ou d'isolation des priorités entre les classes de notifications, et de sémantique de commit de décalage.

Clarté

Poids 10%
85

Excellente lisibilité : sections numérotées, un diagramme d'architecture ASCII, des blocs de code pour le modèle de données, un tableau des compromis et un résumé concis. Facile à parcourir et rapide à saisir la conception en un coup d'œil.

Modèles évaluateurs Google Gemini 2.5 Pro

Score total

85

Commentaire global

La réponse A fournit une conception de système très solide et bien structurée. Ses principaux atouts sont sa clarté et son organisation, utilisant un diagramme et un tableau pour rendre les concepts complexes faciles à comprendre. Elle couvre toutes les exigences fondamentales de la requête, proposant une architecture logique avec des choix technologiques appropriés et des stratégies saines pour la scalabilité et la fiabilité. Cependant, elle manque de la profondeur et de l'étendue de la réponse B, en particulier dans des domaines tels que la conception d'API, la sécurité et la planification détaillée de la reprise après sinistre.

Afficher le détail de l’évaluation

Qualité de l’architecture

Poids 30%
85

L'architecture proposée est logique, complète et bien adaptée à la tâche. Elle identifie clairement tous les composants majeurs et leurs interactions, et l'inclusion d'un diagramme facilite grandement la compréhension. Le flux des producteurs d'événements vers les canaux de diffusion est bien défini.

Complétude

Poids 20%
80

La réponse aborde toutes les exigences fonctionnelles et non fonctionnelles spécifiées dans la requête. Elle couvre les aspects principaux de la conception, y compris les estimations, les composants, les modèles de données et les stratégies de mise à l'échelle et de fiabilité.

Analyse des compromis

Poids 20%
85

La réponse discute clairement des compromis clés dans un tableau dédié, ce qui est très efficace. Elle fournit des justifications solides pour des choix tels que Kafka plutôt que SQS et Cassandra plutôt que DynamoDB, démontrant une bonne compréhension des principes impliqués.

Scalabilité et fiabilité

Poids 20%
85

La conception aborde efficacement la scalabilité et la fiabilité. Elle propose des techniques standard et efficaces telles que la mise à l'échelle horizontale pour les services, le partitionnement dans Kafka et Cassandra, et l'utilisation de DLQ et d'idempotence pour la fiabilité. Les stratégies sont saines et bien expliquées.

Clarté

Poids 10%
90

La réponse est exceptionnellement claire et bien organisée. L'utilisation de titres, d'un diagramme de flux et d'un tableau pour les compromis rend la conception complexe facile à suivre et à assimiler. L'écriture est directe et va droit au but.

Réponse B: OpenAI GPT-5.6

APERÇU

Le système doit traiter chaque notification comme un enregistrement durable et spécifique au destinataire, et la diffuser de manière asynchrone via un ou plusieurs canaux. La boîte de réception durable dans l'application est la source de vérité ; les notifications push mobiles et les e-mails sont des tentatives de livraison dérivées de cet enregistrement. Cette séparation offre une faible latence sans obliger les actions sociales visibles par l'utilisateur à attendre des fournisseurs externes tels que APNs, FCM ou un service de messagerie.

ESTIMATIONS DE CAPACITÉ

Avec 10 millions d'utilisateurs actifs q...

Afficher la réponse complète

APERÇU

Le système doit traiter chaque notification comme un enregistrement durable et spécifique au destinataire, et la diffuser de manière asynchrone via un ou plusieurs canaux. La boîte de réception durable dans l'application est la source de vérité ; les notifications push mobiles et les e-mails sont des tentatives de livraison dérivées de cet enregistrement. Cette séparation offre une faible latence sans obliger les actions sociales visibles par l'utilisateur à attendre des fournisseurs externes tels que APNs, FCM ou un service de messagerie.

ESTIMATIONS DE CAPACITÉ

Avec 10 millions d'utilisateurs actifs quotidiens (DAU) et 20 notifications par utilisateur par jour, le système crée environ 200 millions de notifications par jour. Cela représente environ 2 315 notifications par seconde en moyenne et 11 600 par seconde au pic de 5x indiqué. Avec 100 millions de DAU, les débits correspondants sont d'environ 23 000 par seconde en moyenne et 116 000 par seconde en pic.

Il s'agit de débits par destinataire-notification, et non de simples débits d'événements sources. Une publication de célébrité peut produire un pic de clé chaude ou de diffusion à grande échelle (fan-out), de sorte que les couches d'ingestion et de mise en file d'attente doivent être provisionnées au-dessus du pic calculé, initialement pour environ 25 000 notifications par seconde et éventuellement pour au moins 200 000 par seconde. Les charges utiles doivent rester petites, les médias et le contenu complet des publications étant référencés par ID plutôt qu'intégrés.

ARCHITECTURE DE HAUT NIVEAU

Les services sociaux tels que J'aime, Commentaire, Suivre et Message Direct écrivent leur propre état et un événement de notification dans une « outbox » transactionnelle dans la même transaction de base de données. Les éditeurs d'outbox transfèrent en continu ces événements vers un journal d'événements durable tel qu'Apache Kafka. Cela évite l'échec de double écriture dans lequel une action sociale réussit mais son événement de notification est perdu.

Un processeur de notifications consomme les événements sources, les valide, identifie les destinataires, génère un ID de notification déterministe, charge les préférences de notification, effectue un enrichissement léger et écrit la notification du destinataire dans le magasin de la boîte de réception. Il publie ensuite une commande de livraison durable par canal activé vers des sujets Kafka spécifiques aux canaux.

Les Workers de notifications push consomment les commandes push et invoquent APNs ou FCM. Les Workers d'e-mails rendent les modèles et invoquent un fournisseur tel qu'Amazon SES, SendGrid ou un service interne de transfert de courrier. Une passerelle WebSocket peut également consommer les commandes de livraison dans l'application et mettre à jour immédiatement les clients actuellement connectés ; les clients déconnectés voient toujours la boîte de réception durable lors de la reconnexion. Les résultats de livraison et les nouvelles tentatives sont enregistrés de manière asynchrone.

Le flux principal est le suivant :

Service social et outbox transactionnelle → Sujets d'événements sources Kafka → Processeur de notifications → Magasin de boîte de réception durable → Sujets de commandes de canaux → Workers WebSocket, APNs/FCM et e-mail.

Le flux de lecture est le suivant :

Client → API Gateway → API de notifications → Magasin de boîte de réception et magasin de préférences.

COMPOSANTS CLÉS

L'API Gateway gère l'authentification, la limitation du débit, le routage des requêtes et la protection contre les abus. L'API de notifications prend en charge la récupération des notifications récentes, la pagination basée sur curseur, les comptes de non lus, le marquage d'un ou plusieurs éléments comme lus et la gestion des préférences.

Kafka fournit la mise en mémoire tampon durable, le lissage du trafic, la relecture, l'isolation des consommateurs et la scalabilité horizontale. Les sujets sont répliqués sur au moins trois zones de disponibilité. Les sujets sources peuvent être partitionnés par ID utilisateur destinataire après expansion des destinataires, en préservant l'ordre par utilisateur tout en distribuant les utilisateurs sur les partitions. L'expansion à fort fan-out peut utiliser un pool de workers distinct afin qu'un événement important ne puisse pas bloquer le trafic normal.

Le processeur de notifications doit être sans état et autoscalé en utilisant le décalage de la file d'attente, la latence de traitement, le CPU et le débit. Il évalue les préférences avant d'émettre des commandes de canal. Les préférences peuvent être mises en cache dans Redis, mais la valeur faisant autorité reste dans un magasin durable. Des événements d'invalidation de cache sont émis chaque fois que les préférences changent.

Le magasin de boîte de réception doit être une base de données clé-valeur ou à colonnes larges horizontalement évolutive telle que DynamoDB, Cassandra ou ScyllaDB. DynamoDB offre une charge opérationnelle plus faible et des options multi-régions gérées ; Cassandra ou ScyllaDB peuvent être moins chers à grande échelle soutenue mais nécessitent plus d'expertise opérationnelle. Une base de données relationnelle est moins adaptée à la boîte de réception principale car le volume d'écriture, la croissance des partitions et la mise à l'échelle inter-shards deviendraient coûteux.

Redis peut mettre en cache les comptes de non lus et la première page de la boîte de réception, mais il ne doit pas être le système d'enregistrement. Les passerelles WebSocket sont sans état, à l'exception de l'état de connexion actif. Un répertoire de présence dans Redis ou un magasin éphémère similaire mappe les utilisateurs aux instances de passerelle.

MODÈLE DE DONNÉES

Un enregistrement de notification contient notification_id, recipient_user_id, type, actor_user_id, object_type, object_id, creation_time, template_version, données de rendu compactes, read_time et informations de regroupement facultatives. L'état du canal doit contenir les canaux demandés et le statut de livraison tels que en attente, expédié, échoué ou supprimé. Les corps volumineux et le contenu social mutable ne doivent pas être copiés dans l'enregistrement, sauf si un instantané immuable est requis.

Une clé de boîte de réception appropriée est partition_key = recipient_user_id plus un compartiment temporel facultatif, et sort_key = reverse_timestamp plus notification_id. Le tri chronologique inversé rend la dernière page efficace. À volume ordinaire, une partition par utilisateur est suffisante ; les comptes exceptionnellement actifs peuvent utiliser des compartiments mensuels. L'API interroge d'abord le compartiment le plus récent et suit un curseur opaque dans les compartiments plus anciens.

L'exigence n'expose que les 100 dernières notifications. Le service peut en conserver un peu plus, par exemple 30 à 90 jours, et appliquer une expiration TTL, tandis que l'API de lecture renvoie au maximum 100. Le nettoyage ou l'expiration asynchrone des enregistrements est plus sûr et moins cher que d'effectuer une suppression synchrone à chaque insertion. Si un stockage physique strict de exactement 100 enregistrements est requis, un compacteur en arrière-plan peut supprimer les entrées plus anciennes.

Les préférences sont indexées par ID utilisateur et contiennent des paramètres par type, par canal, par exemple likes.push, likes.email, comments.push et comments.email, plus une mise en sourdine globale, une locale, un fuseau horaire et une version qui augmente de manière monotone. Les jetons d'appareil sont stockés séparément par ID utilisateur et ID d'appareil, avec la plateforme, le jeton, l'heure de dernière consultation et le statut de validité. Les jetons doivent être chiffrés et invalidés après des erreurs APNs ou FCM permanentes.

Un ID de notification déterministe peut être dérivé de source_event_id, recipient_user_id, type de notification et version sémantique. L'écriture dans la boîte de réception est conditionnelle à cet ID, ce qui rend la relecture et la consommation en double sûres. Une commande de livraison a un ID déterministe similaire basé sur l'ID de notification et le canal.

SEMANTIQUE DE LIVRAISON ET FIABILITÉ

La garantie pratique est un traitement durable « au moins une fois » avec des effets idempotents. Une livraison « exactement une fois » à travers les bases de données, Kafka, APNs, FCM et les e-mails n'est pas réalisable de bout en bout. Les outboxes transactionnelles garantissent que les actions sources acceptées sont finalement publiées. La réplication Kafka et les écritures acquittées empêchent la perte de files d'attente. Les écritures conditionnelles dans la boîte de réception suppriment les enregistrements en double. Les workers de canal stockent ou dédupliquent les ID de tentative de livraison, réduisant les envois en double lors des nouvelles tentatives.

Une notification est considérée comme acceptée uniquement après que la transaction source contenant sa ligne d'outbox a été validée. Elle est considérée comme créée durablement après que l'écriture dans la boîte de réception a réussi. Les offsets Kafka ne sont validés qu'après que l'écriture durable correspondante ou le transfert au fournisseur soit terminé. Les échecs transitoires utilisent un backoff exponentiel avec gigue. Après un nombre limité de tentatives, les commandes sont déplacées vers un sujet de lettres mortes avec l'erreur, la référence à la charge utile et l'historique des tentatives.

Les fournisseurs mobiles et l'infrastructure de messagerie ne peuvent pas garantir qu'un appareil ou une boîte aux lettres présentera une notification dans les deux secondes. Par conséquent, le service doit définir l'objectif de latence comme le temps écoulé entre l'événement source validé et la visibilité dans la boîte de réception durable et le premier dispatch du fournisseur. Un SLO raisonnable est de 99 % en moins de deux secondes sous charge prise en charge. Les accusés de réception APNs et FCM signifient l'acceptation par le fournisseur, pas l'affichage par l'utilisateur. La boîte de réception durable garantit que les pannes de fournisseur ou les appareils hors ligne ne font pas perdre la notification de l'historique de l'utilisateur.

Pour les clients actuellement connectés, le chemin WebSocket fournit normalement la livraison la plus rapide. Les messages WebSocket transportent les ID de notification, et les clients les dédupliquent par rapport aux enregistrements de boîte de réception récupérés. Lors de la reconnexion, les clients récupèrent les notifications après leur dernier curseur, de sorte que les messages socket perdus ne créent pas d'écarts.

SCALABILITÉ

Les sujets Kafka doivent commencer avec suffisamment de partitions pour le parallélisme attendu et être étendus avant d'atteindre les limites de débit des partitions. Le partitionnement par ID de destinataire répartit uniformément les utilisateurs ordinaires. Les événements de célébrités ne doivent pas utiliser l'ID d'acteur comme clé de partition car cela crée une partition chaude. L'expansion des destinataires peut diviser une grande audience en morceaux et publier chaque morceau indépendamment.

Les processeurs, les passerelles WebSocket et les workers de canal sont sans état et horizontalement évolutifs. L'autoscaling doit prendre en compte le décalage Kafka et l'âge du message le plus ancien, plutôt que le CPU seul. Des groupes de consommateurs et des quotas distincts isolent les messages directs des J'aime et des e-mails de priorité inférieure. En cas de surcharge, la capacité est réservée aux messages directs et aux commentaires, tandis que les e-mails et les J'aime de faible priorité peuvent être mis en file d'attente sans être rejetés.

La capacité de la boîte de réception augmente linéairement avec le nombre d'utilisateurs mais reste limitée par le TTL et l'exigence d'historique limité. Avec 100 millions de DAU et 20 notifications par jour, la conception doit gérer environ deux milliards d'écritures quotidiennes. Les partitions d'utilisateurs par compartiment temporel, la capacité de base de données à la demande ou provisionnée, les enregistrements compacts compressés et l'absence de diffusion synchrone d'index secondaires la rendent gérable. Les requêtes globales coûteuses doivent être servies à partir d'un pipeline d'analyse, et non de la boîte de réception transactionnelle.

HAUTE DISPONIBILITÉ ET REPRISE APRÈS SINISTRE

Chaque composant synchrone s'exécute sur au moins trois zones de disponibilité derrière des équilibreurs de charge contrôlés par des vérifications de santé. Kafka utilise un facteur de réplication de trois avec des paramètres d'acquittement forts et un nombre approprié de réplicas synchronisés minimum. Les magasins de boîte de réception et de préférences utilisent la réplication multi-zones et des sauvegardes ponctuelles. Les déploiements utilisent des stratégies de canary ou de déploiement progressif, des schémas d'événements rétrocompatibles et un versionnage de schéma via un registre.

Une conception initiale rentable utilise une région active avec redondance multi-zones et une région de secours à chaud répliquée de manière asynchrone. Les procédures de récupération promeuvent la région de secours, restaurent les consommateurs à partir des offsets répliqués ou des événements conservés, et relisent en toute sécurité car le traitement est idempotent. Pour une disponibilité régionale plus stricte, le système peut évoluer vers une ingestion régionale active-active, avec des utilisateurs assignés à une région d'origine et des ID d'événements globalement uniques. L'actif-actif améliore le temps de récupération mais augmente le coût de la base de données, la gestion des doublons, la complexité de l'ordre et les défis de cohérence des préférences.

Les modifications de préférences doivent utiliser des écritures fortement cohérentes dans la région d'origine de l'utilisateur. Une notification déjà créée durablement avant une modification de préférence peut toujours être livrée ; cette limite doit être documentée. Pour la suppression légalement requise ou la suppression de compte, les workers doivent effectuer une vérification supplémentaire faisant autorité immédiatement avant la livraison externe.

OPTIMISATIONS DE LATENCE

Le chemin critique ne contient aucun appel synchrone aux fournisseurs APNs, FCM ou de messagerie. Les charges utiles des événements incluent suffisamment de métadonnées d'acteur et d'objet pour le rendu de base, évitant ainsi plusieurs appels aux services en aval. L'enrichissement facultatif manquant doit produire une notification générique plutôt que de bloquer la livraison. Les enregistrements de préférences et les modèles sont mis en cache localement ou dans Redis, et les connexions à Kafka, aux bases de données et aux fournisseurs sont mises en commun.

Le rendu et l'envoi d'e-mails utilisent un sujet distinct car l'e-mail est plus lent et plus coûteux que la livraison dans l'application. Si les exigences du produit le permettent, les J'aime non urgents peuvent être regroupés ou envoyés sous forme d'e-mails de résumé, tandis que les commentaires, les suivis et les messages directs restent immédiats. Le regroupement réduit les coûts et la fatigue de l'utilisateur mais modifie la sémantique des notifications, il doit donc s'agir d'une décision produit explicite.

CONCEPTION DE L'API

GET /v1/notifications?cursor=...&limit=... renvoie des enregistrements chronologiques inversés, limités aux 100 derniers. POST /v1/notifications/read accepte un ou plusieurs ID de notification ou un horodatage de lecture. GET et PUT /v1/notification-preferences lisent et mettent à jour les paramètres versionnés. Les points de terminaison POST et DELETE device-token enregistrent et révoquent les appareils. Tous les points de terminaison de mutation prennent en charge les clés d'idempotence.

Les comptes de non lus peuvent être maintenus comme un compteur éventuellement cohérent mis à jour à partir des événements de boîte de réception et de lecture. Étant donné que les nouvelles tentatives peuvent corrompre les incréments naïfs, les mises à jour de compteur doivent être idempotentes ou être réconciliées périodiquement à partir d'enregistrements faisant autorité. Si des comptes de non lus exacts sont requis, le service peut interroger un index de non lus limité à l'utilisateur, moyennant un coût de lecture et de stockage plus élevé.

OBSERVABILITÉ ET OPÉRATIONS

Les métriques incluent le taux d'acceptation des événements, la latence de bout en bout par type de notification et par canal, le décalage Kafka, l'âge du message le plus ancien dans la file d'attente, les erreurs d'écriture dans la boîte de réception, les codes de réponse du fournisseur, les nombres de tentatives, le volume de lettres mortes, le nombre de connexions WebSocket, le taux de succès du cache de préférences et le taux de suppression des doublons. Le traçage distribué transporte source_event_id et notification_id à chaque étape. Les journaux structurés excluent les corps de messages et les jetons sensibles.

Les alertes doivent être basées sur les taux d'épuisement des SLO et l'âge du message le plus ancien. Des utilisateurs synthétiques génèrent en continu des événements et vérifient les chemins de la boîte de réception, WebSocket, du fournisseur push et du fournisseur d'e-mails. La relecture des lettres mortes, le basculement régional, les pannes de fournisseur, la perte de partitions Kafka et la limitation des bases de données doivent être exercés régulièrement par le biais de runbooks et de tests d'injection de fautes.

SÉCURITÉ ET CONFIDENTIALITÉ

Les services s'authentifient avec des identités de courte durée et reçoivent un accès au moindre privilège. Les données sont chiffrées en transit et au repos, et les jetons d'appareil et les adresses e-mail bénéficient d'une protection supplémentaire. Les charges utiles de notification affichées sur un écran de verrouillage doivent éviter le contenu sensible des messages directs, sauf si l'utilisateur active explicitement les aperçus. Les API garantissent que les utilisateurs ne peuvent accéder qu'à leur propre boîte de réception et à leurs préférences. Les exigences de rétention, de suppression de compte, de journalisation d'audit et de résidence des données régionales doivent être intégrées au cycle de vie du stockage.

COÛTS ET COMPROMIS

Kafka est préférable aux appels inter-services synchrones car il absorbe les rafales et permet la relecture, bien qu'il introduise une complexité opérationnelle et une cohérence éventuelle. Un service Kafka géré réduit le risque opérationnel à un coût direct plus élevé. DynamoDB est opérationnellement simple et élastique, tandis que Cassandra ou ScyllaDB peuvent réduire le coût de stockage à l'état stable mais nécessitent une équipe d'exploitation compétente.

Écrire dans la boîte de réception avant d'émettre les commandes de canal garantit que l'historique fait autorité et qu'aucune commande de canal ne fait référence à un enregistrement manquant, au prix d'une légère latence d'écriture supplémentaire. La livraison « au moins une fois » est choisie plutôt qu'une conception prétendument « exactement une fois » car elle reste correcte en cas de plantages et de nouvelles tentatives de fournisseurs externes lorsqu'elle est associée à des ID déterministes et à l'idempotence.

Le partitionnement par clé de destinataire préserve l'ordre par utilisateur mais ne fournit pas d'ordre global, ce qui est inutile. Un ordre strict à travers chaque notification réduirait le débit et la disponibilité. De même, les caches de préférences améliorent la latence mais peuvent servir brièvement des valeurs obsolètes ; l'invalidation versionnée et une vérification finale pour la suppression sensible équilibrent performance et correction.

Le déploiement initial recommandé est un cluster Kafka géré, un stockage de boîte de réception et de préférences de style DynamoDB géré, Redis pour le cache éphémère et la présence, des services conteneurisés sans état sur Kubernetes ou une plateforme de conteneurs gérée, APNs/FCM pour les notifications push mobiles, et SES ou un fournisseur d'e-mails comparable. Cette architecture prend en charge confortablement le pic actuel, évolue horizontalement vers 100 millions de DAU, conserve un historique durable visible par l'utilisateur et isole les échecs de livraison externes de l'application sociale principale.

Résultat

#1 | Gagnant

Votes gagnants

3 / 3

Score moyen

90
Modèles évaluateurs OpenAI GPT-5.5

Score total

93

Commentaire global

La réponse B est une conception exceptionnellement complète et bien raisonnée. Elle sépare clairement la création de la boîte de réception durable des tentatives de livraison externes, inclut la gestion transactionnelle de la boîte d'envoi, la mise en file d'attente spécifique au destinataire, le traitement idempotent au moins une fois, les travailleurs spécifiques au canal, la conception de stockage évolutive, le comportement de l'API, la haute disponibilité/reprise après sinistre, l'observabilité, la sécurité, les considérations de coût et une analyse nuancée des compromis. Elle est un peu longue, mais la structure reste claire et les détails ajoutés sont directement pertinents pour les exigences de conception du système.

Afficher le détail de l’évaluation

Qualité de l’architecture

Poids 30%
92

La réponse B fournit une architecture très solide avec une boîte d'envoi transactionnelle, des sujets sources Kafka, des processeurs sans état, un magasin de boîte de réception durable, des sujets de commandes spécifiques au canal, des travailleurs WebSocket/APNs/FCM/email, une passerelle API et des API de lecture. La séparation entre la création de notifications durables et les tentatives de livraison est particulièrement bien conçue.

Complétude

Poids 20%
94

La réponse B aborde en profondeur la quasi-totalité des exigences spécifiées et implicites, y compris l'historique, les préférences, les canaux multiples, les comptes non lus, les jetons d'appareil, les nouvelles tentatives, les DLQ, les points d'accès API, l'observabilité, la sécurité, la rétention, la haute disponibilité/reprise après sinistre et la mise à l'échelle future à 100 millions d'utilisateurs actifs par jour. Elle gère également des cas nuancés tels que les préférences obsolètes, les limitations du fournisseur et le comportement de reconnexion.

Analyse des compromis

Poids 20%
93

La réponse B démontre un raisonnement approfondi sur les compromis tout au long de la proposition, y compris l'infrastructure gérée par rapport à l'auto-exploitée, la durabilité de la boîte de réception d'abord par rapport à la latence, au moins une fois par rapport à exactement une fois, les régions actif-passif par rapport à actif-actif, l'obsolescence du cache de préférences, le partitionnement des destinataires par rapport à l'ordre global, et le coût par rapport à la performance.

Scalabilité et fiabilité

Poids 20%
95

La réponse B est excellente en matière de scalabilité et de fiabilité. Elle couvre la planification de la capacité par destinataire, l'atténuation du fan-out intense, la stratégie de partitionnement, la mise à l'échelle automatique basée sur le décalage et l'âge du message le plus ancien, les identifiants déterministes idempotents, les écritures conditionnelles, les règles de validation des offsets, les DLQ, la relecture, le déploiement multi-AZ, la veille chaude, l'évolution actif-actif et les limites de défaillance des fournisseurs externes.

Clarté

Poids 10%
89

La réponse B est très claire et organisée avec des sections bien étiquetées et une formulation précise. Elle est plus longue et plus dense que la réponse A, mais le détail est pertinent et la conception principale reste facile à comprendre.

Modèles évaluateurs Anthropic Claude Opus 5

Score total

86

Commentaire global

La réponse B est une conception plus approfondie et plus mature sur le plan opérationnel. Elle établit la boîte de réception durable comme source de vérité et en dérive les livraisons de canaux, utilise des outbox transactionnelles et des sujets de commandes par canal avec des identifiants déterministes et des écritures conditionnelles, et définit des limites précises d'acceptation/durabilité avec un ordre de validation des offsets. Elle va bien au-delà de A en matière de conception d'API, de cohérence des messages non lus, de partitionnement par blocs temporels, de haute disponibilité entre les zones de disponibilité, de reprise après sinistre et de basculement régional, d'isolation des priorités en cas de surcharge, d'observabilité avec des sondes synthétiques et l'injection de fautes, ainsi que de sécurité/confidentialité. Elle reformule également de manière critique l'objectif de latence de 2 secondes en un objectif de niveau de service (SLO) sur la visibilité de la boîte de réception et l'expédition par le fournisseur — une vision véritablement senior. Sa principale faiblesse réside dans la présentation : une prose dense et ininterrompue sans diagramme, tableau ou schéma formaté, ce qui la rend plus difficile à parcourir que A.

Afficher le détail de l’évaluation

Qualité de l’architecture

Poids 30%
87

Architecture très solide : outbox transactionnelle avec des éditeurs de type CDC, des sujets sources Kafka, un processeur de notifications sans état qui écrit la boîte de réception durable comme source de vérité, puis des sujets de commandes durables par canal consommés par des workers push/email/WebSocket. Elle sépare explicitement les chemins d'écriture et de lecture, comprend une passerelle API et une API de notification avec des points d'accès concrets, un répertoire de présence et des pools de workers distincts pour un fan-out élevé. La conception des sujets de commandes de canal et le cadre 'boîte de réception comme source de vérité' sont plus rigoureux que le modèle de dispatcher de A. Le seul inconvénient est l'absence d'un diagramme visuel, bien que le flux textuel soit explicite.

Complétude

Poids 20%
88

Couvre essentiellement toutes les exigences et plus encore : estimations de capacité pour l'utilisation actuelle et pour 100 millions d'utilisateurs actifs par jour, modèle de données avec clés de partitionnement/tri et regroupement temporel, versionnement des préférences et invalidation du cache, cycle de vie des jetons d'appareil et chiffrement, API REST explicite avec curseurs et clés d'idempotence, cohérence des messages non lus, haute disponibilité sur trois zones de disponibilité, reprise après sinistre avec standby à chaud et procédure de basculement, observabilité avec des canaris synthétiques, et sécurité/confidentialité incluant les aperçus sur écran de verrouillage et la résidence des données. Très peu de lacunes.

Analyse des compromis

Poids 20%
85

Les compromis sont intégrés tout au long du document et consolidés dans une section de coûts : Kafka vs appels synchrones, géré vs auto-hébergé, DynamoDB vs Cassandra/ScyllaDB, coût de latence d'écriture-avant-expédition de la boîte de réception, au moins une fois avec des identifiants déterministes, ordre par utilisateur vs ordre global, fraîcheur du cache vs correction avec une vérification pré-envoi faisant autorité pour la suppression légale, actif-actif vs standby à chaud, et regroupement des digests comme décision produit explicite. Notamment, il remet également en question la prémisse du SLA de 2 secondes, redéfinissant la latence comme l'engagement source vers la boîte de réception durable et la première expédition par le fournisseur — une vision de niveau senior. Le format est moins facile à parcourir que le tableau de A.

Scalabilité et fiabilité

Poids 20%
89

Exceptionnellement approfondi : cibles de surprovisionnement supérieures aux pics calculés, partitionnement par clé de destinataire avec avertissement explicite contre les partitions chaudes par clé d'acteur, expansion des destinataires par lots, autoscaling basé sur le décalage et l'âge du message le plus ancien plutôt que sur le CPU, groupes de consommateurs et quotas séparés pour prioriser les messages directs par rapport aux likes en cas de surcharge, validation des offsets uniquement après écriture durable, écritures conditionnelles pour la déduplication, DLQ avec rejeu, RF=3 avec ISR minimum, multi-AZ, reprise après sinistre avec standby à chaud et rejeu idempotent, stockage limité par TTL, et analyse de 2 milliards d'écritures quotidiennes à 100 millions d'utilisateurs actifs par jour. L'injection de fautes et les exercices de runbook ajoutent une crédibilité opérationnelle.

Clarté

Poids 10%
74

Bien organisé avec des en-têtes de section clairs et une prose technique précise et dense, mais il s'agit uniformément de longs paragraphes sans diagramme, sans tableau et sans schéma formaté en code. Charge cognitive plus élevée et plus difficile à parcourir, bien que le contenu lui-même soit sans ambiguïté et logiquement ordonné.

Modèles évaluateurs Google Gemini 2.5 Pro

Score total

92

Commentaire global

La réponse B est une proposition de conception de système exceptionnelle et complète qui démontre un niveau d'expertise approfondi. Elle répond non seulement à toutes les exigences, mais va bien au-delà, en abordant des aspects critiques tels que la conception d'API, la sécurité, des stratégies détaillées de haute disponibilité/reprise après sinistre et l'observabilité avec une rigueur professionnelle. Les choix architecturaux sont nuancés et bien justifiés, et la discussion sur la scalabilité et la fiabilité est particulièrement détaillée et pratique. Bien que sa prose dense la rende légèrement moins accessible que la réponse A, sa profondeur technique et sa complétude sont exceptionnelles.

Afficher le détail de l’évaluation

Qualité de l’architecture

Poids 30%
90

L'architecture est exceptionnellement bien conçue, démontrant une compréhension mature des systèmes distribués. Elle met correctement l'accent sur le modèle outbox transactionnel dès le départ et propose un flux affiné avec des sujets distincts pour les événements source et les commandes de canal. L'inclusion de la passerelle API et des considérations de conception d'API rend l'architecture plus complète.

Complétude

Poids 20%
95

Cette réponse est exceptionnellement complète. Elle couvre non seulement toutes les exigences de l'énoncé, mais aborde également des domaines connexes cruciaux tels que la conception d'API, la sécurité et la confidentialité, des stratégies détaillées de haute disponibilité et de reprise après sinistre, et l'observabilité. Cette approche globale reflète un état d'esprit holistique et prêt pour la production.

Analyse des compromis

Poids 20%
90

La discussion des compromis est sophistiquée et intégrée tout au long de la conception, avec un résumé concis à la fin. Elle couvre un large éventail de décisions, des choix technologiques aux modèles architecturaux comme les modèles de disponibilité régionaux et les sémantiques de livraison, démontrant une expertise approfondie.

Scalabilité et fiabilité

Poids 20%
95

Le traitement de la scalabilité et de la fiabilité est exceptionnel. Il fournit des stratégies très spécifiques et pratiques, telles que le partitionnement par ID de destinataire pour éviter les points chauds induits par les célébrités, l'utilisation de files d'attente prioritaires et la définition d'objectifs de niveau de service (SLO) de latence réalistes. La section détaillée sur la haute disponibilité/reprise après sinistre est une force majeure.

Clarté

Poids 10%
85

La réponse est bien structurée et rédigée avec précision technique. Cependant, sa prose est assez dense, et l'absence d'aides visuelles comme des diagrammes ou des tableaux la rend légèrement moins immédiatement accessible que la réponse A, nécessitant une lecture plus attentive pour saisir pleinement tous les détails.

Résumé comparatif

Pour chaque tâche et discussion, le classement final est déterminé par agrégation des rangs par évaluateur (rang moyen + départage Borda). Le score moyen est affiché à titre indicatif.

Évaluateurs: 3

Votes gagnants

0 / 3

Score moyen

83
Voir cette réponse

Votes gagnants

3 / 3

Score moyen

90
Voir cette réponse

Résultats de l’évaluation

Modèles évaluateurs Google Gemini 2.5 Pro

Raison du gagnant

La réponse B est le vainqueur incontesté en raison de sa profondeur, de son exhaustivité et de sa nuance technique supérieures. Bien que la réponse A fournisse une conception très bonne et standard, la réponse B opère à un niveau de détail et de prévoyance plus élevé, caractéristique d'un ingénieur expérimenté. Elle aborde des considérations critiques du monde réel qu'A néglige, telles que la conception d'API, la sécurité et des plans détaillés de reprise après sinistre. Les discussions de B sur la scalabilité (par exemple, la gestion du fan-out des célébrités) et la fiabilité (par exemple, la définition d'SLO réalistes) sont plus avancées et pratiques. Ces forces dans les critères les plus pondérés - architecture, exhaustivité et scalabilité/fiabilité - en font la meilleure réponse.

Modèles évaluateurs Anthropic Claude Opus 5

Raison du gagnant

La réponse B l'emporte sur le résultat pondéré. Elle surpasse A sur la qualité de l'architecture (30 %) grâce au modèle de boîte de réception comme source de vérité, à la séparation explicite des chemins de lecture/écriture et aux sujets de commande par canal, et elle l'emporte de manière décisive sur la complétude (20 %), la scalabilité et la fiabilité (20 %), et le raisonnement sur les compromis (20 %) en ajoutant la conception de l'API, la haute disponibilité/reprise après sinistre, l'isolation des priorités, la sémantique de validation des décalages, la sécurité, l'observabilité et un recadrage critique de l'objectif de niveau de service de latence. La réponse A est clairement meilleure sur la clarté (10 %) grâce à son diagramme, ses tableaux et sa structure, mais cet unique avantage faiblement pondéré ne peut compenser la supériorité de B sur les quatre critères les plus importants.

Modèles évaluateurs OpenAI GPT-5.5

Raison du gagnant

La réponse B l'emporte car elle fournit une conception plus complète et techniquement précise selon les critères fortement pondérés. Les deux réponses proposent des architectures événementielles solides, mais B définit plus explicitement les sémantiques de livraison, les limites de défaillance, le comportement de relecture, la haute disponibilité et la reprise après sinistre, la gestion de la surcharge, le comportement de l'API, les compromis en matière de sécurité/confidentialité et de coûts. Sa discussion sur la fiabilité et la scalabilité est plus approfondie et plus ancrée sur le plan opérationnel, tout en répondant à toutes les exigences fonctionnelles.

X f L