web-dev-qa-db-fra.com

Petits écrit sur SMB Le partage réseau est lent sur Windows, rapide sur le montage Linux CIFS

Je me suis battu pour résoudre un problème de performance avec une action SMB/CIFS lors de l'exécution de petites écritures.

Tout d'abord, laissez-moi décrire ma configuration de réseau actuelle:

serveur

  • Synology DS215J (avec support SMB3 activé)

CLIENTS (MÊME Ordinateur Dual-Bootd 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

Je teste actuellement les petites performances d'écriture avec le programme suivant écrit en C++ (sur GitHub ici ):

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

Configuration du montage Linux:

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

Temps d'exécution du programme sur Linux (sortie de réseau pics à ~ 100 Mbps):

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

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

Snapshot PCAP montrant des morceaux de nombreuses lignes en un seul TCP paquet:

Linux PCAP snapshot

Temps d'exécution du programme sous Windows, mesuré par 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

Snapshot PCAP sous Windows montrant une ligne unique par SMB Demande d'écriture:

Windows PCAP snapshot

Ce même programme prend environ 10 minutes (~ 2,3 Mbps) sous Windows. De toute évidence, la PCAP Windows montre un très bruyant SMB avec une très faible efficacité de la charge utile.

Y a-t-il des paramètres sur Windows qui peuvent améliorer les petites performances d'écriture? Il semble de regarder des captures de paquets que Windows ne tamponnez pas correctement et envoie immédiatement les données une ligne à la fois. Alors que, sous Linux, les données sont fortement tamponnées et ont ainsi une performance de loin supérieure. Faites-moi savoir si les fichiers PCAP seraient utiles et je peux trouver un moyen de les télécharger.

Mise à jour 10/27/16:

Comme mentionné par @sehafoc, j'ai réduit les serveurs Samba max protocol Réglage sur SMB1 avec ce qui suit:

max protocol=NT1

Le paramètre ci-dessus a abouti au même comportement.

J'ai également supprimé la variable de Samba en créant une part sur une autre machine Windows 10, et elle présente également le même comportement que le serveur Samba, donc je commence à croire qu'il s'agit d'un bogue de mise en cache en écriture avec des clients Windows en général.

Mise à jour: 10/06/17:

Capture de paquets Linux complète (14 Mo

Capture de paquets Full Windows (375MB)

Mise à jour: 10/12/17:

Je configurais également une part NFS et Windows écrit sans tampon pour cela aussi. Donc, c'est certainement un problème de client Windows sous-jacent aussi loin que possible, ce qui est définitivement malheureux: - /

Toute aide serait appréciée!

10
mevatron

Le C++ endl est défini sur la sortie '\ n' suivie d'une rinçage. Flush () est une opération coûteuse, vous devriez donc éviter d'utiliser Endl comme fin de ligne par défaut, car il peut créer exactement le problème de performance que vous voyez (et non seulement avec SMB, mais avec n'importe lequel avec une flush chère, y compris la filature locale. Rust ou même la dernière NVME à un taux de production ridiculement élevé).

Le remplacement de l'ENDL avec "\ N" corrigera les performances ci-dessus en permettant au système de tamponner comme prévu. Sauf que certaines bibliothèques peuvent affleurer "\ n", auquel cas vous avez plus de maux de tête (voir https://stackoverflow.com/questions/21129162/tell-endl-not-a-flush pour un solution remplace la méthode Sync ()).

Maintenant, pour compliquer les choses, Flush () n'est définie que pour ce qui se passe dans les tampons de la bibliothèque. L'effet de flush sur le système d'exploitation, le disque et d'autres tampons externes n'est pas défini. Pour Microsoft.net "Lorsque vous appelez la méthode filtream.flush, le tampon d'E/S système d'exploitation est également rincé." (- https://msdn.microsoft.com/en-us/library/2bw4h516 (v = vs.110) .aspx ) Ceci fait rincer particulièrement cher pour Visual Studio C++, car il va aller L'Écrivez toutes les sorties sur le support physique à l'extrémité extrême de votre serveur distant comme vous le voyez. GCC de l'autre montre "Un dernier rappel: Il y a généralement plus de tampons impliqués que ceux du niveau de langue/bibliothèque. Les tampons de noyau, les tampons de disque, etc. auront également un effet. Inspecter et modifier ceux-ci sont dépendants du système . " (- https://gcc.gnu.org/onlinedocs/libstdc++/manual/streambufs.html ) Vos traces Ubuntu sembleraient indiquer que les tampons de système d'exploitation/réseau ne sont pas rougrés par la bibliothèque Flush ( ). Le comportement dépendant du système serait d'autant plus de raisons d'éviter l'endl et de rincer excessivement. Si vous utilisez VC++, vous pouvez essayer de passer à une dérivée Windows GCC pour voir comment les comportements dépendants du système réagissent ou utilisent alternativement le vin pour exécuter l'exécutable Windows sur Ubuntu.

Plus généralement, vous devez réfléchir à vos besoins pour déterminer si une rinçage chaque ligne est appropriée ou non. Endl convient généralement aux flux interactifs tels que l'affichage (nous avons besoin de l'utilisateur pour voir notre sortie, et non dans des rafales), mais ne convient généralement pas à d'autres types de flux, y compris des fichiers où la surcharge de rinçage peut être importante. J'ai vu des applications affleurantes sur tous les 1 et 2 et 4 et 8 octets écrit ... Ce n'est pas joli de voir le système d'exploitation grinçant des millions d'iOS à écrire un fichier de 1 Mo.

À titre d'exemple, un fichier journal peut avoir besoin de rincer toutes les lignes si vous déboguez un crash car vous devez rincer l'OFEAM avant que le crash ne se produise; tandis qu'un autre fichier journal peut ne pas avoir besoin de rincer toutes les lignes s'il ne s'agit que de produire une journalisation d'information verbeuse qui devrait être affleuré automatiquement avant que l'application se termine. Il n'est pas nécessaire de ne pas être ni/ou comme vous pouvez tirer une classe avec un algorithme de chasse plus sophistiqué pour répondre aux exigences spécifiques.

Comparez votre cas avec le cas contrastant des personnes qui ont besoin de garantir que leurs données sont complètement persistées au disque et non vulnérables dans un tampon de système d'exploitation ( https://stackoverflow.com/questions/7522479/how-do-i -Sursure-data-is-écrit-de-disque-avant-ferme-frestream ).

Notez que comme écrit, Outfile.Flush () est superflu alors qu'il glisse un déjà rouginé. Pour être pédant, vous auriez dû être utilisé seul ou de préférence "\ n" avec Outfile.Flush () mais pas les deux.

2
Doug

La performance des opérations de fichier distant, telles que la lecture/écriture, l'utilisation SMB Protocol peut être affectée par la taille des tampons alloués par des serveurs et des clients. La taille de la mémoire tampon détermine le nombre de voyages ronds nécessaires à envoyer une quantité fixe de données. Chaque fois que lorsque les demandes et les réponses sont envoyées entre client et serveur, le temps pris est égal à au moins la latence entre les deux côtés, qui pourrait être très significative dans le cas d'un réseau étendu (WAN ).

Buffer SMB - Le maxbufferSize peut être configuré via le paramètre de registre suivant:

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

Type de données: REG_DWORD

Plage: 1024 à 65535 (Choisissez la valeur selon vos besoins supérieurs à 5000)

Mais SMB Effets de la signature La taille tampon maximale autorisée. Ainsi, nous devons désactiver SMB SIGNATION également à Aechieve Notre objectif. Vous devez créer à la fois que le registre doit être créé sur les deux côté serveur et si possible sur le côté client aussi.

HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\LanManWorkstation\Parameters

Nom de la valeur: EnableSecuritySignature

Type de données: REG_DWORD

Données: 0 (Désactiver), 1 (Activer)

2
Adi Jha

Je n'ai pas assez de réputation pour laisser un commentaire (ce que je pense serait mieux compte tenu du niveau de vérification de cette réponse).

Je remarque qu'une grande variance de votre trace de niveau Windows Linux vs est que vous utilisez SMB1 sur Linux et SMB2 dans Windows. Peut-être que le mécanisme de lot Opplock fonctionne mieux dans SMB1 Samba que la mise en œuvre du bail exclusif SMB2. Dans les deux cas, ceux-ci devraient permettre une certaine quantité de la mise en cache latérale du client.

1) Peut-être essayez peut-être de définir un niveau de protocole maximum inférieur dans Samba pour essayer Windows avec SMB1 2) Valider que les OPLOCs ou les locations exclusifs sont supprimés.

J'espère que cela t'aides :)

2
sehafoc

Phénomène intéressant. Voici ce que j'essaierais - je n'ai aucune idée si cela aide vraiment. Si c'était ma machine, je regarderais largement le SMB perfcounters. L'un d'eux sera montrent la cause.

Plus de choses à essayer

ajoutez plus de threads de travailleur

Si le SMB_RRDR obense une demande d'E/S d'Ecrire une demande d'E/S par ligne (quel devrait non arriver ici), il May Aide à ajouter des threads au moteur d'exécution.

Définissez "Travaliers supplémentaires" à 2, puis à 4.

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

La valeur par défaut est 0, ce qui signifie qu'aucun thread de travailleur de noyau critique supplémentaire n'est ajouté. Qui est habituellement ok. Cette valeur affecte le nombre de threads que le cache de système de fichiers utilise pour les demandes de lecture-avance et d'écriture. Élever cette valeur peut permettre d'autoriser plus d'E/S en file d'attente dans le sous-système de stockage (qui est bon, lorsque vous souhaitez écrire la ligne de ligne), Mais c'est plus cher CPU.

ajoutez plus de longueur de la queue

L'augmentation de la valeur "supplémentaireCriticalworkerTheads" soulève le nombre de threads que le serveur de fichiers peut utiliser pour servir simultanément .

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

La valeur par défaut est 20. Une indication que la valeur peut avoir besoin d'être augmentée est si les files d'attente de travail SMB2 augmentent de très volumineuses (la longueur des files d'attente du serveur de perfcanter\file d'attente\SMB2 * '. Devrait être <100).

1
bjoster