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가 있습니다. 모든 테스트 사이에 다시 마운트하여 클라이언트 측 캐싱을 피합니다. 내가 사용하는 dtraceNFS를 통해 제공되는 얼마나 빨리 데이터를 측정하기 위해 서버에서 볼 수 있습니다. v3과 v4 모두 변경했습니다.

 nfs4_bsize
 nfs3_bsize

기본 32K에서 1M까지 (v4에서 32K로 최대 150MB / s) 조정을 시도했습니다.

  • nfs3_max_threads
  • clnt_max_conns
  • nfs3_async_clusters

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의 스눕을 비교하고 비교합니다. 이미 수행했지만 트래픽이 너무 많아서 캐시 된 파일 대신 디스크 파일을 사용하여 타이밍 비교를 의미가 없었습니다. 캐시 된 데이터로 다른 스눕을 실행하고 상자 사이에 다른 트래픽은 없습니다. TBD

또한 네트워크 담당자는 연결에 트래픽 조절 또는 대역폭 제한이 없다고 말합니다.


2
nfsv4는 기본적으로 udp 대신 tcp에서 실행됩니다.
Phil Hollenback

3
AFAIK, solaris는 Linux와 달리 vcp에서도 기본적으로 tcp를 마운트합니다. v3 테스트의 경우 일부 테스트에서는 명시 적으로 "proto = tcp"이지만 "proto = tcp"를 포함하거나 포함하지 않고 v3에서 동일한 성능을 나타 냈습니다
Kyle Hailey

스위칭 인프라 및 서버 NIC에서 점보 프레임을 이미 활성화 했습니까?
다항식

예, 점보 프레임이 설정되고 확인되었습니다. dtrace를 사용하면 패킷 크기를 볼 수 있습니다.
Kyle Hailey

1
TCP와 장착에 대한 사실, 리눅스는 또한 기본 설정
janneb

답변:


4

NFS 4.1 (부 1) 은 더 빠르고 효율적인 프로토콜로 설계되었으며 이전 버전, 특히 4.0보다 권장됩니다.

여기에는 클라이언트 측 캐싱 이 포함 되며이 시나리오에서는 관련이 없지만 pNFS (parallel-NFS)가 포함 됩니다. 주요 변경 사항은 프로토콜이 이제 상태 저장 상태라는 것입니다.

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

NetApp을 사용할 때 성능 문서로 판단 할 때 권장되는 프로토콜이라고 생각합니다. 이 기술은 Windows Vista + 기회 잠금과 유사합니다.

NFSv4는 서버가 파일에 대한 특정 작업을 클라이언트에 위임하여보다 적극적인 클라이언트 데이터 캐싱 및 잠금 상태 캐싱을 허용함으로써 이전 버전의 NFS와 다릅니다. 서버는 위임을 통해 파일 업데이트 및 잠금 상태를 클라이언트에 제어합니다. 이를 통해 클라이언트는 다양한 작업을 수행하고 데이터를 로컬로 캐시 할 수 있으므로 대기 시간이 줄어 듭니다. 읽기와 쓰기라는 두 가지 유형의 위임이 현재 존재합니다. 서버는 파일에 대한 경합이있을 경우 클라이언트에서 위임을 다시 호출 할 수 있습니다. 클라이언트가 위임을 보유하면 네트워크 대기 시간을 피하고 I / O를 최적화하기 위해 데이터가 로컬로 캐시 된 파일에 대한 작업을 수행 할 수 있습니다. 위임으로 인한보다 적극적인 캐싱은 다음과 같은 특성을 가진 환경에서 큰 도움이 될 수 있습니다.

  • 빈번한 개폐
  • 빈번한 GETATTR
  • 파일 잠금
  • 읽기 전용 공유
  • 높은 대기 시간
  • 빠른 고객
  • 많은 클라이언트가있는로드가 많은 서버

NFS A 4.1에 대한 포인터에 감사합니다. 비록 우리가 4.0에 있습니다
Kyle Hailey

1
실제로 클라이언트 측 캐싱 변경 사항은 4.0과 함께 제공되었으며 v4 추출에서 볼 수 있듯이 "NFSv4 ... 델리게이트를 클라이언트에 위임"하는 것처럼 성능면에서 가장 큰 차이가있을 수 있습니다. 방금 질문이 독서에 관한 것임을 알았습니다. 이 경우와 관련하여 대부분의 관련성이 확실하지 않습니다.
피터
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.