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 до 1М (на v4 я максимум 150MB / с 32K) я спробував налаштувати

  • 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

планують взяти snoop's від DD над v3 та v4 та порівняти. Ви вже зробили це, але трафіку було занадто багато, і я використав дисковий файл замість кешованого файлу, що порівнював таймінги безглуздо. Запускатимуться інші snoop's з кешованими даними та без іншого трафіку між полями. ТБД

Крім того, хлопці в мережі говорять, що на з'єднаннях немає обмежувачів руху або обмеження пропускної здатності.


2
Ну для однієї речі nfsv4 за замовчуванням працює на tcp замість udp.
Філ Холленбек

3
AFAIK, solaris, на відміну від Linux, монтує tcp за замовчуванням навіть на v3. Для тестів v3 я також явно "proto = tcp" у деяких тестах, але мав таку ж продуктивність на v3 з або без включення "proto = tcp"
Кайл Хейлі

Ви вже включили джомбові кадри на комутаційну інфраструктуру та сервери NIC?
многочлен

так, рамки jumbo встановлені та перевірені. З dtrace я бачу розміри пакетів.
Кайл Хейлі

1
Насправді, Linux також за замовчуванням монтується за допомогою tcp
janneb

Відповіді:


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 тим, що дозволяє серверу делегувати конкретні дії над файлом клієнтові, щоб активізувати більш агресивне кешування даних клієнта та дозволити кешування стану блокування. Сервер передає клієнтові керування оновленнями файлів та станом блокування клієнту через делегування. Це зменшує затримку, дозволяючи клієнту виконувати різні операції та кешувати дані локально. В даний час існує два типи делегацій: читати та писати. Сервер має можливість передзвонити делегацію від клієнта у разі наявності суперечок для файлу. Після того, як клієнт має делегацію, він може виконувати операції над файлами, дані яких були кешовані локально, щоб уникнути затримки в мережі та оптимізувати введення-виведення. Агресивніше кешування, яке випливає з делегацій, може стати великою підмогою в таких середовищах:

  • Часті відкриваються та закриваються
  • Часті GETATTR
  • Блокування файлів
  • Спільний доступ лише для читання
  • Висока затримка
  • Швидкі клієнти
  • Сильно завантажений сервер з багатьма клієнтами

Дякую за покажчики на NFS 4.1, хоча я AFAIK вони ми на 4.0
Кайл Хейлі

1
Власне, зміни кешування на стороні клієнта відбулися з 4.0, і це може бути найбільшою різницею в роботі, як це видно з виписки v4 - "NFSv4 ... делегат ... клієнту". Щойно помітив, питання стосувалося читання. Я не впевнений, наскільки це стосується більшості цього випадку.
Петро
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.