SMBネットワーク共有への小さな書き込みは、Windowsでは遅く、CIFS Linuxマウントより速い


10

小さな書き込みを実行するときに、SMB / CIFS共有のパフォーマンスの問題を修正するのに苦労しています。

最初に、現在のネットワーク設定について説明します。

サーバ

  • Synology DS215j(SMB3サポートが有効)

クライアント(同じコンピューターのデュアルブート有線Gig-E)

  • Ubuntu 14.04.5 LTS、Trusty Tahr
  • ウィンドウズ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

単一のTCPパケットへの多数の行のチャンキングを示すPCAPスナップショット:

Linux PCAPスナップショット

PowerShellで測定したWindowsでのランタイムのプログラム:

> 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

Windows上のPCAPスナップショットで、SMB書き込み要求ごとに1行が表示されます。

Windows PCAPスナップショット

この同じプログラムは、Windowsでは約10分(約2.3Mbps)かかります。明らかに、Windows PCAPは、非常に低いペイロード効率で非常にノイズの多いSMB会話を示します。

小さな書き込みパフォーマンスを改善できるWindowsの設定はありますか?パケットキャプチャを見ると、Windowsは書き込みを適切にバッファリングせず、一度に1行ずつデータをすぐに送信しているようです。一方、Linuxでは、データは大量にバッファリングされるため、パフォーマンスははるかに優れています。PCAPファイルが役立つかどうか教えてください。アップロードする方法を見つけることができます。

2016年10月27日更新:

@sehafocで述べたようにmax protocol、次のようにしてSambaサーバーの設定をSMB1に減らしました。

max protocol=NT1

上記の設定では、まったく同じ動作が発生しました。

また、別のWindows 10マシンで共有を作成してSambaの変数を削除しました。また、Sambaサーバーと同じ動作をするため、これは一般にWindowsクライアントの書き込みキャッシュのバグであると考え始めています。

アップデート:10/06/17:

完全なLinuxパケットキャプチャ(14MB)

完全なWindowsパケットキャプチャ(375MB)

アップデート:10/12/17:

また、NFS共有をセットアップしましたが、Windowsでも、バッファリングなしで書き込みを行っています。ですから、私が知る限り、それは間違いなくWindowsクライアントの根本的な問題であり、これは間違いなく残念です:-/

何か助けていただければ幸いです!

回答:


2

C ++ endlは、 '\ n'に続いてフラッシュを出力するように定義されています。flush()は負荷の高い操作です。したがって、SMBだけでなく、ローカルスピンを含む高価なフラッシュを伴うあらゆるストリームで、パフォーマンスの問題が発生する可能性があるため、デフォルトの行末としてendlを使用することは通常避けてください。とんでもないほど高い出力率での錆または最新のNVMe

endlを「\ n」に置き換えると、システムが意図したとおりにバッファリングできるようになるため、上記のパフォーマンスが修正されます。一部のライブラリが「\ n」でフラッシュする可能性があることを除いて、その場合はさらに頭痛の種があります(sync()メソッドをオーバーライドするソリューションについては、https://stackoverflow.com/questions/21129162/tell-endl-not-to-flushを参照してください)。

物事を複雑にするために、flush()はライブラリバッファ内で発生することに対してのみ定義されています。オペレーティングシステム、ディスク、およびその他の外部バッファに対するフラッシュの影響は定義されていません。Microsoft.NETの場合「FileStream.Flushメソッドを呼び出すと、オペレーティングシステムのI / Oバッファーもフラッシュされます。」(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トレースは、オペレーティングシステム/ネットワークバッファーがライブラリflush()によってフラッシュされていないことを示しているようです。システムに依存する動作は、endlと過度のフラッシュを回避するためのより多くの理由になります。VC ++を使用している場合は、Windows GCC派生に切り替えてシステム依存の動作がどのように反応するかを確認するか、Wineを使用してUbuntuでWindows実行可能ファイルを実行してみてください。

より一般的には、すべての行をフラッシュすることが適切かどうかを判断するために、要件について考える必要があります。endlは一般に、ディスプレイなどのインタラクティブストリーム(バーストではなく実際に出力を確認する必要があります)に適していますが、一般に、フラッシュのオーバーヘッドが大きくなる可能性があるファイルを含む他のタイプのストリームには適していません。1、2、4、および8バイトの書き込みごとにアプリがフラッシュするのを見てきました... OSが1MBのファイルを書き込むために何百万ものIOをグラインドするのを見るのはかなり良くありません。

たとえば、クラッシュをデバッグする場合、クラッシュが発生する前にオフストリームをフラッシュする必要があるため、ログファイルですべての行をフラッシュする必要がある場合があります。一方、アプリケーションが終了する前に自動的にフラッシュされることが予想される詳細な情報ログを生成するだけの場合は、別のログファイルがすべての行をフラッシュする必要がない場合があります。特定の要件に合うように、より洗練されたフラッシュアルゴリズムを使用してクラスを派生できるので、どちらかまたは両方である必要はありません。

あなたのケースを、データがディスクに完全に永続化され、オペレーティングシステムのバッファーで脆弱ではないことを確認する必要がある人々の対照的なケースと比較してください(/programming/7522479/how-do-i-ensure-data -is-written-to-disk-before-closing-fstream)。

記述されているように、outFile.flush()はすでにフラッシュされたofstreamをフラッシュするので不要です。簡潔にするために、endlを単独で使用するか、できればoutFile.flush()で「\ n」を使用する必要がありますが、両方は使用しないでください。


どうもありがとう!あなたは100ポイント以上の価値がありますが、私が与えることができるのはそれだけです:)これは間違いなく問題でした!
mevatron 2017年

2

私はコメントを残す十分な評判がありません(この回答の検証レベルを考えると、これはより良いと思います)。

LinuxとWindowsレベルのトレースの大きな違いの1つは、LinuxでSMB1を使用し、WindowsでSMB2を使用していることです。おそらく、バッチoplockメカニズムは、SMB2排他的リース実装よりもSMB1 sambaでパフォーマンスが向上します。どちらの場合も、これらはある程度のクライアント側キャッシュを可能にするはずです。

1)SMBでウィンドウを試すために、Sambaで最大プロトコルレベルを低く設定してみてください2)排他的なoplockまたはリースが削除されていることを確認してください

お役に立てれば :)


2

SMBプロトコルを使用した読み取り/書き込みなどのリモートファイル操作のパフォーマンスは、サーバーとクライアントによって割り当てられたバッファーのサイズによって影響を受ける可能性があります。バッファサイズは、固定量のデータを送信するために必要なラウンドトリップの数を決定します。要求と応答がクライアントとサーバー間で送信されるたびに、かかる時間は少なくとも両側間の待機時間に等しく、これは広域ネットワーク(WAN)の場合は非常に重要です。

SMBバッファー-MaxBufferSizeは、次のレジストリ設定で構成できます。

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

データ・タイプ: REG_DWORD

範囲:1024〜65535(必要に応じて5000を超える値を選択してください)

BUT SMB SIGNINGは、許容される最大バッファサイズに影響します。したがって、目標を達成するには、SMB署名も無効にする必要があります。次のレジストリは、サーバー側と可能であればクライアント側の両方で作成する必要があります。

HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\LanManWorkstation\Parameters

値の名前: EnableSecuritySignature

データ・タイプ: REG_DWORD

データ:0(無効)、1(有効)


先端をありがとう; しかし、私はこれらの両方の救済策を試しましたが、それでも上記の動作が見られます:-/
mevatron

また、「Synology DS215j」がSMB3を使用していない理由も確認してください。Win 8.1では、デフォルトでSMB3が有効になっています。
Adi Jha 2016年

1

興味深い現象。これが私が試すことです-これが本当に役立つかどうかはわかりません。それが私のマシンだったとしたら、SMBパフォーマンスカウンターを広範囲にわたって監視していました。それらの1つが原因示します。

試してみるべきこと

ワーカースレッドを追加する

SMB_RDRが1行あたり1つの書き込みI / O要求を実行する場合(ここで発生しないはずです)、いくつかのスレッドを実行エンジンに追加すると役立つ場合があります。

「AdditionalCriticalWorkerThreads」を2、次に4に設定します。

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

デフォルトは0です。これは、重要なカーネルワーカースレッドが追加されないことを意味します。これは通常は大丈夫です。この値は、ファイルシステムキャッシュが先読みおよび後書き要求に使用するスレッドの数に影響します。この値を大きくすることができ、ストレージ・サブシステム(あなたが書き込みライン・バイ・ラインにしたいときには、良いです)でより多くのキューに入れられたI / Oを可能にしますが、より多くのCPU高価です。

キューの長さをさらに追加

「AdditionalCriticalWorkerThreads」の値を増やすと、ファイルサーバーが同時要求の処理に使用できるスレッドの数が増えます。

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

デフォルトは20です。この値を増やす必要があることを示すのは、SMB2ワークキューが非常に大きくなっている場合です(perfcounter 'Server Work Queues \ Queue Length \ SMB2 *'。be <100)。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.