MongoDB y esquemas de datos flexibles
(Sección: Tecnologías e Infraestructura)
Resumen breve
MongoDB es un almacenamiento orientado a documentos con circuitos flexibles (BSON), inserciones rápidas, escalado horizontal y potente Aggregation Pipeline. En iGaming, es ideal para perfiles de jugadores, tarjetas CRM flexibles, registros de eventos, telemetría, proyecciones materializadas de streaming, catálogos de juegos y representaciones en caché para frentes. Para invariantes monetarios (monederos/ledger), el circuito SQL/CP permanece con mayor frecuencia; MongoDB es adecuado como modelo de lectura y almacenamiento de documentos de alto rendimiento.
Donde MongoDB da el máximo en iGaming
Perfiles y ajustes de los jugadores: variables de estructura (configuración local, preferencias, metadatos KYC).
Catálogos de contenido/juegos/proveedores: lectura rápida de tarjetas, filtros, teging, texto completo.
Eventos/telemetría/registros: TPS alto, ventanas temporales, almacenamiento TTL.
Representaciones materializadas (CQRS): pantallas rápidas (tablas de liderazgo, últimas acciones, agregados).
Personalización/fichas en línea ML: patrones KV en colecciones, TTL corto.
Principios de un esquema flexible: disciplina en lugar de caos
MongoDB no es «sin esquema» - el esquema vive en código y validación.
Se recomienda:1. Esquema como contrato: JSON Schema Validation en colecciones.
2. Versionar documentos con el campo 'schemaVersion'.
3. Campos obligatorios estrictos (id, claves de búsqueda), «cola» de atributos raros - opcional.
4. Limitación de la dimensión de matrices y anidamiento (para índices y RAM).
5. Migraciones en el fondo: apdates por 'schemaVersion', shedulers, back-files.
Ejemplo: Validación de JSON Schema
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" }
}
}
}
}
}
});
Modelo de datos y diseño de documentos
Diseño «bajo petición»: 1 pantalla/endpoint = 1 documento o pequeño conjunto de documentos.
Denormalización: incluye pequeños subdocumentos anidados (por ejemplo, mini tarjetas de proveedores de juegos).
- Incrustación: para fragmentos estrechamente relacionados y raramente actualizados.
- Referencias ('ref'): con un tamaño grande/update frecuente/reutilización.
- Límite de tamaño: documento ≤ 16 MB; binarios grandes - GridFS/almacenamiento de objetos.
- Auditoría/metadatos: 'createdAt', 'updatedAt', 'traceId', 'tenantId', 'idempotencyKey'.
Índices: calidad de lectura y estabilidad latency
Tipos de índices y prácticas:- B-Tree (principal)
Compound: el orden de los campos corresponde a predicados y ordenamientos frecuentes.
Regla Prefix: para '(tenantId, playerId, createdAt)' las opciones prefijadas funcionan.
Ordenar: tenga en cuenta 'sort' al final del índice (por ejemplo, 'createdAt: -1').
js db.bets.createIndex(
{ tenantId: 1, playerId: 1, createdAt: -1 },
{ name: "idx_bets_tenant_player_created_desc" }
);
Partial / Sparse
Aceleran los subconjuntos frecuentes ('status: «pending»), reducen el tamaño.
js db.withdrawals.createIndex(
{ playerId: 1, createdAt: -1 },
{ partialFilterExpression: { status: "pending" } }
);
TTL
Para telemetría/registros/fichas temporales, caducidad automática.
js db.events.createIndex({ expireAt: 1 }, { expireAfterSeconds: 0 });
Texto/autocomplete
'text' para texto completo (restricciones por idioma); para autocompletar - 'n-gram '/trigram a través de campos y acercamientos regex o Atlas Search.
Antipatters de índices
Índice «para todo» → caída de la velocidad de grabación.
Baja cardinalidad sin parcial → baja selectividad.
Compounds duplicados.
Indexar campos dentro de matrices gigantes sin límites.
Aggregation Pipeline: pantallas rápidas e informes
Use '$ match' → '$ sort' → '$ limit' como etapas iniciales; diseñar índices bajo '$ match/$ sort'.
'$ lookup' para joynas controladas (blandas, en volúmenes razonables).
'$ facet' para métricas múltiples; '$ unionWith' es una combinación de colecciones.
'$ merge '/' $ out' - materialización de resultados en la colección (read-models).
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" }
} }
]);
Transacciones, consistencia e idempotencia
Solo-documento atómico - atomicidad libre; invariantes complejos - pensar en dividir por documentos.
Multi-document transactions (ACID): hay con redes de réplica, pero más caras por latencia; aplicar puntualmente.
- 'w: «majority»' para registros críticos (costo latency);
- 'readConcern:' majority 'para una lectura coherente.
- Idempotencia: claves únicas en 'idempotencyKey '/' pspTx', operaciones UPSERT ('$ setOnInsert', '$ inc').
js db.wallet.updateOne(
{ playerId: "p123" },
{ $inc: { balanceCents: -5000 }, $set: { updatedAt: new Date() } },
{ upsert: true, writeConcern: { w: "majority" } }
);
Charding y selección de claves
MongoDB chardea en shard key. La selección es crítica:- Distribución de carga: clave de alta cardinalidad y distribución uniforme (por ejemplo, '(tenantId, playerId)').
- Evite la monotonía: 'createdAt' como única clave → «hot» shard.
- Hashed - Distribuye los registros de manera más uniforme.
- Ranged - mejor para consultas de rango, pero cuidado con las colas calientes.
- Zona de charding (tag ranges) para la regulación/localización (EU/LatAm/TR).
js sh.enableSharding("igaming");
db.bets.createIndex({ tenantId: 1, playerId: 1, _id: "hashed" });
sh.shardCollection("igaming.bets", { tenantId: 1, playerId: 1, _id: "hashed" });
Antipattern:
- La clave de shard en la cardinalidad baja ('status') es el sesgo de los shards.
- Frecuente '$ lookup' entre colecciones chardeadas sin codificar una clave cada una.
- Shard key cambiable (cambiar es difícil y caro).
Réplicas, lecturas y políticas read-after-write
Replica-set = HA y la base de las transacciones.
Read Preference:- 'primary' para los críticos read-after-write;
- 'primaryPreferred '/' secondary' - para análisis/no crítico.
- Read/Write concern con SLO y el presupuesto latency.
Cambiar las líneas, los CDC y la integración
Change Streams: suscripción a inserciones/apdates/desinstalaciones - conveniente para:- sincronización de capas de caché (Redis),
- activadores de CRM/notificaciones,
- descargas en OLAP (ClickHouse/Pinot),
- pantallas reactivas.
- Patrón de outbox: para dominios críticos, publique los eventos en una colección separada, que luego el conector lee y transmite en un bus (Kafka). Esto aumenta la previsibilidad de las integraciones.
Observabilidad y SLO
SLO: p99 lectura de tarjetas ≤ 10-20 ms; insertar eventos ≤ 20-40 ms; la diferencia de leitensi entre los chardos dentro de X%; disponibilidad ≥ 99. 9%.
Métricas: op-latencia, queue depth,% yumps por secundarias, estadísticas cache/WT, page faults, lock-waits, cole-in de cursores/conexiones abiertas.
Perfilando: 'system. perfil ',' explain («executionStats») ', bloqueos de colecciones/índices.
Alertas: crecimiento de WT cache pressure, operaciones lentas, crecimiento de solicitudes que no cayeron en el índice, rezago secundario, chunk migrations/balancer.
Rendimiento y afinación
Caché WiredTiger: por defecto ~ 50% RAM - validar en el perfil.
Compression: snappy/zstd para colecciones, zstd para revistas - balance CPU/IO.
Inserciones de batch y bulkWrite para telemetría.
Projection ('{campo: 1}') para no arrastrar documentos «gruesos».
Limit/Skip: evite los 'skip' grandes → utilice la paginación por cursor/marcador ('createdAt/_ id').
Capped colecciones para «anillos» registros.
Seguridad y cumplimiento
Auth/RBAC: roles en la colección/DB, privilegios mínimos necesarios.
TLS en tránsito, cifrado en disco (FLE/at-nat).
Políticas PII: enmascaramiento/pseudonimización, colecciones separadas para campos sensibles.
Multi-tenencia: prefijos/BD/colecciones individuales, filtros por 'tenantId', puede RLS capas similares en la aplicación.
Auditoría: habilite la auditoría de operaciones en colecciones críticas.
Backups, PITR y DR
Instantáneas (snapshots) de volúmenes + respaldo de oplog para recuperación de puntos en tiempo.
Replica-set en otra región para DR; ejercicios regulares de recuperación.
Control de crecimiento de oplog bajo picos de inserción (PSP webhooks/torneos).
En clústeres shard, los backups consistentes con el servidor config.
Integración con el resto de la arquitectura
CQRS: los equipos golpean SQL (dinero), eventos → Vistas materializadas en MongoDB.
Event-Streaming: Kafka/Pulsar como bus, Mongo - sink/source a través de conectores y Change Streams.
Redis: cerca como una capa de latencia ultra baja (cachés/contadores).
OLAP: descarga en ClickHouse/Pinot para escaneos largos y BI.
Lista de comprobación de implementación
1. Fije los dominios: lo que va a Mongo (TPS flexible/alto/proyección) que permanece en SQL.
2. Defina schema contracts: JSON Schema Validation, 'schemaVersion'.
3. Diseñar índices para consultas reales; agregue TTL para datos «ruidosos».
4. Seleccione shard key (alta cardinalidad, uniformidad); si es necesario - zone-charding.
5. Configure la réplica-set, Read/Write Concern bajo SLO; política read-after-write.
6. Incluya la observabilidad y el perfilado, alertas en índices/WT cache/oplog.
7. Organiza backups + PITR, DR-cluster y ejercicios regulares.
8. Conecte Change Streams/Outbox para sincronizar cachés y buses.
9. Limite el tamaño de los documentos y los datos adjuntos; introduzca la paginación por el cursor.
10. Políticas separadas para PII/tenantes, cifrado, auditoría.
antipatterny
«Sin esquema» en venta: falta de validación y versiones → caos.
Llave de Shard en el tiempo/monótona - shard caliente y p99 inestable.
Joynes '$ lookup' en conjuntos enormes sin índices/paginación.
Utilizar transacciones en todas partes: pérdidas de rendimiento.
La ausencia de TTL/retención para los registros → un aumento de volumen y costo.
Almacenar invariantes monetarios críticos sólo en Mongo sin una idempotencia estricta.
Resultados
MongoDB es una poderosa herramienta para dominios flexibles de iGaming: perfiles, catálogos, telemetría, proyecciones y personalización. La clave del éxito son los esquemas-contratos y la validación, la indexación elaborada, la clave de shard bien escogida, el Concern de Lectura/Escritura, las Cadenas de Cambio para integraciones y la disciplina de operación rígida (observabilidad, backups, DR). Combinado con el núcleo SQL y el bus de streaming, da a la plataforma interfaces rápidas y resiliencia a los picos del torneo.