NFS v3与v4

我想知道为什么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。 我通过在所有testing之间重新安装来避免任何客户端caching。 我使用dtrace在服务器上查看数据通过NFS服务的速度。 对于v3和v4我改变了:

  nfs4_bsize nfs3_bsize 

从默认的32K到1M(在V4上,我用32K的最高速度为150MB /秒)我试过调整

  • nfs3_max_threads
  • clnt_max_conns
  • nfs3_async_clusters

提高V3的性能,但没有去。

在v3上,如果我运行四个并行dd ,吞吐量从90MB / s下降到70-80MB,这导致我认为问题是一些共享资源,如果是的话,那么我想知道它是什么,如果我可以增加那个资源。

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上使用snoop的dd和比较。 已经做到了,但是stream量太大,我使用了磁盘文件而不是caching文件,这使得比较时间变得毫无意义。 将使用caching的数据运行其他snoop,并且在各个框之间没有其他stream量。 TBD

此外,networking人士说,连接上没有stream量整形或带宽限制器。

NFS 4.1(次要1)被devise成一个更快和更有效的协议,并推荐在以前的版本,特别是4.0。

这包括客户端caching ,虽然在这种情况下并不相关, parallel-NFS(pNFS) 。 主要的变化是协议现在是有状态的。

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

我认为这是使用NetApps时推荐的协议,根据其性能文档来判断。 该技术类似于Windows Vista +机会locking。

NFSv4与以前的NFS版本不同,它允许服务器将文件上的特定操作委托给客户端,以启用更积极的客户端数据caching并允许cachinglocking状态。 服务器通过委托将文件更新和locking状态控制权交给客户端。 这通过允许客户端在本地执行各种操作和caching数据来减less延迟。 目前存在两种types的授权:读取和写入。 如果存在文件争用,服务器能够从客户端回拨委托。 一旦客户端拥有一个委托,它就可以对数据caching在本地的文件执行操作,以避免networking延迟并优化I / O。 代表团所产生的更积极的caching对于具有以下特征的环境可能是一个很大的帮助:

  • 经常打开和closures
  • 频繁的GETATTR
  • 文件locking
  • 只读共享
  • 高延迟
  • 快速的客户
  • 重载服务器与许多客户端