한국어English日本語简体中文繁體中文DeutschไทยTiếng ViệtРусскийPortuguês (Brasil)EspañolBahasa Indonesia

游戏卡顿白皮书 › L11 磁盘

同步写日志 Synchronous logging

原因 ID dk-sync-log · 主责 研发团队·服务器开发 · 配合 运维团队·系统运维

在含图示和实验的完整版中打开此卡片 →

游戏线程每写一行日志都要等磁盘完成,磁盘一忙,游戏逻辑也跟着停住。

起因 在游戏线程里直接把战斗、交易日志写入文件 → 结果 要求确保落盘(fsync),或 OS 的写缓冲(页缓存)达到上限时,磁盘一忙,一次写入就要几十 ms → 画面表现 日志多的战斗中顿一下

症状
一卡一卡, 卡住
因素
停顿
谁会遇到
特定地点/分线, 全服
何时出现
人多的时候
负责方
主责 研发团队·服务器开发 · 配合 运维团队·系统运维
研发团队要做的事
异步日志(内存缓冲 + 独立线程),减少日志量,不在游戏线程里调用 fsync。
运维团队要做的事
日志轮转和压缩以较低的 I/O 优先级运行,日志与数据放在不同磁盘,监控磁盘写入延迟。
监控图上
偶发随机尖峰 · 服务器 tick 耗时、磁盘写入延迟
查看位置
把 iostat -x 1 的 w_await、aqu-sz 与 tick 耗时叠加对照,用 perf trace -p PID --duration 10 找出游戏服务器中耗时超过 10 ms 的 write、fsync 调用及其所在线程
确认依据
tick 冲高的时刻,游戏线程的 write、fsync 调用耗时几十 ms,同时磁盘写入延迟也飙升。常与日志轮转、压缩的时间重合
排除依据
游戏线程中没有耗时长的系统调用而 tick 仍冲高,是 GC、锁、tick 超出预算等其他原因。只有日志专用线程耗时长,则不影响游戏逻辑
确认手段
运维工具即可确认(无需游戏代码)
深入了解
OS 通常先把写入的数据放进内存(页缓存),稍后再刷到磁盘,所以写一行日志一般会立即完成。停顿出现在这几种时候:用 fsync 要求确保落盘时;积压的写入超过上限、OS 阻塞写调用时;轮转或压缩日志文件时。所以平时一切正常,只在磁盘繁忙的瞬间冲高。

出处

  1. fsync(2) — Linux manual page Linux man-pages
    fsync 把修改过的数据刷到磁盘(包括磁盘缓存),并阻塞到设备报告完成
  2. Documentation for /proc/sys/vm/ Linux kernel
    积压的写入(dirty)达到 dirty_ratio 时,执行写入的进程要亲自承担刷盘工作
  3. ionice(1) — Linux manual page util-linux
    以 idle I/O 优先级运行的任务,只在其他程序不使用磁盘时才分到磁盘时间
  4. iostat(1) — Linux manual page sysstat
    -x:w_await(写请求的平均处理时间,包括在队列中等待的时间),aqu-sz(平均队列长度,旧名 avgqu-sz)
  5. perf-trace(1) — Linux manual page perf
    -p 跟踪运行中进程的系统调用,--duration 只显示耗时超过指定 ms 的调用

相关原因

同一层:L11 磁盘

其他层中同样导致“一卡一卡”的原因

查看含图示和实验的原卡片