GH GambleHub

MongoDB et schémas de données flexibles

(Section : Technologie et infrastructure)

Résumé succinct

MongoDB est un stockage orienté documents avec des schémas flexibles (BSON), des inserts rapides, une mise à l'échelle horizontale et un puissant pipeline d'aggregation. Dans iGaming, il est idéal pour les profils de joueurs, les cartes CRM flexibles, les logs d'événements, la télémétrie, les projections matérialisées à partir de strim, les catalogues de jeux et les représentations cachées pour les fronts. Pour les invariants monétaires (portefeuille/ledger), il reste plus souvent un contour SQL/CP ; MongoDB convient en tant que modèle de lecture et de stockage documentaire haute performance.

Où MongoDB donne le maximum dans iGaming

Profils et paramètres des joueurs : variables de structure (paramètres locaux, préférences, métadonnées KYC).
Catalogues de contenu/jeux/fournisseurs : lecture rapide des cartes, filtres, balisage, texte intégral.
Événements/télémétrie/journaux : TPS élevés, fenêtres temporelles, stockage TTL.
Représentations matérialisées (CQRS) : écrans rapides (leaders, actions récentes, agrégats).
Personnalisation/fiches en ligne ML : modèles KV dans les collections, court TTL.

Principes du régime flexible : la discipline au lieu du chaos

MongoDB n'est pas « sans schéma » - le schéma vit dans le code et la validation.

Recommandé :

1. Schéma comme contrat : JSON Schema Validation dans les collections.

2. Versioner les documents avec le champ 'schemaVersion'.

3. Champs obligatoires stricts (id, clés de recherche), « queue » des attributs rares - facultatif.

4. Limite la dimension et l'imbrication des tableaux (pour les index et RAM).

5. Migrations en arrière-plan : Apdates par « schemaVersion », Shedulers, back-fill.

Exemple : JSON Schema Validation

js db. createCollection("player_profiles", {
validator: {
$jsonSchema: {
bsonType: "object",
required: ["playerId", "createdAt", "schemaVersion"],
properties: {
playerId: { bsonType: "string" },
createdAt: { bsonType: "date" },
schemaVersion: { bsonType: "int", minimum: 1 },
locale: { bsonType: "string" },
kyc: {
bsonType: "object",
properties: {
status: { enum: ["pending", "verified", "rejected"] },
doc: { bsonType: "object" }
}
}
}
}
}
});

Modèle de données et conception de documents

Concevoir « à la demande » : 1 écran/endpoint = 1 document ou un petit ensemble de documents.
Dénormalisation : incluez les petits sous-papiers imbriqués (par exemple, les mini-cartes des fournisseurs de jeux).

Liens d'intégration vs :
  • Intégration - pour les tranches étroitement liées et rarement mises à jour.
  • Les références ('ref') sont à grande taille/fréquentes updates/réutilisation.
  • Limite de taille : Document ≤ 16 Mo ; les grands binaires sont GridFS/objets de stockage.
  • Audit/métadonnées : 'createdAt', 'updatedAt', 'traceId', 'tenantId', 'idempotencyKey'.

Indices : qualité de lecture et stabilité de latitude

Types d'indices et de pratiques :
  • B-Tree (principal)

Composer : l'ordre des champs correspond à des prédicats et des triages fréquents.
Règle prefix : Les options préfixées fonctionnent pour '(tenantId, playerId, createdAt)'.
Trier : tenez compte de 'sort' à la fin de l'index (par exemple, 'createdAt : -1').

js db. bets. createIndex(
{ tenantId: 1, playerId: 1, createdAt: -1 },
{ name: "idx_bets_tenant_player_created_desc" }
);

Partial / Sparse

Accélérer les sous-ensembles fréquents ('status : « pending »), réduire la taille.

js db. withdrawals. createIndex(
{ playerId: 1, createdAt: -1 },
{ partialFilterExpression: { status: "pending" } }
);

TTL

Pour la télémétrie/logs/fiches temporelles, l'expiration automatique.

js db. events. createIndex({ expireAt: 1 }, { expireAfterSeconds: 0 });

Texte/autocoplete

'text' pour le texte intégral (restrictions linguistiques) ; pour le remplissage automatique - 'n-gram '/trigram à travers les champs et les approches regex ou Atlas Search.

Antécédents d'index

L'indice « pour tout » → la baisse de la vitesse d'enregistrement.
Faible cardinalité sans partialité → faible sélectivité.
Composites en double.
Indexer les champs à l'intérieur des masses géantes sans limites.

Aggregation Pipeline : écrans rapides et rapports

Utilisez '$ match' → '$ sort' → '$ limit' comme étapes initiales ; concevoir des index sous '$ match/$ sort'.
'$ lookup 'pour les joyaux contrôlés (doux, en volumes raisonnables).
'$ facet' pour les métriques multiples ; '$ unionWith' est une fusion de collections.
'$ merge '/' $ out' est la matérialisation des résultats dans la collection (read-models).

Exemple : derniers paris joueur + voûte :
js db. bets. aggregate([
{ $match: { tenantId: "eu-1", playerId: "p123" } },
{ $sort: { createdAt: -1 } },
{ $limit: 100 },
{ $group: {
_id: "$playerId",
lastBets: { $push: { amount: "$amount", ts: "$createdAt", game: "$gameId" } },
totalAmount: { $sum: "$amount" }
} }
]);

Transactions, cohérence et idempotence

Single-document atomic - atomicité libre ; invariants complexes - pensez à diviser par documents.
Transactions multi-documents (ACID) - il y a des réseaux de répliques, mais plus chers en latitude ; appliquer par points.

Write Concern / Read Concern:
  • « w : » majority « » pour les enregistrements critiques (coût de la latitude) ;
  • « readConcert : » majority « » pour une lecture cohérente.
  • Idempotence : clés uniques sur 'idempotencyKey '/' pspTx', opération UPSERT ('$ setOnInsert', '$ inc').
Exemple UPSERT :
js db. wallet. updateOne(
{ playerId: "p123" },
{ $inc: { balanceCents: -5000 }, $set: { updatedAt: new Date() } },
{ upsert: true, writeConcern: { w: "majority" } }
);
💡 Pour les invariants monétaires, ils préfèrent généralement SQL. Dans Mongo - seulement avec une discipline stricte des clés/idempotence et des transactions limitées.

Chardonnage et sélection de clés

MongoDB chardonne sur la clé shard. Le choix est critique :
  • Répartition de la charge : clé d'une cardinalité élevée et d'une distribution uniforme (par exemple, '(tenantId, playerId)').
  • Évitez la monotonie : 'CreatedAt'comme seule clé → boule « chaude ».
Fourchettes vs hash :
  • Hashed - distribue les enregistrements de manière plus uniforme.
  • Ranged - mieux pour les demandes de gamme, mais regardez les queues chaudes.
  • Zone de partage (tag ranges) pour la réglementation/localisation (EU/LatAm/TR).
Exemple :
js sh. enableSharding("igaming");
db. bets. createIndex({ tenantId: 1, playerId: 1, _id: "hashed" });
sh. shardCollection("igaming. bets", { tenantId: 1, playerId: 1, _id: "hashed" });
Antichambre :
  • La clé shard par faible cardinalité (« status ») est une distorsion des chards.
  • Fréquents '$ lookup' entre les collections chardonnées sans co-chardage sur une seule clé.
  • Clé shard modifiable (difficile et coûteuse à changer).

Replica-sets, lectures et politiques read-after-write

Réplique-set = HA et base de transaction.

Read Preference:
  • « primary » pour les lectures critiques ;
  • "primaryPreferred'/" secondaire" - pour les analystes/non critiques.
  • Lisez/Écrivez dernier accord avec SLO et le budget de latitude.

Modification des flux, CDC et intégration

Change Streams : Abonnement insertion/update/suppression - pratique pour :
  • Synchronisation des couches cache (Redis),
  • déclencheurs CRM/notifications,
  • téléchargements en OLAP (ClickHouse/Pinot),
  • écrans à réaction.
  • Modèle Outbox : pour les domaines critiques, publiez les événements dans une collection distincte, qui est ensuite lue par le connecteur et diffusée sur le bus (Kafka). Cela améliore la prévisibilité des intégrations.

Observabilité et SLO

SLO : p99 cartes de lecture ≤ 10-20 ms ; insertion d'événements ≤ 20-40 ms ; La différence de leitensi entre les chardes dans X %; disponibilité ≥ 99. 9%.
Métriques : op-latence, queue depth, % de yumps par statistiques secondaires, cache/WT, page fautes, lock-waits, kol dans les curseurs/connexions ouverts.
Profilage : 'system. profile ',' explain (« executionStats ») ', verrouillage des collections/index.
Alert : croissance de WT cache pressure, opérations lentes, croissance des requêtes qui ne sont pas entrées dans l'indice, retard des migrations secondaires, chunk/balancier.

Performances et tuning

WiredTiger Cache : par défaut, ~ 50 % RAM - validez sous le profil.
Compression : snappy/zstd pour les collections, zstd pour les magazines - équilibre CPU/IO.
Inserts Batch et bulkWrite pour la télémétrie.
Projection ('{field : 1}') pour ne pas traîner de documents « épais ».
Limit/Skip : évitez les grands 'skip' → utilisez la pagination par curseur/par marqueur ('createdAt/_ id').
Collections cappées pour les loges « anneaux ».

Sécurité et conformité

Auth/RBAC : rôles sur les collections/OBD, privilèges minimes nécessaires.
TLS en transit, cryptage sur disque (FLE/at-rest).
Politiques PII : masquage/pseudonymisation, collections séparées pour les champs sensibles.
Multi-tenance : préfixes/bases de données/collections individuelles, filtres par 'tenantId', vous pouvez des couches RLS similaires dans l'application.
Vérification : inclure une vérification des opérations sur les collections critiques.

Backups, PITR et DR

Snapshots (snapshots) volumes + oplog-backaps pour Point-in-Time Recovery.
Replica set dans une autre région pour DR ; exercices réguliers de reconstruction.
Contrôle de la croissance oplog sous les pics d'insertion (PSP webhooks/tournois).
Les clusters shard sont des backups cohérents avec le serveur bou.

Intégration avec le reste de l'architecture

CQRS : les commandes frappent SQL (argent), les événements → Materialized Views dans MongoDB.
Event-Streaming : Kafka/Pulsar comme pneu, Mongo - sink/source via connecteurs et Change Streams.
Redis : à côté d'une couche de latence ultra-basse (caches/compteurs).
OLAP : déchargement à ClickHouse/Pinot pour les scans longs et BI.

Chèque d'implémentation

1. Fixez les domaines : ce qui se passe dans Mongo (flexible/haute TPS/projection), ce qui reste dans SQL.
2. Définissez schema contracts : JSON Schema Validation, 'schemaVersion'.
3. Concevoir des index pour les demandes réelles ; ajoutez un TTL pour les données « bruyantes ».
4. Choisissez la clé de shard (cardinalité élevée, uniformité) ; si nécessaire, zone-charding.
5. Personnalisez le jeu de répliques, Read/Write Concert sous SLO ; la politique de read-after-write.
6. Inclure l'observation et le profilage, les alertes par index/WT cache/oplog.
7. Organisez des backups + PITR, un cluster DR et des exercices réguliers.
8. Connectez Change Streams/Outbox pour synchroniser les caches et les bus.
9. Limitez la taille et l'imbrication des documents ; introduire la pagination sur le curseur.
10. Politiques distinctes pour les IPI/tenants, cryptage, audit.

Anti-modèles

« Pas de schéma » dans la vente : l'absence de validation et de versions → chaos.
La clé shard dans le temps/monotone est une boule chaude et une p99 instable.
Joynes '$ lookup' sur d'énormes ensembles sans index/pagination.
Utiliser les transactions partout - perte de productivité.
L'absence de TTL/rétroaction pour les loges → une augmentation du volume et du coût.
Stocker des invariants monétaires critiques uniquement dans Mongo sans impotence stricte.

Résultats

MongoDB est un outil puissant pour les domaines flexibles iGaming : profils, catalogues, télémétrie, projections et personnalisation. La clé du succès est le schéma-contrat et la validation, l'indexation réfléchie, la clé bien choisie, Read/Write Concert, Change Streams pour les intégrations et la discipline opérationnelle rigoureuse (observabilité, backups, DR). Combiné avec le noyau SQL et le bus de streaming, cela donne à la plate-forme des interfaces rapides et résistantes aux pics de tournoi.

Contact

Prendre contact

Contactez-nous pour toute question ou demande d’assistance.Nous sommes toujours prêts à vous aider !

Commencer l’intégration

L’Email est obligatoire. Telegram ou WhatsApp — optionnels.

Votre nom optionnel
Email optionnel
Objet optionnel
Message optionnel
Telegram optionnel
@
Si vous indiquez Telegram — nous vous répondrons aussi là-bas.
WhatsApp optionnel
Format : +code pays et numéro (ex. +33XXXXXXXXX).

En cliquant sur ce bouton, vous acceptez le traitement de vos données.