解决 ESXi NFS 数据存储上的延迟峰值问题

解决 ESXi NFS 数据存储上的延迟峰值问题

我遇到了大约五秒钟在 ESXi 中的 NFS 数据存储上,由某些虚拟机触发。我怀疑这可能是由使用 NCQ/TCQ 的虚拟机引起的,因为这种情况不会发生在虚拟 IDE 驱动器上。

可以使用以下方法重现fsync 测试器(作者:Ted Ts'o)和约平。例如使用具有 8GB 磁盘的 Grml 实时系统:

Linux 2.6.33-grml64:
root@dynip211 /mnt/sda # ./fsync-tester
fsync time: 5.0391
fsync time: 5.0438
fsync time: 5.0300
fsync time: 0.0231
fsync time: 0.0243
fsync time: 5.0382
fsync time: 5.0400
[... goes on like this ...]

那是5秒,而不是毫秒。这甚至会在同一主机和数据存储上运行的不同虚拟机上产生 IO 延迟

root@grml /mnt/sda/ioping-0.5 # ./ioping -i 0.3 -p 20 .
4096 bytes from . (reiserfs /dev/sda): request=1 time=7.2 ms
4096 bytes from . (reiserfs /dev/sda): request=2 time=0.9 ms
4096 bytes from . (reiserfs /dev/sda): request=3 time=0.9 ms
4096 bytes from . (reiserfs /dev/sda): request=4 time=0.9 ms
4096 bytes from . (reiserfs /dev/sda): request=5 time=4809.0 ms
4096 bytes from . (reiserfs /dev/sda): request=6 time=1.0 ms
4096 bytes from . (reiserfs /dev/sda): request=7 time=1.2 ms
4096 bytes from . (reiserfs /dev/sda): request=8 time=1.1 ms
4096 bytes from . (reiserfs /dev/sda): request=9 time=1.3 ms
4096 bytes from . (reiserfs /dev/sda): request=10 time=1.2 ms
4096 bytes from . (reiserfs /dev/sda): request=11 time=1.0 ms
4096 bytes from . (reiserfs /dev/sda): request=12 time=4950.0 ms

当我将第一个虚拟机移动到本地存储时,它看起来完全正常:

root@dynip211 /mnt/sda # ./fsync-tester
fsync time: 0.0191
fsync time: 0.0201
fsync time: 0.0203
fsync time: 0.0206
fsync time: 0.0192
fsync time: 0.0231
fsync time: 0.0201
[... tried that for one hour: no spike ...]

我尝试过但没有任何效果的方法:

  • 测试了多个 ESXi 版本:381591、348481、260247
  • 在不同的硬件、不同的 Intel 和 AMD 机器上进行了测试
  • 使用不同的 NFS 服务器进行测试,均显示相同的行为:
    • OpenIndiana b147(ZFS 同步始终或禁用:无区别)
    • OpenIndiana b148(ZFS 同步始终或禁用:无区别)
    • Linux 2.6.32(同步或异步:无区别)
    • NFS 服务器是否在同一台机器上(作为虚拟存储设备)或位于不同的主机上没有区别

经过客户操作系统测试,发现存在问题:

  • Windows 7 64 位(使用 CrystalDiskMark,延迟峰值主要发生在准备阶段)
  • Linux 2.6.32 (fsync 测试器 + ioping)
  • Linux 2.6.38 (fsync 测试器 + ioping)

我无法在 Linux 2.6.18 VM 上重现此问题。

另一种解决方法是使用虚拟 IDE 磁盘(与 SCSI/SAS 相比),但这会限制性能和每个 VM 的驱动器数量。

更新2011-06-30:

如果应用程序在 fsync 之前写入多个小块,则延迟峰值似乎会更频繁地发生。例如,fsync-tester 会这样做(strace 输出):

pwrite(3, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"..., 1048576, 0) = 1048576
fsync(3)                                = 0

ioping 在准备文件时执行此操作:

[lots of pwrites]
pwrite(3, "********************************"..., 4096, 1036288) = 4096
pwrite(3, "********************************"..., 4096, 1040384) = 4096
pwrite(3, "********************************"..., 4096, 1044480) = 4096
fsync(3)                                = 0

ioping 的设置阶段几乎总是挂起,而 fsync-tester 有时工作正常。有人能更新 fsync-tester 来写入多个小块吗?我的 C 语言技能很差 ;)

更新2011-07-02:

iSCSI 不会出现此问题。我尝试使用 OpenIndiana COMSTAR iSCSI 服务器。但 iSCSI 无法让您轻松访问 VMDK 文件,因此您可以使用快照和 rsync 在主机之间移动它们。

更新2011-07-06:

这是 wireshark 捕获的一部分,由同一 vSwitch 上的第三台虚拟机捕获。这一切都发生在同一主机上,不涉及任何物理网络。

我已经在时间 20 左右开始 ioping。直到五秒延迟结束才发送数据包:

No.  Time        Source                Destination           Protocol Info
1082 16.164096   192.168.250.10        192.168.250.20        NFS      V3 WRITE Call (Reply In 1085), FH:0x3eb56466 Offset:0 Len:84 FILE_SYNC
1083 16.164112   192.168.250.10        192.168.250.20        NFS      V3 WRITE Call (Reply In 1086), FH:0x3eb56f66 Offset:0 Len:84 FILE_SYNC
1084 16.166060   192.168.250.20        192.168.250.10        TCP      nfs > iclcnet-locate [ACK] Seq=445 Ack=1057 Win=32806 Len=0 TSV=432016 TSER=769110
1085 16.167678   192.168.250.20        192.168.250.10        NFS      V3 WRITE Reply (Call In 1082) Len:84 FILE_SYNC
1086 16.168280   192.168.250.20        192.168.250.10        NFS      V3 WRITE Reply (Call In 1083) Len:84 FILE_SYNC
1087 16.168417   192.168.250.10        192.168.250.20        TCP      iclcnet-locate > nfs [ACK] Seq=1057 Ack=773 Win=4163 Len=0 TSV=769110 TSER=432016
1088 23.163028   192.168.250.10        192.168.250.20        NFS      V3 GETATTR Call (Reply In 1089), FH:0x0bb04963
1089 23.164541   192.168.250.20        192.168.250.10        NFS      V3 GETATTR Reply (Call In 1088)  Directory mode:0777 uid:0 gid:0
1090 23.274252   192.168.250.10        192.168.250.20        TCP      iclcnet-locate > nfs [ACK] Seq=1185 Ack=889 Win=4163 Len=0 TSV=769821 TSER=432716
1091 24.924188   192.168.250.10        192.168.250.20        RPC      Continuation
1092 24.924210   192.168.250.10        192.168.250.20        RPC      Continuation
1093 24.924216   192.168.250.10        192.168.250.20        RPC      Continuation
1094 24.924225   192.168.250.10        192.168.250.20        RPC      Continuation
1095 24.924555   192.168.250.20        192.168.250.10        TCP      nfs > iclcnet_svinfo [ACK] Seq=6893 Ack=1118613 Win=32625 Len=0 TSV=432892 TSER=769986
1096 24.924626   192.168.250.10        192.168.250.20        RPC      Continuation
1097 24.924635   192.168.250.10        192.168.250.20        RPC      Continuation
1098 24.924643   192.168.250.10        192.168.250.20        RPC      Continuation
1099 24.924649   192.168.250.10        192.168.250.20        RPC      Continuation
1100 24.924653   192.168.250.10        192.168.250.20        RPC      Continuation

第二次更新 2011-07-06:

TCP 窗口大小似乎有一些影响。我无法使用 FreeNAS(基于 FreeBSD)作为 NFS 服务器重现此问题。wireshark 捕获显示 TCP 窗口定期更新至 29127 字节。我没有在 OpenIndiana 中看到它们,因为它默认使用更大的窗口大小。

如果我在 OpenIndiana 中设置以下选项并重新启动 NFS 服务器,则不再重现此问题:

ndd -set /dev/tcp tcp_recv_hiwat 8192 # default is 128000
ndd -set /dev/tcp tcp_max_buf 1048575 # default is 1048576

但这会影响性能:使用 dd_rescue 从 /dev/zero 写入文件的速度从 170MB/s 降至 80MB/s。

更新2011-07-07:

我已经上传了tcpdump 捕获(可以使用 wireshark 分析)。在本例中,192.168.250.2 是 NFS 服务器(OpenIndiana b148),192.168.250.10 是 ESXi 主机。

我在这次捕获过程中测试过的内容:

在时间 30 时开始“ioping -w 5 -i 0.2 .”,设置中挂起 5 秒,在时间 40 时完成。

在时间 60 时开始“ioping -w 5 -i 0.2 .”,设置中挂起 5 秒,在时间 70 时完成。

在时间 90 启动“fsync-tester”,出现以下输出,在时间 120 停止:

fsync time: 0.0248
fsync time: 5.0197
fsync time: 5.0287
fsync time: 5.0242
fsync time: 5.0225
fsync time: 0.0209

第二次更新 2011-07-07:

测试了另一个 NFS 服务器 VM,这次是 NexentaStor 3.0.5 社区版:显示同样的问题。

更新2011-07-31:

我也可以在新的 ESXi 版本 4.1.0.433742 上重现此问题。

答案1

该问题似乎已在 ESXi 5 中修复。我已成功测试了版本 469512。

答案2

谢谢,nfsstat 看起来不错。我查看了捕获的内容。没有发现任何结论性的东西,但确实发现了一些有趣的东西。我过滤了 tcp.time_delta > 5。我在每一个延迟实例是 RPC 调用的确切开始。并非所有新的 RPC 调用都很慢,但所有减速都发生在 RPC 调用的确切开始处。此外,从捕获结果来看,192.168.250.10 包含所有延迟。192.168.250.2 立即响应所有请求。

发现:

  • 延迟总是发生在 RPC 调用的第一个数据包中
  • NFS 命令类型与延迟实例无关
  • 碎片化 = 仅延迟第一个数据包

一个大型的写入调用可以分解成 300 个单独的 TCP 数据包,只有第一个被延迟,其余的都飞过去了。中间从来不会发生延迟。我不确定窗口大小会如何影响开始如此剧烈地改变这种关系。

下一步:我将开始向下调整 NFS 选项(如 NFSSVC_MAXBLKSIZE),而不是 TCP 窗口。此外,我注意到 2.6.18 可以工作,而 2.6.38 则不行。我知道在那段时间里添加了对 VMXnet3 驱动程序的支持。您在主机上使用什么 NIC 驱动程序?TCP 卸载是/否?在 95 秒左右,单个 NFS 写入调用有超过 500 个 TCP 数据包。负责 TCP 并分解大型 PDU 的任何东西都可能是阻塞的原因。

答案3

我在使用 ESXi4.1U1 和 CentOS VM 时遇到了同样的问题。主机是 Dell R610s,存储是 EMC2 Isilon 集群。

您是否使用了 VLANS?我发现在 VMkernel 端口上使用 VLAN 进行存储会导致 VMHost 上的所有存储流量“挂起”4000-5000 毫秒。但是,如果我将 VMkernel 端口移出 VLAN,使其接收未标记的数据包,则不会出现此问题。

下面的简单设置将会导致我的网络出现问题:

1)在服务器或工作站上安装 ESXi 4.1U1(我尝试时都出现了这个问题)

2)在 VLAN 上添加 VMkernel 端口。

3)添加 NFS 数据存储(我的位于同一个 VLAN 上,即 Isilon 接收标记数据包)

4)安装2个CentOS 5.5 VM,其中一个带有ioping。

5)将虚拟机启动到单用户模式(即无网络、最少服务)

6)在一台机器上运行ioping,以便将其写入虚拟磁盘

7)在另一台机器上运行 dd 或类似命令,将 100MB 数据写入 /tmp 或类似目录

我经常会看到两个虚拟机都冻结 4-5 秒。

真的很感兴趣看看是否有其他人也见过类似的东西。

答案4

你的 DNS 看起来怎么样?你的 DNS/etc/resolv.conf正确吗?默认超时时间为 5 秒。

man resolv.conf

timeout:n
                 sets the amount of time the  resolver  will  wait  for  a
                 response  from  a  remote name server before retrying the
                 query via a different name server.  Measured in  seconds,
                 the default is RES_TIMEOUT (currently 5, see <resolv.h>).

尝试附加timeout:3到您的/etc/resolv.conf,然后再次运行您的 fsync 测试。

相关内容