NFS v3与v4


11

我想知道为什么NFS v4会比NFS v3快得多,并且v3上是否有任何参数可以调整。

我挂载文件系统

sudo mount  -o  'rw,bg,hard,nointr,rsize=1048576,wsize=1048576,vers=4'  toto:/test /test

然后运行

 dd if=/test/file  of=/dev/null bs=1024k

我可以读取200-400MB / s, 但是当我将版本更改为vers=3,重新安装并重新运行dd时,我只能得到90MB / s。我正在读取的文件是NFS服务器上的内存文件。连接的两端均为Solaris,并具有10GbE NIC。通过在所有测试之间重新安装,我避免了任何客户端缓存。我曾经dtrace在服务器上看到过测量通过NFS服务数据的速度。对于v3和v4,我都进行了更改:

 nfs4_bsize
 nfs3_bsize

从默认的32K到1M(在v4上,使用32K时最大速度为150MB / s),我尝试进行调整

  • nfs3_max_threads
  • clnt_max_conns
  • nfs3_async_clusters

来改善v3的性能,但没有成功。

在v3上,如果我运行四个并行服务器dd,那么吞吐量从90MB / s下降到70-80MBs,这使我相信问题是共享资源,如果是这样,那么我想知道这是什么,是否可以增加它资源。

dtrace代码以获取窗口大小:

#!/usr/sbin/dtrace -s
#pragma D option quiet
#pragma D option defaultargs

inline string ADDR=$$1;

dtrace:::BEGIN
{
       TITLE = 10;
       title = 0;
       printf("starting up ...\n");
       self->start = 0;
}

tcp:::send, tcp:::receive
/   self->start == 0  /
{
     walltime[args[1]->cs_cid]= timestamp;
     self->start = 1;
}

tcp:::send, tcp:::receive
/   title == 0  &&
     ( ADDR == NULL || args[3]->tcps_raddr == ADDR  ) /
{
      printf("%4s %15s %6s %6s %6s %8s %8s %8s %8s %8s  %8s %8s %8s  %8s %8s\n",
        "cid",
        "ip",
        "usend"    ,
        "urecd" ,
        "delta"  ,
        "send"  ,
        "recd"  ,
        "ssz"  ,
        "sscal"  ,
        "rsz",
        "rscal",
        "congw",
        "conthr",
        "flags",
        "retran"
      );
      title = TITLE ;
}

tcp:::send
/     ( ADDR == NULL || args[3]->tcps_raddr == ADDR ) /
{
    nfs[args[1]->cs_cid]=1; /* this is an NFS thread */
    this->delta= timestamp-walltime[args[1]->cs_cid];
    walltime[args[1]->cs_cid]=timestamp;
    this->flags="";
    this->flags= strjoin((( args[4]->tcp_flags & TH_FIN ) ? "FIN|" : ""),this->flags);
    this->flags= strjoin((( args[4]->tcp_flags & TH_SYN ) ? "SYN|" : ""),this->flags);
    this->flags= strjoin((( args[4]->tcp_flags & TH_RST ) ? "RST|" : ""),this->flags);
    this->flags= strjoin((( args[4]->tcp_flags & TH_PUSH ) ? "PUSH|" : ""),this->flags);
    this->flags= strjoin((( args[4]->tcp_flags & TH_ACK ) ? "ACK|" : ""),this->flags);
    this->flags= strjoin((( args[4]->tcp_flags & TH_URG ) ? "URG|" : ""),this->flags);
    this->flags= strjoin((( args[4]->tcp_flags & TH_ECE ) ? "ECE|" : ""),this->flags);
    this->flags= strjoin((( args[4]->tcp_flags & TH_CWR ) ? "CWR|" : ""),this->flags);
    this->flags= strjoin((( args[4]->tcp_flags == 0 ) ? "null " : ""),this->flags);
    printf("%5d %14s %6d %6d %6d %8d \ %-8s %8d %6d %8d  %8d %8d %12d %s %d  \n",
        args[1]->cs_cid%1000,
        args[3]->tcps_raddr  ,
        args[3]->tcps_snxt - args[3]->tcps_suna ,
        args[3]->tcps_rnxt - args[3]->tcps_rack,
        this->delta/1000,
        args[2]->ip_plength - args[4]->tcp_offset,
        "",
        args[3]->tcps_swnd,
        args[3]->tcps_snd_ws,
        args[3]->tcps_rwnd,
        args[3]->tcps_rcv_ws,
        args[3]->tcps_cwnd,
        args[3]->tcps_cwnd_ssthresh,
        this->flags,
        args[3]->tcps_retransmit
      );
    this->flags=0;
    title--;
    this->delta=0;
}

tcp:::receive
/ nfs[args[1]->cs_cid] &&  ( ADDR == NULL || args[3]->tcps_raddr == ADDR ) /
{
    this->delta= timestamp-walltime[args[1]->cs_cid];
    walltime[args[1]->cs_cid]=timestamp;
    this->flags="";
    this->flags= strjoin((( args[4]->tcp_flags & TH_FIN ) ? "FIN|" : ""),this->flags);
    this->flags= strjoin((( args[4]->tcp_flags & TH_SYN ) ? "SYN|" : ""),this->flags);
    this->flags= strjoin((( args[4]->tcp_flags & TH_RST ) ? "RST|" : ""),this->flags);
    this->flags= strjoin((( args[4]->tcp_flags & TH_PUSH ) ? "PUSH|" : ""),this->flags);
    this->flags= strjoin((( args[4]->tcp_flags & TH_ACK ) ? "ACK|" : ""),this->flags);
    this->flags= strjoin((( args[4]->tcp_flags & TH_URG ) ? "URG|" : ""),this->flags);
    this->flags= strjoin((( args[4]->tcp_flags & TH_ECE ) ? "ECE|" : ""),this->flags);
    this->flags= strjoin((( args[4]->tcp_flags & TH_CWR ) ? "CWR|" : ""),this->flags);
    this->flags= strjoin((( args[4]->tcp_flags == 0 ) ? "null " : ""),this->flags);
    printf("%5d %14s %6d %6d %6d %8s / %-8d %8d %6d %8d  %8d %8d %12d %s %d  \n",
        args[1]->cs_cid%1000,
        args[3]->tcps_raddr  ,
        args[3]->tcps_snxt - args[3]->tcps_suna ,
        args[3]->tcps_rnxt - args[3]->tcps_rack,
        this->delta/1000,
        "",
        args[2]->ip_plength - args[4]->tcp_offset,
        args[3]->tcps_swnd,
        args[3]->tcps_snd_ws,
        args[3]->tcps_rwnd,
        args[3]->tcps_rcv_ws,
        args[3]->tcps_cwnd,
        args[3]->tcps_cwnd_ssthresh,
        this->flags,
        args[3]->tcps_retransmit
      );
    this->flags=0;
    title--;
    this->delta=0;
}

输出看起来像(不是在这种特殊情况下):

cid              ip  usend  urecd  delta     send     recd      ssz    sscal      rsz     rscal    congw   conthr     flags   retran
  320 192.168.100.186    240      0    272      240 \             49232      0  1049800         5  1049800         2896 ACK|PUSH| 0
  320 192.168.100.186    240      0    196          / 68          49232      0  1049800         5  1049800         2896 ACK|PUSH| 0
  320 192.168.100.186      0      0  27445        0 \             49232      0  1049800         5  1049800         2896 ACK| 0
   24 192.168.100.177      0      0 255562          / 52          64060      0    64240         0    91980         2920 ACK|PUSH| 0
   24 192.168.100.177     52      0    301       52 \             64060      0    64240         0    91980         2920 ACK|PUSH| 0

一些标题

usend - unacknowledged send bytes
urecd - unacknowledged received bytes
ssz - send window
rsz - receive window
congw - congestion window

计划在v3和v4上获取dd的监听消息并进行比较。已经做到了,但是流量太多了,我使用了磁盘文件而不是缓存文件,这使得比较计时变得毫无意义。将使用缓存的数据运行其他监听,并且框之间没有其他流量。待定

另外,网络专家说,连接上没有流量调整或带宽限制器。


2
好吧,nfsv4默认在tcp而不是udp上运行。
Phil Hollenback

3
AFAIK,solaris与Linux不同,即使在v3上也默认安装tcp。对于v3测试,我在某些测试中也明确显示了“ proto = tcp”,但无论是否包含“ proto = tcp”,v3上的性能都相同
Kyle Hailey

您是否已经在交换基础结构和服务器NIC上启用了巨型帧?
多项式

是的,已设置并验证了巨型帧。使用dtrace,我可以看到数据包的大小。
凯尔·海莉

1
实际上,Linux也默认使用tcp挂载
janneb 2011年

Answers:


4

NFS 4.1(次要版本1)被设计为一种更快,更有效的协议,建议在以前的版本(尤其是4.0)上使用。

这包括客户端缓存,尽管在这种情况下不相关,但包括并行NFS(pNFS)。主要的变化是该协议现在是有状态的。

http://www.netapp.com/us/communities/tech-ontap/nfsv4-0408.html

我认为从NetApps的性能文档来看,这是推荐的协议。该技术类似于Windows Vista +机会锁定。

NFSv4与以前的NFS版本不同,NFSv4允许服务器将文件上的特定操作委派给客户端,以启用更积极的客户端数据缓存并允许锁定状态的缓存。服务器通过委派将文件更新和锁定状态的控制权交给客户端。通过允许客户端执行各种操作并在本地缓存数据,可以减少延迟。当前存在两种类型的委托:读取和写入。如果有文件争用,服务器可以从客户端回调委托。客户端拥有委托后,它可以对其数据已本地缓存的文件执行操作,以避免网络延迟并优化I / O。在具有以下特征的环境中,委托带来的更积极的缓存可能会大有帮助:

  • 频繁打开和关闭
  • 常见的GETATTR
  • 文件锁定
  • 只读共享
  • 高延迟
  • 快速客户
  • 具有许多客户端的服务器负载较重

感谢NFS 4.1的指针,尽管我相信我们使用的是4.0
Kyle Hailey

1
实际上,客户端缓存更改是在4.0中引入的,这可能是最大的性能差异,正如您从v4摘录中看到的那样-“ NFSv4 ...委托给客户端”。刚注意到问题是关于阅读。我不确定大多数情况与这种情况是否相关。
彼得
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.