SMB 네트워크 공유에 대한 소규모 쓰기는 Windows에서 느리고 CIFS Linux 마운트보다 빠릅니다.


10

작은 쓰기를 수행 할 때 SMB / CIFS 공유의 성능 문제를 해결하기 위해 고심하고 있습니다.

먼저 현재 네트워크 설정을 설명하겠습니다.

섬기는 사람

  • Synology DS215j (SMB3 지원 사용)

클라이언트 (동일 컴퓨터 이중 부팅 유선 Gig-E)

  • 우분투 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;
}

리눅스 마운트 구성 :

//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 스냅 샷 :

리눅스 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

SMB 쓰기 요청 당 한 줄을 표시하는 Windows의 PCAP 스냅 샷 :

Windows PCAP 스냅 샷

이 같은 프로그램은 Windows에서 약 10 분 (~ 2.3Mbps)이 걸립니다. 분명히, Windows PCAP는 페이로드 효율이 매우 낮은 잡음이 많은 SMB 대화를 보여줍니다.

작은 쓰기 성능을 향상시킬 수있는 Windows 설정이 있습니까? 패킷 캡처를 보면 Windows가 쓰기를 올바르게 버퍼링하지 않고 한 번에 한 줄씩 데이터를 즉시 보냅니다. 반면 Linux에서는 데이터가 많이 버퍼링되므로 성능이 훨씬 뛰어납니다. PCAP 파일이 도움이되는지 알려 주시면 업로드 방법을 찾을 수 있습니다.

10/27/16 업데이트 :

@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 ()는 비용이 많이 드는 작업이므로 일반적으로 endl을 기본 줄 끝으로 사용하지 않아야합니다. 이는 SMB뿐만 아니라 로컬 회전을 포함하여 값 비싼 플러시가있는 스트림과 정확하게 일치하는 성능 문제를 야기 할 수 있기 때문입니다. 엄청나게 높은 출력 속도에서 녹 또는 최신 NVMe).

endl을 "\ n"으로 바꾸면 시스템이 의도 한대로 버퍼링되도록하여 위의 성능을 수정합니다. 일부 라이브러리는 "\ n"에서 플러시 될 수 있습니다.이 경우 더 많은 두통이 있습니다 ( sync () 메서드를 재정의하는 솔루션에 대해서는 /programming/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 ++를 사용하는 경우 시스템 종속 동작이 어떻게 반응하는지 또는 다른 방법으로 Wine을 사용하여 Ubuntu에서 Windows 실행 파일을 실행하는 방법을보기 위해 Windows GCC 파생물로 전환 할 수 있습니다.

보다 일반적으로 모든 라인 세척이 적절한 지 여부를 결정하기 위해 요구 사항을 고려해야합니다. endl은 일반적으로 디스플레이와 같은 대화 형 스트림에 적합하지만 (버스트가 아닌 실제로 출력을 볼 필요가 있음), 일반적으로 플러싱 오버 헤드가 중요한 파일을 포함한 다른 유형의 스트림에는 적합하지 않습니다. 1 및 2 및 4 및 8 바이트 쓰기마다 앱이 플러시되는 것을 보았습니다 ... OS가 1MB 파일을 작성하기 위해 수백만 IO를 분쇄하는 것은 그리 좋지 않습니다.

예를 들어 충돌이 발생하기 전에 ofstream을 플러시해야하기 때문에 충돌을 디버깅하는 경우 로그 파일이 모든 행을 플러시해야합니다. 응용 프로그램이 종료되기 전에 자동으로 플러시 될 자세한 정보 로깅 만 생성하는 경우 다른 로그 파일이 모든 행을 플러시 할 필요는 없습니다. 특정 요구 사항에 맞게보다 정교한 플러시 알고리즘을 사용하여 클래스를 파생시킬 수 있으므로 / 또는 필요하지 않습니다.

데이터가 디스크에 완전히 유지되고 운영 체제 버퍼에 취약하지 않은지 확인하는 사람들의 경우와 대조 하십시오 ( https : //.com/questions/7522479/how-do-i-ensure-data -is-write-to-disk-before-closing-fstream )입니다.

작성된 것처럼 outFile.flush ()는 이미 플러시 된 스트림을 플러시하므로 불필요합니다. pedantic하려면 endFile을 단독으로 사용하거나 outFile.flush ()와 함께 "\ n"을 사용해야하지만 둘 다 사용하지 않아야합니다.


정말 고마워! 당신은 100 점 이상을 가치가 있지만, 그것이 내가 줄 수있는 전부입니다 :) 이것은 분명히 문제였습니다!
mevatron

2

의견을 남길만한 명성이 없습니다 (이 답변에 대한 검증 수준이 더 좋을 것이라고 생각합니다).

Linux와 Windows 수준 추적 간의 큰 차이는 Linux에서 SMB1을 사용하고 Windows에서 SMB2를 사용한다는 것입니다. 아마도 배치 oplock 메커니즘은 SMB2 독점 임대 구현보다 SMB1 삼바에서 더 잘 수행됩니다. 두 경우 모두 클라이언트 측 캐싱을 어느 정도 허용해야합니다.

1) 아마도 SMB1을 사용하여 창을 시험해보기 위해 삼바에서 더 낮은 최대 프로토콜 레벨을 설정하십시오. 2) 독점 oplock 또는 임대가 제거되었는지 확인하십시오.

도움이 되었기를 바랍니다 :)


2

SMB 프로토콜을 사용한 읽기 / 쓰기와 같은 원격 파일 작업의 성능은 서버 및 클라이언트가 할당 한 버퍼 크기에 영향을받을 수 있습니다. 버퍼 크기는 고정 된 양의 데이터를 전송하는 데 필요한 왕복 횟수를 결정합니다. 클라이언트와 서버간에 요청과 응답이 전송 될 때마다 걸리는 시간은 최소한 양측 간의 대기 시간과 같으며 WAN (Wide Area Network)의 경우 매우 중요 할 수 있습니다.

SMB 버퍼-MaxBufferSize는 다음 레지스트리 설정을 통해 구성 할 수 있습니다.

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

데이터 형식: REG_DWORD

범위 : 1024 ~ 65535 (5000 이상 요구 사항에 따라 값 선택)

그러나 SMB 서명은 허용 된 최대 버퍼 크기에 영향을줍니다. 따라서 목표를 달성하기 위해 SMB 서명을 비활성화해야합니다. 서버 측과 가능하면 클라이언트 측에서도 다음 레지스트리를 작성해야합니다.

HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\LanManWorkstation\Parameters

값 이름 : EnableSecuritySignature

데이터 형식: REG_DWORD

데이터 : 0 (비활성화), 1 (활성화)


팁 고마워; 그러나이 두 가지 치료법을 모두 시도했지만 여전히 위의 동작을보고 있습니다 :-/
mevatron

"Synology DS215j"가 SMB3를 사용하지 않는 이유를 확인하고 싶습니다. 기본적으로 SMB3은 Win 8.1에서 사용됩니다.
Adi Jha

1

재미있는 현상. 여기에 내가 시도 할 것이 있습니다-이것이 정말로 도움이되는지 모르겠습니다. 그것이 나의 기계라면, 나는 SMB perfcounters를 광범위하게 볼 것입니다. 그들 중 하나가 원인 보여줄 것 입니다 .

더 시도해야 할 것들

더 많은 작업자 스레드 추가

경우에 SMB_RDR 하나 개의 쓰기 I / 줄에 O 요청을 (해야 무슨 obens 하지 여기 일이), 수 있습니다 실행 엔진에 약간의 스레드를 추가하는 데 도움이됩니다.

"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 *'. <100).

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.