尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

mongodb面试题

mongodb面试题 第1题​在游戏后端中为什么很多团队选择用 MongoDB 来存储玩家存档如背包、技能、任务进度请从数据模型和开发效率两个角度说明。因为mongoDB是文档型数据库存储单位是文档其不需要结构化文档结构随时可以添加新的字段对于大部分团队来说使用灵活维护相比mysql简单。第2题​MongoDB 的文档模型相比 MySQL 的关系模型在处理玩家背包这种频繁变动的数据结构时有什么优势举个例子。数据模型更贴合业务逻辑​玩家背包天然是一个嵌套结构一个玩家有多个装备每件装备有属性、强化等级、宝石槽位等。MongoDB直接用一条文档表示整个背包结构清晰代码与数据一一对应。{playerId:10001,bag:[{itemId:101,name:屠龙刀,attack:500,level:10,gems:[{type:红宝石,attr:攻击50}]},{itemId:102,name:玄铁甲,defense:300,level:8}]}MySQL需要拆成多张表player_bag玩家背包主表、equipment装备表、gem宝石表查询时要用 3 次 JOIN 才能拼回完整的背包数据。查询性能更高减少 IO 次数​MongoDB玩家登录时一次查询就能把整个背包数据拉回来只需一次磁盘 IO。MySQL需要多次 JOIN可能涉及 3~5 次 IO在高并发场景下比如万人同时登录差距非常明显。开发迭代更灵活​游戏版本迭代频繁经常要往背包里加新字段比如新增“洗炼属性”、“套装效果”。MongoDB直接在文档中加字段即可无需修改表结构不影响线上服务。MySQL需要执行 ALTER TABLE 加列大表下可能锁表导致线上抖动而且需要同步修改所有关联表的 schema。维护成本更低​MongoDB一个集合管理所有背包数据没有外键约束没有复杂的表关联逻辑。MySQL需要维护多张表的外键关系、事务一致性每次需求变更都要改表结构开发和 DBA 的工作量都更大。第3题​如果一个玩家拥有多个装备每件装备又有不同的属性攻击力、耐久度、镶嵌宝石等你会怎么设计 MongoDB 中的文档结构嵌套还是引用为什么我会设计为嵌套这样在一个集合中就可以完成属性的调整如果使用引用每次查询装备都需要再查询引用所指的集合从而加载数据那么效率会低且存储时失败带来的影响更大可能存在引用存储了但是引用指向的表存储失败导致数据没有正常落地。第4题​MongoDB 的 _id 字段是如何生成的它在分布式游戏服务器中有什么好处每个文档生成时mongodb自动生成的_id表示唯一的文档表示。他在分布式游戏服务器中天然满足唯一不需要担心不同的服务器存在相同_id的记录。第5题​你在游戏项目中如何为 MongoDB 建索引请举例说明哪些字段适合建索引哪些不适合为什么联合索引的顺序很重要在游戏项目中我会为高频查询或影响玩家体验的字段建立索引使用 createIndex() 方法。索引类型包括唯一索引、联合索引等。例如玩家登录时需要根据 playerId 快速查询我会给玩家集合的 playerId 字段建索引。但注意不建议用 UUID 作为索引字段因为 UUID 是随机字符串插入时会导致 B 树页分裂频繁写入性能下降。更优的做法是使用自增整数或雪花算法生成的 ID保证插入有序减少索引维护开销。对于支付场景我会对订单号和支付 ID 建立联合索引因为经常按这两个字段组合查询。联合索引的设计遵循最左前缀原则等值条件字段放前面范围/排序字段放后面。我还关注覆盖索引的运用。如果查询只需要返回索引中已有的字段就不需要回表查文档性能更高。比如玩家登录时只查 playerId 和 nickname可以建联合索引 (playerId, nickname)查询直接从索引返回结果避免一次文档读取。第6题​游戏中有个功能查询全服排名前100的玩家按战力降序。请写出 MongoDB 的聚合查询语句使用 aggregate。db.players.aggregate([{$sort:{power:-1}},// 按战力降序排序{$limit:100},// 取前100条{$project:{// 只返回需要的字段隐藏不必要的信息_id:0,playerId:1,name:1,power:1}}])第7题​MongoDB 的聚合管道中match和group 的执行顺序对性能有什么影响实际开发中你应该怎么安排它们$match 应尽量放在 $group 之前提前过滤可以减少后续阶段处理的数据量大幅提升聚合管道的性能。这是 MongoDB 聚合优化的黄金法则之一。第8题​游戏上线后玩家数据量暴增MongoDB 写入变慢。你会怎么排查和优化列举至少三种方法。检查慢查询日志​开启 profiling找出耗时长的写入操作。常见原因没有索引的全表扫描COLLSCAN导致的写锁竞争。查看索引使用情况​用 explain() 分析写入前的查询是否走了索引。如果频繁的更新操作需要先查找文档却没有索引就会拖慢写入。比如按 playerId 更新背包务必给 playerId 建索引。检查磁盘 I/O 和内存​MongoDB 依赖内存和磁盘。如果物理内存不足大量数据被换出写入时频繁刷盘性能会急剧下降。可以通过 mongostat 和 iostat 观察 page fault 和磁盘利用率。确认是否存在写锁争用​MongoDB 3.x 之前是库级锁4.0 改为文档级锁。但如果某个集合的写入热点过于集中比如所有玩家同时更新全局排行榜仍可能造成锁等待。可以考虑拆分集合或改用批量写入。评估是否需要分片​如果上述优化都做了单机写入仍然无法满足增长才考虑分片。分片前要选好分片键避免出现“写热点”比如按时间戳分片可能导致数据倾斜。分片后还需要调整 chunk 均衡策略。硬件与配置层面​增加内存让工作集hot data尽可能驻留内存使用 SSD 替代 HDD调整 write concern比如从 majority 降为 acknowledged但需权衡数据安全性第9题​什么是 MongoDB 的副本集在游戏后端中副本集解决了什么问题读写分离怎么配置副本集是 MongoDB 的高可用方案由一个主节点和多个从节点组成。主节点负责写从节点同步数据并在主节点故障时自动接管。在游戏后端中它解决了单点故障和数据备份问题同时通过读写分离提升性能。配置读写分离很简单在查询时设置 readPref(‘secondary’) 即可但需要注意从节点可能有秒级延迟关键数据读主节点。第10题​如果你的游戏需要跨区服例如国服、美服共享部分数据如全球排行榜你会怎么设计 MongoDB 的分片集群分片键怎么选为什么“全球排行榜是一个典型的‘写多读多、热点集中’的场景。直接对 MongoDB 做分片会遇到两难按分数分片会有写热点按玩家 ID 哈希分片则排行榜查询性能差。我的设计方案是 分层架构实时排行榜​ 交给 Redis 的 Sorted Set利用其 ZREVRANGE 直接获取 TOP N毫秒级响应。MongoDB 做全量持久化存储每个玩家的历史积分和详细记录。这里使用 hashed(playerId) 作为分片键确保写入均匀分布在所有分片上避免写热点。定期同步后台定时任务将 Redis 的排行榜快照写入 MongoDB 的一个专门集合比如 rank_snapshots供历史分析和回滚使用。第11题​MongoDB 4.0 开始支持多文档事务。但在游戏场景中官方建议尽量少用事务。你能说说原因吗并举例说明如何通过文档设计避免事务需求。第12题​玩家同时在线数很高MongoDB 的连接数可能会被耗尽。你怎么处理这个问题常见的解决方案有哪些连接池管理最基础​使用 MongoDB 驱动自带的连接池配置合理的参数最小连接数保证始终有一定数量的连接可用避免突发请求时临时创建。最大连接数根据服务器内存和 MongoDB 的 maxIncomingConnections 设置上限一般建议 500~1000。空闲连接超时及时回收长时间不用的连接释放资源。等待队列当连接池满时请求排队等待而不是立即报错。批量操作减少连接占用时间​不要在循环中逐条执行 insert/update而是用 bulkWrite() 或 insertMany() 一次性提交多条数据。例如每 100ms 或每积累 1000 条日志才写入一次大幅减少连接占用时长。引入消息队列做异步写入进阶方案​在应用层和 MongoDB 之间加一层消息队列如 Kafka 或 RabbitMQ玩家数据先写入队列再由消费者批量写入 MongoDB。好处削峰填谷即使瞬时流量暴涨也不会打爆数据库连接。代价数据写入有短暂延迟秒级但对日志、行为埋点等非实时场景完全可接受。检查是否存在连接泄漏​排查代码中是否有忘记关闭游标cursor或未释放连接的情况。用 db.serverStatus().connections 监控连接数变化趋势。操作系统层面调优​Linux 系统默认的文件句柄限制可能只有 1024需要调高 ulimit -n否则 MongoDB 无法创建更多连接。第13题​有一个游戏日志集合每天产生几亿条记录。你需要按玩家ID和时间范围快速查询。你会怎么设计索引和分片如果数据需要定期归档怎么做我会创建一个联合索引playeridtimestamp这样通过playerid快速收缩查询范围然后根据timestamp进行范围查询这样查询效率相对较好。由于每天产生几亿条记录单片的写压力非常大而游戏日志一般都是玩家查看自己的那么分片键就可以使用playerid这样可以将日志均衡的分布在不同的分片。代价全服时间范围查询需要扫描所有分片但这类查询频率低可以接受。由于每天几亿条记录不可能永久保留。我会采用分层策略短期数据最近7天留在主分片集群使用 TTL 索引自动删除超过7天的文档。中期数据7天3个月通过后台定时任务如每天凌晨将过期数据迁移到另一个 MongoDB 集群配置较低的机器或云上的低成本实例。长期数据3个月以上压缩后导出到对象存储如 AWS S3 或腾讯云 COS只保留索引文件供审计查询。迁移工具可以使用 MongoDB 的 mongodump mongorestore或者写一个脚本用 change stream 监听增量数据并同步到归档库。
返回列表