请注意,虽然这个问题有点特定于 Redis,但主要问题是通用的:某个进程占用了太多的 HDD IO 写入带宽,以致其他进程无法写入任何内容。
我们在基于 Ubuntu 的 Xen XCP 主机中安装了一台 Ubuntu VM(安装在软件 RAID1 中的两块硬盘上)。该 VM 正在以大约 2K 命令/秒的负载运行 Redis 服务器。
问题:当所述 Redis 服务器执行此操作时BGREWRITEAOF
,它会阻止其客户端约 10 秒。
细节:
仅使用 AOF 持久性,不使用 RDB。Redis 配置为每秒 fsync 一次 AOF 文件。
RedisBGREWRITEAOF
会分叉并在子进程中执行所有磁盘密集型工作。同时,主进程不断将数据附加到其 AOF 文件。
BGREWRITEAOF
大约需要 10 秒(1.5GB 数据,150 MB/s 磁盘写入速度)。执行重写的子进程消耗了所有 HDD IO 写入吞吐量。
父进程尝试fsync
,这需要两秒以上的时间,数据保护启动,并调用阻止write
,阻止父进程直到BGREWRITEAOF
完成磁盘操作。
以下是详细信息和讨论这使我对事件做出了上述解释。
问题:一个进程被允许执行如此多的磁盘 IO,以至于其他一切都被阻止,这对我来说似乎很可疑。我可以在系统级别做些什么来解决这个问题?如果BGREWRITEAOF
花一点时间,我没问题,只要允许父进程在重写处于活动状态时保存其数据即可。
请注意,我知道一些解决方法,例如将 AOF 持久性移动到从属、使用no-appendfsync-on-rewrite
Redis 配置选项等;这个问题专门用于解决问题,而不是绕过它。
答案1
据我所知,您可以尝试更改 IO 调度程序。尝试使用此命令:
echo cfq > /sys/block/$DEVICE/queue/scheduler
其中 $DEVICE 是您的 RAID1 磁盘。此命令为您的设备安装“完全公平排队”调度程序。
答案2
我建议更改 I/O 调度程序并应用一些轻度调优技术。虽然我没有全面的调优指南,但其中一些答案和这个问题中详述的建议也可能对你有帮助。
考虑将 I/O 升降机改为最后期限或者无操作算法,然后重新测试。您可以使用另一个答案中详述的技术即时进行此更改。向 GRUB 内核命令添加一个条目,使其在重新启动后保持不变(添加elevator=deadline
:)
也许有关底层硬件或主机系统设置的一些细节会有所帮助。存储子系统上是否有任何电池支持或闪存支持的写入缓存?这会带来改变。
iostat
最后,您可以尝试一些轻量级的基准测试/监控工具来查看发生了什么。例如,如果您可以访问,则可以在测试应用程序时在另一个终端窗口中运行它。
例如,iostat -x 1
将以 1 秒的样本运行,并提供一些有关读/写速度和 I/O 服务时间和等待时间的指示。我也喜欢收集以此目的。