NFS v3 contro v4


11

Mi chiedo perché NFS v4 sarebbe molto più veloce di NFS v3 e se ci sono parametri su v3 che potrebbero essere modificati.

Montare un file system

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

e poi corri

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

Riesco a leggere 200-400 MB / s ma quando cambio versione a vers=3, rimontalo e rieseguo il dd ottengo solo 90 MB / s . Il file da cui sto leggendo è un file in memoria sul server NFS. Entrambi i lati della connessione sono Solaris e hanno una scheda NIC da 10 GbE. Evito qualsiasi memorizzazione nella cache lato client rimontando tra tutti i test. Ero solito dtracevedere sul server per misurare la velocità con cui vengono forniti i dati tramite NFS. Sia per la v3 che per la v4 ho cambiato:

 nfs4_bsize
 nfs3_bsize

da 32 KB a 1 MB di default (su v4 ho raggiunto il massimo a 150 MB / s con 32 KB) Ho provato a modificare

  • nfs3_max_threads
  • clnt_max_conns
  • nfs3_async_clusters

per migliorare le prestazioni della v3, ma niente da fare.

Sulla v3 se ddeseguo quattro paralleli , il throughput scende da 90 MB / sa 70-80 MB, il che mi porta a credere che il problema sia una risorsa condivisa e, in tal caso, allora mi chiedo di cosa si tratta e se posso aumentarlo risorsa.

codice dtrace per ottenere le dimensioni della finestra:

#!/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;
}

L'output è simile (non da questa situazione particolare):

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

alcune intestazioni

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

pensando di prendere ficcanaso del dd su v3 e v4 e confrontarlo. L'ho già fatto ma c'era troppo traffico e ho usato un file su disco invece di un file memorizzato nella cache che ha reso insignificante il confronto dei tempi. Eseguirà altri snoop con dati memorizzati nella cache e nessun altro traffico tra le caselle. TBD

Inoltre, i ragazzi della rete affermano che non vi sono limiti di traffico o limitatori di larghezza di banda sulle connessioni.


2
Bene per prima cosa nfsv4 gira su tcp di default invece di udp.
Phil Hollenback,

3
AFAIK, solaris, a differenza di Linux, monta tcp di default anche su v3. Per i test v3 ho anche esplicitamente "proto = tcp" in alcuni dei test ma ho avuto le stesse prestazioni su v3 con o senza "proto = tcp"
Kyle Hailey,

Hai già abilitato i frame jumbo sull'infrastruttura di commutazione e le schede NIC del server?
polinomio

sì, i frame jumbo sono impostati e verificati. Con dtrace posso vedere le dimensioni dei pacchetti.
Kyle Hailey,

1
In realtà, anche per impostazione predefinita Linux viene montato con tcp
janneb il

Risposte:


4

NFS 4.1 (minore 1) è progettato per essere un protocollo più veloce ed efficiente ed è raccomandato rispetto alle versioni precedenti, in particolare 4.0.

Ciò include la memorizzazione nella cache lato client e, sebbene non pertinente in questo scenario, parallel-NFS (pNFS) . Il principale cambiamento è che il protocollo è ora con stato.

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

Penso che sia il protocollo raccomandato quando si usano NetApps, a giudicare dalla loro documentazione delle prestazioni. La tecnologia è simile a Windows Vista + blocco opportunistico.

NFSv4 differisce dalle versioni precedenti di NFS consentendo a un server di delegare azioni specifiche su un file a un client per consentire una memorizzazione più aggressiva dei dati nella cache dei client e consentire la memorizzazione nella cache dello stato di blocco. Un server cede il controllo degli aggiornamenti dei file e dello stato di blocco a un client tramite una delega. Ciò riduce la latenza consentendo al client di eseguire varie operazioni e memorizzare nella cache i dati localmente. Esistono attualmente due tipi di delegazioni: lettura e scrittura. Il server ha la possibilità di richiamare una delega da un client in caso di contesa per un file. Una volta che un client detiene una delega, può eseguire operazioni sui file i cui dati sono stati memorizzati nella cache locale per evitare la latenza della rete e ottimizzare l'I / O. La memorizzazione nella cache più aggressiva che risulta dalle delegazioni può essere di grande aiuto in ambienti con le seguenti caratteristiche:

  • Frequenti si apre e si chiude
  • GETATTR frequenti
  • Blocco dei file
  • Condivisione di sola lettura
  • Alta latenza
  • Clienti veloci
  • Server pesantemente caricato con molti client

Grazie per i suggerimenti su NFS 4.1 anche se AFAIK sono su 4.0
Kyle Hailey

1
In realtà, le modifiche alla cache sul lato client sono arrivate con 4.0 e potrebbero essere la maggiore differenza di prestazioni, per la scrittura, come si può vedere dall'estratto v4 - "NFSv4 ... delegato ... a un client". Ho appena notato che la domanda riguardava la lettura. Non sono sicuro di quanto la maggior parte di questo sia rilevante per quel caso.
Peter,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.