游戏卡顿白皮书 › L12 数据库
登录激增与 N+1 查询 Login storm, N+1 queries
原因 ID db-login-storm · 主责 研发团队·服务器开发 · 配合 运维团队·数据库运维
在含图示和实验的完整版中打开此卡片 →
加载一个角色要分别查询几十次时,数万人同时登录就会变成几百万条查询。
起因 加载角色时分别查询物品、技能、任务 → 结果 维护结束后大量玩家同时登录,查询激增 → 画面表现 登录时无限加载,正在游戏的玩家存盘也被拖慢
- 症状
- 连不上/无限加载, 操作延迟
- 因素
- 停顿, 延迟
- 谁会遇到
- 全服
- 何时出现
- 刚登录/维护结束后
- 负责方
- 主责 研发团队·服务器开发 · 配合 运维团队·数据库运维
- 研发团队要做的事
- 合并成一次查询,登录排队,缓存,检查 ORM 懒加载产生的查询次数。
- 运维团队要做的事
- 统计调用次数最多的查询排名并共享,监控维护结束后登录时段的查询数和连接数。
- 监控图上
- 开服/维护后激增 · DB 每秒查询数、登录数
- 查看位置
- 把维护结束后的登录数与 DB 每秒查询数(MySQL 看 Questions 的增量)叠加对照,算出每次登录的查询数。调用次数靠前的查询,MySQL 用 events_statements_summary_by_digest 的 COUNT_STAR,PostgreSQL 用 pg_stat_statements 的 calls 统计
- 确认依据
- 每次登录有几十条查询,排名靠前的是按单个角色 ID 查询的同类短查询。版本更新后每次登录的查询数增加,就从那次更新查起
- 排除依据
- 每次登录的查询数不多、但每条查询都慢,看“冷缓存(刚重启时)”(db-cold-cache)或“缺少索引的查询”(db-no-index)
- 确认手段
- 运维工具即可确认(无需游戏代码)
- 深入了解
- ORM(代替开发者生成 DB 查询的库)的懒加载,会在开发者不知情的情况下产生这类查询。开发服上只有几个角色,看不出来,到线上大量玩家同时登录时才第一次暴露。
出处
- Efficient Querying .NET
ORM 的懒加载会造成每个条目都多发一次查询的 N+1 问题,严重拖累性能;建议一次性批量加载(eager loading) - pg_stat_statements — track statistics of SQL planning and execution PostgreSQL
汇总每条语句的执行次数(calls)和总执行时间,得出调用最多的查询排名 - Performance Schema Statement Digests and Sampling MySQL
用 events_statements_summary_by_digest 把同类查询归并,统计次数和时间 - Statement Summary Tables MySQL
汇总表的 COUNT_STAR(执行次数)、SUM_TIMER_WAIT(总时间) - Server Status Variables MySQL
Questions:客户端发送的语句数
相关原因
同一层:L12 数据库
其他层中同样导致“连不上/无限加载”的原因
查看含图示和实验的原卡片