Невеликі записи в мережу SMB діляться повільно в Windows, швидко над кріпленням CIFS Linux


10

Я намагаюся вирішити проблему продуктивності з часткою SMB / CIFS під час виконання малих записів.

Спочатку дозвольте описати мою поточну настройку мережі:

Сервер

  • Synology DS215j (з підтримкою SMB3)

Клієнти (той же комп'ютерний двожильний провідний Gig-E)

  • Ubuntu 14.04.5 LTS, Trusty Tahr
  • Windows 8.1

smb.conf

[global]
    printcap name=cups
    winbind enum groups=yes
    include=/var/tmp/nginx/smb.netbios.aliases.conf
    socket options=TCP_NODELAY IPTOS_LOWDELAY SO_RCVBUF=65536 SO_SNDBUF=65536
    security=user
    local master=no
    realm=*
    passdb backend=smbpasswd
    printing=cups
    max protocol=SMB3
    winbind enum users=yes
    load printers=yes
    workgroup=WORKGROUP

В даний час я тестую невелику ефективність запису за допомогою наступної програми, написаної на C ++ (на GitHub тут ):

#include <iostream>
#include <fstream>
#include <sstream>

using namespace std;

int main(int argc, char* argv[])
{
    ofstream outFile(argv[1]);
    for(int i = 0; i < 1000000; i++)
    {
        outFile << "Line #" << i << endl;   
    }

    outFile.flush();
    outFile.close();
    return 0;
}

Конфігурація кріплення для Linux:

//192.168.1.10/nas-main on /mnt/nas-main type cifs (rw,noexec,nodev)

Пробіг програми в Linux (максимальний вихід мережі при ~ 100Mbps):

$ time ./nas-write-test /mnt/nas-main/home/will/test.txt

real    0m0.965s
user    0m0.148s
sys 0m0.672s

Знімок PCAP, що показує з’єднання багатьох рядків в один пакет TCP:

Знімок PCAP для Linux

Пробіг програми в Windows, виміряний PowerShell:

> Measure-Command {start-process .\nas-write-test.exe -argumentlist "Z:\home\will\test-win.txt" -wait}


Days              : 0
Hours             : 0
Minutes           : 9
Seconds           : 29
Milliseconds      : 316
Ticks             : 5693166949
TotalDays         : 0.00658931359837963
TotalHours        : 0.158143526361111
TotalMinutes      : 9.48861158166667
TotalSeconds      : 569.3166949
TotalMilliseconds : 569316.6949

Знімок PCAP у Windows, що показує один рядок на запит SMB:

Знімок Windows PCAP

Ця ж програма займає близько 10 хвилин (~ 2,3 Мбіт / с) у Windows. Очевидно, що Windows PCAP демонструє дуже шумну SMB розмову з дуже низькою ефективністю корисного навантаження.

Чи є налаштування в Windows, які можуть покращити невелику продуктивність запису? З огляду на захоплення пакетів, Windows не буферизує записи належним чином і негайно надсилає дані по одному рядку. В той час, як в Linux, дані сильно буферизовані і, таким чином, мають значно кращі показники. Повідомте мене, чи корисні будуть файли PCAP, і я можу знайти спосіб їх завантаження.

Оновлення 27.10.16:

Як згадував @sehafoc, я зменшив max protocolналаштування серверів Samba до SMB1 з наступним:

max protocol=NT1

Вищевказані настройки призвели до точно такої ж поведінки.

Я також видалив змінну Samba, створивши спільний доступ на іншій машині Windows 10, і він також демонструє таку саму поведінку, як і сервер Samba, тому я починаю вважати, що це помилка кешування записів із клієнтами Windows в цілому.

Оновлення: 10.06.17:

Повне захоплення пакетів Linux (14 МБ)

Повний захват пакетів Windows (375 МБ)

Оновлення: 12.12.17:

Я також налаштовую NFS-спільний доступ, і Windows записує без буферизації для цього. Отже, це, безумовно, основна проблема клієнта Windows, наскільки я можу сказати, що, безумовно, прикро:

Будь-яка допомога буде вдячна!

Відповіді:


2

Кінцевий термін C ++ визначений для виведення '\ n' з подальшим флешем. flush () - це дорога операція, тому, як правило, слід уникати використання endl як кінцевого рядка за замовчуванням, оскільки це може створити саме таку проблему з продуктивністю, яку ви бачите (і не тільки з SMB, але і з будь-яким потоком зі дорогим флеш, включаючи локальне спінінг іржі або навіть найновіші NVMe при деяких смішно високих показниках випуску).

Заміна endl на "\ n" призведе до виправлення продуктивності вище, дозволяючи системі буферувати за призначенням. За винятком того, що деякі бібліотеки можуть перемикатись на "\ n", і в цьому випадку у вас більше головних болів (див. Https://stackoverflow.com/questions/21129162/tell-endl-not-to-flush для рішення, що перекриває метод sync () ).

Тепер, щоб ускладнити речі, flush () визначається лише для того, що відбувається в буферах бібліотеки. Вплив змиву на операційну систему, диск та інші зовнішні буфери не визначено. Для Microsoft.NET "Коли ви викликаєте метод FileStream.Flush, буфер вводу / виводу операційної системи також промивається." ( https://msdn.microsoft.com/en-us/library/2bw4h516(v=vs.110).aspx ) Це робить флеш особливо дорогим для Visual Studio C ++, оскільки це дозволить у без зворотній стороні записувати весь шлях фізичні носії в дальньому кінці віддаленого сервера, як ви бачите. GCC, з іншого боку, говорить: "Останнє нагадування: зазвичай є більше буферів, ніж лише ті, які є на мові / бібліотеці. Буфери ядра, дискові буфери тощо можуть також мати ефект. Перевірка та зміна цих систем залежать від системи" . "https://gcc.gnu.org/onlinedocs/libstdc++/manual/streambufs.html ) Схоже, ваші сліди Ubuntu вказують на те, що буфери операційної системи / мережі не змиваються під час промивання бібліотеки (). Поведінка, залежна від системи, буде тим більше причин уникати надмірного перемикання. Якщо ви використовуєте VC ++, ви можете спробувати перейти на похідну Windows GCC, щоб побачити, як реагує залежна від системи поведінка, або альтернативно використовувати Wine для запуску виконуваного Windows на Ubuntu.

Більш загально, вам потрібно подумати над вашими вимогами, щоб визначити, чи підходить прошивання кожної лінії чи ні. endl, як правило, підходить для інтерактивних потоків, таких як дисплей (нам потрібен користувач, щоб насправді бачити наш вихід, а не під час всплеску), але, як правило, не підходить для інших типів потоків, включаючи файли, де промивання накладних може бути значним. Я бачив, як програми промивають кожні 1, 2 та 4 та 8 байтових записів ... це не дуже приємно бачити, як ОС шліфує мільйони IO, щоб написати 1MB файл.

Як приклад, файл журналу може потребувати промивання кожного рядка, якщо ви налагоджуєте аварію, тому що вам потрібно очистити потоку до того, як відбудеться збій; в той час як інший файл журналу може не потребувати змивання кожного рядка, якщо він просто створює багатослівний інформаційний журнал, який, як очікується, автоматично спускається до завершення програми. Це не повинно бути ні /, ні тим, як ви могли б вивести клас із більш досконалим алгоритмом змивання відповідно до конкретних вимог.

Порівняйте свій випадок із контрастним випадком людей, яким потрібно забезпечити, щоб їх дані повністю зберігалися на диску та не були вразливими в буфері операційної системи ( /programming/7522479/how-do-i-ensure-data -написано на диск-до закриття-fstream ).

Зауважте, що як написано, outFile.flush () є зайвим, оскільки він змиває вже розмиту потоку. Щоб бути педантичним, вам слід було використовувати сам endl або бажано "\ n" з outFile.flush (), але не те й інше.


Завдяки мільйонів! Ви заслуговуєте на понад 100 балів, але це все, що я можу дати :) Це точно була проблема!
mevatron

2

У мене недостатньо репутації, щоб залишити коментар (що, на мою думку, було б краще враховувати рівень перевірки на цю відповідь).

Я зауважую, що одна велика відмінність у трасі рівня Linux та Windows - це те, що ви використовуєте SMB1 у Linux та SMB2 у Windows. Можливо, механізм пакетної розблокування працює в самбі SMB1, ніж реалізація ексклюзивного оренди SMB2. В обох випадках це повинно передбачати певну кількість кешування на стороні клієнта.

1) Можливо, спробуйте встановити нижчий максимальний рівень протоколу в Samba, щоб спробувати Windows з SMB1 2) Перевірте, чи вилучаються ексклюзивні оплоки або оренди

Сподіваюся, це допомагає :)


2

На ефективність віддалених файлових операцій, таких як читання / запис, за допомогою протоколу SMB, може впливати розмір буферів, виділених серверами та клієнтами. Розмір буфера визначає кількість зворотних поїздок, необхідних для надсилання фіксованої кількості даних. Кожен раз, коли запити та відповіді надсилаються між клієнтом та сервером, витрачений час дорівнює принаймні затримці між обома сторонами, що може бути дуже значним у випадку Wide Area Network (WAN).

SMB буфер - MaxBufferSize можна налаштувати за допомогою наступних параметрів реєстру:

HKLM\SYSTEM\CurrentControlSet\Services\LanmanServer\Parameters\SizeReqBuf

Тип даних: REG_DWORD

Діапазон: від 1024 до 65535 (Виберіть значення відповідно до вашої вимоги вище 5000)

АЛЕ SMB SIGNING впливає на максимально допустимий розмір буфера. Таким чином, нам потрібно відключити підписання SMB, а також для досягнення своєї мети. Наступний реєстр потрібно створити як на стороні сервера, так і, якщо можливо, на стороні клієнта.

HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\LanManWorkstation\Parameters

Значення значення: EnableSecuritySignature

Тип даних: REG_DWORD

Дані: 0 (відключити), 1 (включити)


Дякую за пораду; проте я спробував обидва ці засоби, і я все ще бачу вищезгадану поведінку: - /
mevatron

Ви також хочете перевірити, чому "Synology DS215j" не використовує SMB3. За замовчуванням SMB3 увімкнено у програмі Win 8.1.
Аді Джа

1

Цікаве явище. Ось що б я спробував - я поняття не маю, чи справді це допомагає. Якби це була моя машина, я б пильно спостерігав за парфумеріями SMB. Один з них буде показувати причину.

Більше спробувати

Додати більше робочих ниток

Якщо SMB_RDR завищує один запит вводу / виводу на рядок (що тут не повинно відбуватися), це може допомогти додати деякі потоки в механізм виконання.

Встановіть "AdditionalCriticalWorkerThreads" на 2, потім на 4.

HKLM\System\CurrentControlSet\Control\Session Manager\Executive\AdditionalCriticalWorkerThreads

За замовчуванням дорівнює 0, це означає, що ніяких додаткових критичних робочих ниток ядра не додано. Що зазвичай нормально. Це значення впливає на кількість потоків, які кеш файлової системи використовує для запитів, що читаються вперед та назад. Підвищення цього значення може забезпечити більше введення-виводу в чергу в підсистемі зберігання даних (що добре, коли ви хочете писати по черзі), але це дорожче процесора.

Додайте більше довжини черги

Збільшення значення "AdditionalCriticalWorkerThreads" збільшує кількість потоків, які файловий сервер може використовувати для обслуговування одночасних запитів.

HKLM\System\CurrentControlSet\Services\LanmanServer\Parameters\MaxThreadsPerQueue

За замовчуванням - 20. Вказівка ​​на те, що значення, можливо, потрібно буде збільшити, якщо робочі черги SMB2 зростають дуже великими (perfcounter 'Робочі черги сервера \ Довжина черги \ SMB2 *'. Має бути <100).

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.