GNU/Linux >> Znalost Linux >  >> Linux

Malé zápisy do síťového sdílení SMB jsou pomalé ve Windows, rychlé přes CIFS Linux mount

C++ endl je definován jako výstup '\n' následovaný vyprázdněním. flush() je drahá operace, takže byste se měli obecně vyhnout použití endl jako výchozího konce řádku, protože může způsobit přesně ten problém s výkonem, který vidíte (a to nejen u SMB, ale u jakéhokoli ofstream s drahým flushem včetně místního spinningu rez nebo dokonce nejnovější NVMe při nějaké směšně vysoké rychlosti výstupu).

Nahrazení endl za "\n" opraví výše uvedený výkon tím, že umožní systému vyrovnávací paměť, jak bylo zamýšleno. Až na to, že některé knihovny se mohou na "\n" vyprázdnit, v takovém případě budete mít větší bolesti hlavy (viz https://stackoverflow.com/questions/21129162/tell-endl-not-to-flush, kde najdete řešení, které přepíše metodu sync() ).

Abychom to zkomplikovali, flush() je definována pouze pro to, co se děje v rámci vyrovnávacích pamětí knihovny. Vliv vyprázdnění na operační systém, disk a další externí vyrovnávací paměti není definován. Pro Microsoft.NET "Když zavoláte metodu FileStream.Flush, dojde také k vyprázdnění I/O vyrovnávací paměti operačního systému." (https://msdn.microsoft.com/en-us/library/2bw4h516(v=vs.110).aspx) Díky tomu je flush zvláště drahý pro Visual Studio C++, protože to zopakuje zápis až do fyzického média na vzdáleném konci vašeho vzdáleného serveru, jak vidíte. GCC na druhé straně říká:"Poslední připomenutí:obvykle se jedná o více vyrovnávacích pamětí než jen ty na úrovni jazyka/knihovny. Vyrovnávací paměti jádra, vyrovnávací paměti disku a podobně budou mít také vliv. Kontrola a změna těchto vyrovnávacích pamětí závisí na systému ." (https://gcc.gnu.org/onlinedocs/libstdc++/manual/streambufs.html) Zdá se, že vaše stopy Ubuntu naznačují, že vyrovnávací paměti operačního systému / sítě nejsou vyprázdněny knihovnou flush(). Chování závislé na systému by bylo tím větším důvodem, proč se vyhnout nadměrnému endl a splachování. Pokud používáte VC++, můžete zkusit přejít na derivát Windows GCC, abyste viděli, jak reagují chování závislé na systému, nebo alternativně použít Wine ke spuštění spustitelného souboru Windows na Ubuntu.

Obecněji se musíte zamyslet nad svými požadavky, abyste zjistili, zda je proplachování každého řádku vhodné nebo ne. endl je obecně vhodný pro interaktivní streamy, jako je displej (potřebujeme, aby uživatel skutečně viděl náš výstup, a ne v dávkách), ale obecně není vhodný pro jiné typy streamů včetně souborů, kde může být významná režie splachování. Viděl jsem, jak se aplikace vyprázdní při každém zápisu 1 a 2 a 4 a 8 bajtů... není hezké vidět, jak OS drtí miliony IO, aby zapsal 1 MB soubor.

Například soubor protokolu může vyžadovat vyprázdnění každého řádku, pokud ladíte selhání, protože potřebujete vyprázdnit ofstream předtím, než dojde k selhání; zatímco jiný soubor protokolu nemusí vyprázdnit každý řádek, pokud pouze vytváří podrobné informační protokolování, u kterého se očekává, že se automaticky vyprázdní před ukončením aplikace. Nemusí to být buď/nebo, protože byste mohli odvodit třídu se sofistikovanějším flush algoritmem, který by vyhovoval specifickým požadavkům.

Porovnejte svůj případ s kontrastním případem lidí, kteří potřebují zajistit, aby jejich data byla zcela uložena na disku a nebyla zranitelná ve vyrovnávací paměti operačního systému (https://stackoverflow.com/questions/7522479/how-do-i-ensure-data -je-zapsáno-na-disk-před uzavřením-fstream).

Všimněte si, že jak je napsáno, outFile.flush() je nadbytečné, protože vyprázdní již vyprázdněný proud. Abyste byli pedantští, měli byste použít samotný endl nebo nejlépe "\n" s outFile.flush(), ale ne obojí.


Výkon operací se vzdálenými soubory, jako je čtení/zápis pomocí protokolu SMB, může být ovlivněn velikostí vyrovnávacích pamětí přidělených servery a klienty. Velikost vyrovnávací paměti určuje počet zpátečních cest potřebných k odeslání pevného množství dat. Pokaždé, když jsou požadavky a odpovědi posílány mezi klientem a serverem, doba potřebná k tomu se rovná přinejmenším latenci mezi oběma stranami, což může být velmi významné v případě Wide Area Network (WAN).

Vyrovnávací paměť SMB – MaxBufferSize lze konfigurovat pomocí následujícího nastavení registru:

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

Typ dat:REG_DWORD

Rozsah:1024 až 65535 (Vyberte hodnotu podle svého požadavku nad 5000)

ALE SMB SIGNING ovlivňuje maximální povolenou velikost vyrovnávací paměti. Abychom dosáhli našeho cíle, musíme také zakázat podepisování SMB. Následující registr musí být vytvořen na straně serveru a pokud možno také na straně klienta.

HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\LanManWorkstation\Parameters

Název hodnoty:EnableSecuritySignature

Typ dat:REG_DWORD

Data:0 (zakázat), 1 (povolit)


Nemám dostatečnou pověst, abych mohl zanechat komentář (což si myslím, že by bylo lepší vzhledem k úrovni ověření této odpovědi).

Všiml jsem si, že jedna velká odchylka ve vašem trasování na úrovni Linuxu a Windows je, že používáte SMB1 v Linuxu a SMB2 ve Windows. Možná, že dávkový oplock mechanismus funguje v SMB1 sambě lépe než implementace exkluzivního pronájmu SMB2. V obou případech by to mělo umožňovat určité množství mezipaměti na straně klienta.

1) Možná zkuste nastavit nižší maximální úroveň protokolu v Sambě, abyste vyzkoušeli okna s SMB12) Ověřte, že jsou uzavřeny exkluzivní oplocky nebo leasingy

Doufám, že to pomůže :)


Linux
  1. Jak vytvořit síťové sdílení přes Samba na Linuxu

  2. Jak připojit vzdálené sdílení Windows v systému Linux

  3. Jak udělat Cifs/smb Mount Ignore Umask?

  1. Odpojení sdílené složky Windows v systému Linux se nezdaří

  2. Zkopírujte soubor z linuxu do sdílení systému Windows pomocí C# (jádro .NET)

  3. Jak zobrazit seznam všech souborů ve sdílené síťové složce Windows SMB

  1. Debian – Cifs náhodně ztrácí připojení k Windows Share?

  2. Linux – Mount Cifs Network Drive:Oprávnění k zápisu a Chown?

  3. připojit vzdálené sdílení oken z centos