MongoDB和灵活的数据模式
(部分: 技术和基础设施)
简短的摘要
MongoDB是一种面向文档的存储,具有灵活的电路(BSON),快速插入,水平缩放和功能强大的Aggregation Pipeline。在iGaming中,它非常适合玩家配置文件、灵活CRM卡、事件日志、遥测、流中的实例化投影、游戏目录和面向前面的可压缩表示。对于现金不变量(钱包/ledger),SQL/CP回路更常见。MongoDB作为阅读模型和高性能文档存储是合适的。
其中MongoDB在iGaming中给出最大值
玩家配置文件和设置:结构变量(位置设置、首选项、KYC元数据)。
内容/游戏/提供商目录:快速读卡、过滤器、标签、全文。
事件/遥测/日志:高TPS,时间窗口,TTL存储。
实例化视图(CQRS):快速屏幕(领导板、最新动作、聚合)。
个性化/fici online ML: KV模式集合,简称TTL。
灵活方桉原则: 纪律而不是溷乱
MongoDB不是"没有方案"-方案生活在代码和验证中。
建议:1.计划作为合同:JSON计划验证。
2.通过"schemaVersion"字段对文档进行测试。
3.严格的必填字段(id,搜索键),稀有属性的"尾巴"是可选的。
4.限制阵列尺寸和嵌套值(用于索引和RAM)。
5.背景迁移:通过"schemaVersion"进行的升级,shedulers,后门。
示例: JSON计划验证
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" }
}
}
}
}
}
});
数据模型和文档设计
在提示下设计:1个屏幕/结束点=1个文档或一小组文档。
非规范化:包括小型嵌套子文件(例如游戏提供商迷你卡)。
- 嵌入-用于紧密相关且很少更新的片段。
- 链接("ref")-大尺寸/频繁升级/重用。
- 大小限制:文档≤ 16 MB;大型二进制-GridFS/对象存储。
- 审计/元数据:"createdAt","updatedAt","traceId","tenantId","idempotencyKey"。
索引: 阅读质量和稳定性
索引和实践类型:- B-Tree(主要)
Compound:字段的顺序对应于频繁的谓词和排序。
Prefix规则:对于'(tenantId, playerId, createdAt)'使用前缀选项。
排序:在索引末尾考虑"sort"(例如"createdAt: -1")。
js db.bets.createIndex(
{ tenantId: 1, playerId: 1, createdAt: -1 },
{ name: "idx_bets_tenant_player_created_desc" }
);
Partial / Sparse
加速频繁的子集("status: "pending"),减小大小。
js db.withdrawals.createIndex(
{ playerId: 1, createdAt: -1 },
{ partialFilterExpression: { status: "pending" } }
);
TTL
对于遥测/标志/时间镜头-自动到期。
js db.events.createIndex({ expireAt: 1 }, { expireAfterSeconds: 0 });
文本/自动复制
全文的"text"(语言限制);对于巡回赛-"n-gram"/trigram通过字段和regex方法或Atlas Search。
指数的反模式
所有索引→记录速度下降。
没有部分的低基数→低选择性。
复制的复合体。
在没有限制的巨型阵列中索引字段。
Aggregation Pipeline: 快速屏幕和报告
使用"$match" → "$sort" → "$limit"作为早期阶段;将索引设计为"$match/$sort"。
"$lookup"用于受控的joins(柔软,数量合理)。
多项指标的"$facet";"$unionWith"是集合的组合。
"$merge"/"$out"-实现集合中的结果(阅读模型)。
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" }
} }
]);
交易、一致性和平均性
单文档原子-免费原子性;复杂的不变式-考虑按文档划分。
多文档交易(ACID)-带有复制集,但后期价格更高;逐点应用。
Write Concern / Read Concern:
"w: 关键记录的'majority'(后期成本);
'readConcern: 'majority'用于一致阅读。
相似性:"idempotencyKey"/"pspTx",UPSERT操作("$setOnInsert","$inc")上的唯一密钥。
js db.wallet.updateOne(
{ playerId: "p123" },
{ $inc: { balanceCents: -5000 }, $set: { updatedAt: new Date() } },
{ upsert: true, writeConcern: { w: "majority" } }
);
摇摇欲坠和选择钥匙
MongoDB在硬键上摇摇欲坠。选择至关重要:- 负载分布:高基数键和均匀分布(例如"(tenantId,playerId)")。
- 避免单调:"createdAt"作为→"热"阴谋的唯一关键。
- Hashed-更均匀地分配记录。
- Ranged-适用于范围查询,但要注意热尾巴。
- 用于调节/定位(EU/LatAm/TR)的区域缓解(tag ranges)。
js sh.enableSharding("igaming");
db.bets.createIndex({ tenantId: 1, playerId: 1, _id: "hashed" });
sh.shardCollection("igaming.bets", { tenantId: 1, playerId: 1, _id: "hashed" });
反模式:
- 低基数的Shard键("状态")是Shard的偏斜。
- 在破折号的集合之间经常出现"$lookup",而无需通过一个键进行共同破解。
- 可变硬键(难以更换且昂贵)。
复制集,阅读和阅读后写入策略
复制集=HA和事务基础。
Read Preference:
关键阅读后写作的"主要";
"primaryPreferred"/"secondary"-用于分析/非关键。
Read/Write concern与SLO和latency预算保持一致。
Change Streams、CDC和集成
Change Streams:订阅插件/升级/删除-非常方便:- 缓存层同步(Redis),
- CRM/通知触发器,
- 下载到OLAP (ClickHouse/Pinot),
- 喷气屏幕。
- Outbox模式:对于关键域,将事件发布到一个单独的集合中,然后由连接器读取并广播到总线(Kafka)。这提高了积分的可预测性。
可观察性和SLO
SLO: p99读卡≤ 10-20毫秒;插入≤ 20-40毫秒;X%以内的沙丁鱼之间的亮点差;可用性≥ 99。9%.
度量标准:op-latentity, queue depth,每个次要,cache/WT统计数据的百分比,page faults, lock-waits, Kol in open游标/连接。
分析:'系统。profile","explain("executionStats")",集合/索引锁。
Alerts: WT cache pressure的增长,操作缓慢,查询不属于索引的增长,次要积压,chunk migrations/balancer。
性能和调音
WiredTiger Cache:默认情况下~ 50% RAM-验证配置文件。
Compression: snappy/zstd for Collections, zstd for Magazine-CPU/IO平衡。
用于遥测的Batch插入和bulkWrite。
投影("{field: 1}")以免拖动"厚"文档。
Limit/Skip:避免大型"skip" →使用游标/标记("createdAt /_id")分区。
为"环形"徽标捕获的集合。
安全和合规性
Auth/RBAC:集合/DB中的角色,最低要求的特权。
过境中的TLS,磁盘加密(FLE/at rest)。
PII策略:掩码/别名化,敏感字段的单独集合。
多重性:前缀/单个DB/集合,"tenantId"过滤器,可以在应用程序中使用类似RLS的层。
审核:包括对关键集合的操作审核。
Bacaps,PITR和DR
点对点恢复的+oplog备份卷快照(快照)。
DR在不同地区的复制集;定期恢复演习。
在插入峰值下控制oplog生长(PSP webhooks/锦标赛)。
在shard群集中-与config服务器一致的备份。
与体系结构的其余部分集成
CQRS:团队击败SQL(金钱),事件→ MongoDB的Materialized Views。
Event-Streaming:Kafka/Pulsar作为总线,Mongo是通过连接器和Change Streams进行的sink/source。
Redis:旁边是超低潜能层(缓存/计数器)。
OLAP:在ClickHouse/Pinot卸载长扫描和BI。
实施支票清单
1.记录域:在Mongo(灵活/高TPS/投影)中会发生什么,这保留在SQL中。
2.定义schema contracts:JSON Schema Validation,"schemaVersion"。
3.为实际查询设计索引;为"嘈杂"数据添加TTL。
4.选择硬键(高基数,均匀性);如有必要-分区。
5.在SLO下配置复制集Read/Write Concern;阅读后写入策略。
6.在/WT cache/oplog索引上启用可观察性和分析。
7.组织备用+PITR,DR集群和定期演习。
8.连接Change Streams/Outbox以同步缓存和轮胎。
9.限制文档大小和附件;通过游标引入分区。
10.PII/Tenant的单独策略,加密,审核。
反模式
"没有计划"在销售:缺乏验证和版本→溷乱。
按时间/单调键是热键和不稳定的p99。
Joins '$lookup'在没有索引/分割的巨大套装上。
无处不在地使用事务-性能损失。
缺少TTL/博客转义 →数量和成本增长。
仅在Mongo中存储关键的货币不变量,而无需严格的幂等。
三.成果
MongoDB是灵活的iGaming域的强大工具:配置文件,目录,遥测,投影和个性化。成功的关键是电路合同和验证,经过深思熟虑的索引,精心挑选的软管键,Read/Write Concern意识到,用于集成的Change Streams和严格的操作纪律(可观察性,备份,DR)。结合SQL内核和流媒体总线,这为平台提供了快速的界面和锦标赛高峰的可持续性。