なぜ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 /秒)調整を試みました
v3のパフォーマンスを向上させるために、しかし行くことはありません。
V3で4つの並列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を超えるddのスヌープを計画して比較します。すでに実行しましたが、トラフィックが多すぎて、タイミングを比較しても意味がないキャッシュファイルの代わりにディスクファイルを使用しました。キャッシュされたデータで他のスヌープを実行し、ボックス間の他のトラフィックは実行しません。未定
さらに、ネットワーク関係者は、接続にトラフィックシェーピングや帯域幅制限機能がないと言っています。
NFS 4.1(マイナー1) は、より高速で効率的なプロトコルになるように設計されており、以前のバージョン、特に4.0よりも推奨されています。
これには クライアント側のキャッシュ が含まれ、このシナリオでは関係ありませんが、- parallel-NFS(pNFS) が含まれます。主な変更は、プロトコルがステートフルになったことです。
http://www.netapp.com/us/communities/tech-ontap/nfsv4-0408.html
NetAppsを使用する場合は、パフォーマンスドキュメントから判断すると、これが推奨されるプロトコルだと思います。このテクノロジーは、Windows Vista +の便宜的ロックに似ています。
NFSv4は以前のバージョンのNFSとは異なり、サーバーがファイルに対する特定のアクションをクライアントに委任して、より積極的なクライアントのデータキャッシュを有効にし、ロック状態のキャッシュを許可します。サーバーは、委任を介してファイルの更新とロック状態の制御をクライアントに譲ります。これにより、クライアントがさまざまな操作を実行し、データをローカルにキャッシュできるようになるため、待ち時間が短縮されます。現在、委任には、読み取りと書き込みの2つのタイプがあります。サーバーには、ファイルの競合が発生した場合にクライアントから委任をコールバックする機能があります。クライアントが委任を保持すると、データがローカルにキャッシュされているファイルに対して操作を実行して、ネットワーク遅延を回避し、I/Oを最適化できます。委任から生じるより積極的なキャッシングは、次の特性を持つ環境で大きな助けになる可能性があります。
- 頻繁な開閉
- 頻繁なGETATTR
- ファイルのロック
- 読み取り専用の共有
- 高レイテンシ
- 高速クライアント
- 多くのクライアントを持つ負荷の高いサーバー