正常运行 30 分钟后调用 sync/fsync 会减慢 IO

ale*_*x.p 6 linux unix ubuntu performance filesystems

使用带有 ext4混合 SSD 的Ubuntu 14.04 正常运行 30 分钟后,我看到许多进程使用 iotop 阻塞 IO。

这种减速的根本原因可以追溯到 Unix 系统调用sync

sync从终端重复运行可能需要 1 - 2 秒的时间,但仅在 30 分钟的正常运行时间之后。

为了证明这一点,我制作了一个脚本,以秒为单位输出正常运行时间与执行同步所需的时间,并每秒运行一次:

while true;
do
cat /proc/uptime | awk '{printf "%f ",$1}'; /usr/bin/time -f '%e' sync;
sleep 1;
done;
Run Code Online (Sandbox Code Playgroud)

我运行了上面的脚本,等了大约一个小时(系统处于空闲状态)并在 gnuplot 中绘制了结果(y = 执行同步的时间,x = 以秒为单位的正常运行时间):

减速图

图表上升的时间点大约是 1780(1780/60 = 大约 30 分钟)。

除了脚本,此时不应向磁盘写入任何内容,因此在第一次同步之后页面缓存中应该几乎没有任何内容,每个后续同步将准确写入正在写入脚本的内容,大约为 100 字节或所以。

当我检查cat /proc/meminfo脏行(页面缓存中的数据需要保存到磁盘?)和回写行(HD磁盘缓冲区?)都为零时。我的想法是调用会sync刷新这些磁盘缓存,但即使这些缓存中没有任何内容,它仍然会冻结,所以它会做其他事情吗?

重新启动后此问题仍然存在;例如 - 如果我等待 30 分钟减速然后重新启动,减速仍然存在。如果我关闭电源然后重新启动问题会消失,直到 30 分钟后。

另一个好奇心是,当我检查上图并放大正在发生减速的区域时,我得到了这个:

减速图放大

波峰和波谷重复——这在波谷与波谷之间以 10 秒的间隔发生。

在减速之前,我还运行了 hdparm 测试(hdparm -t /dev/sdahdparm -T /dev/sda):

/dev/sda:
Timing cached reads:   23778 MB in  2.00 seconds = 11900.64 MB/sec
/dev/sda:
Timing buffered disk reads: 318 MB in  3.01 seconds = 105.63 MB/sec
Run Code Online (Sandbox Code Playgroud)

在放缓期间:

/dev/sda:
 Timing cached reads:     2 MB in  2.24 seconds = 915.50 kB/sec
/dev/sda:
Timing buffered disk reads: 300 MB in  3.01 seconds =  99.54 MB/sec
Run Code Online (Sandbox Code Playgroud)

显示实际磁盘读取没有受到影响,但缓存读取受到影响,这是否意味着这与系统总线有关,而与 HD 无关?

这是我尝试过的解决方案:

  • 更改 HD 的降速设置(也许 HD 正在进入省电模式?):

    hdparm /dev/sda -S252 #(set it to 5 hours before spindown)
    
    Run Code Online (Sandbox Code Playgroud)
  • 将文件系统的日志类型更改为回写而不是有序,以便我们获得性能改进 - 这并不能解决问题,因为它没有解释当我尝试这样做时 30 分钟无减速正常运行时间没有变化。

  • 禁用 CRON,因为它似乎在 30 分钟后发生。

  • CPU 使用率很好并且完全空闲,因此不能责怪任何进程,但是我尝试关闭包括会话管理器 (lightdm) 在内的所有服务,这没有任何作用,因为我认为问题级别较低。

  • 分析 30 分钟后进入的任何新进程表明没有任何变化 - 我前后对比了 PS 的输出,没有区别。

这仅在大约 2 周前开始发生,当时没有安装任何内容,也没有进行任何更新。我认为这个问题的级别要低得多,所以我真的很感激这里的一些帮助,因为我一无所知,即使将我指向正确的方向也会有所帮助。

有问题的磁盘上启用了写缓存,我也尝试过禁用写屏障。HD 上的 SMART 数据表明 HD 本身没有问题,但我怀疑是 HD 做了一些神秘的事情,因为它在重新启动后仍然存在。

ale*_*x.p 3

这是由于为相关驱动器启用了SMART 数据而导致的。

禁用 SMART 数据解决了这个问题:

sudo smartctl --smart=off /dev/sda
Run Code Online (Sandbox Code Playgroud)

有趣的是,重新启用驱动器的 SMART 数据不会使问题返回,这表明 SMART 处于不一致的状态(自检运行时可能会崩溃?)并将其关闭然后再次打开重置该状态。

据推测,在磁盘旋转并进入循环后 30 分钟,它不断重新运行某种内部自检;由于这是在硬件层,计算机的其余部分不知道它正在发生,因此我看不到任何进程专门负责 IO 阻塞,也没有进程占用资源。

我会运行 SMART 自测试,同时尝试找出问题所在,但即使这样也不会重置状态 - 必须将其关闭然后再显式打开。