QQ 聊天记录加载卡死:NFS 上的 44G SQLite 不是"整理数据库",是机械盘随机读延迟

【时间】2026 年 9 月 25 号下午,QQ 启动后卡死不动

~/.config/QQ 通过 bind 挂载指向 NFS(/tank/shared/QQ)。QQ 启动后界面转圈,日志里能看到主进程打开了一堆数据库文件,但就是不出聊天记录。

第一反应是:SQLite 在跑 vacuum 或者 integrity check,等一等就过去了。

坑

vmstat 1 显示 wa(IO 等待)在 20–26%,有进程阻塞。直接读 31G 的 nt_msg.db:

本机 direct read:20.6 MB/s(2G 用了 104s)
宿主侧 direct read 同文件:24.8 MB/s

两个数字几乎一样,说明瓶颈不在 NFS 网络层,而在宿主那两块 ST16000NM000J 16T 机械盘的顺序读上限。SQLite 加载聊天记录是大量随机读,在这两块盘上就是分钟级。

再看 nt_db 目录,实际 du 出来是 202G——其中 nt_data(媒体库)158G,nt_db(全部数据库)44G。媒体库留在 NFS 没问题(顺序读单文件,25MB/s 够用),卡的是 SQLite 的随机读。

修复

宿主是 PVE,tank 是 ZFS。查 ARC:

zfs_arc_max = 4294967296  # /etc/modprobe.d/zfs.conf 里人为钳到 4G
ARC 命中率:85.6%(30.6M hits / 5.2M misses)

4G ARC 装 44G 数据库的热工作集,只能覆盖一小部分。冷加载时大量块要穿透到机械盘。

改动(免重启):

# 持久化
echo "options zfs zfs_arc_max=17179869184" >> /etc/modprobe.d/zfs.conf
# 即时生效
echo 17179869184 | sudo tee /sys/module/zfs/parameters/zfs_arc_max

改完验证 ARC 开始增长:4G → 6.9G,上限 16G,会随 IO 逐步填满。

经验

  1. vmstat wa 高不代表数据库在整理,先测 direct read 速度区分“网络瓶颈”还是“磁盘瓶颈”。
  2. PVE 宿主上的 ZFS ARC 默认会被钳到 RAM 的 25% 甚至更低,查 /etc/modprobe.d/zfs.conf 里有没有 zfs_arc_max。
  3. 媒体库(顺序读)和数据库(随机读)的 IO 模式完全不同,不能混在一起评估。媒体库放 NFS 没问题,数据库放 NFS 就卡。

🎵 Listening companion