การเขียนขนาดเล็กลงในเครือข่าย SMB จะใช้ร่วมกันบน Windows ช้ากว่าเมานต์ CIFS Linux


10

ฉันดิ้นรนเพื่อแก้ไขปัญหาด้านประสิทธิภาพด้วยการแชร์ SMB / CIFS เมื่อทำการเขียนขนาดเล็ก

ก่อนอื่นให้ฉันอธิบายการตั้งค่าเครือข่ายปัจจุบันของฉัน:

เซิร์ฟเวอร์

  • Synology DS215j (เปิดใช้งานการสนับสนุน SMB3)

ไคลเอนต์ (คอมพิวเตอร์แบบใช้สายคู่บูต Gig-E)

  • Ubuntu 14.04.5 LTS, 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 mount:

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

โปรแกรมรันไทม์บน Linux (เอาต์พุตเครือข่าย peaks ที่ ~ 100Mbps):

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

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

PCAP snapshot แสดงการดึงข้อมูลหลาย ๆ บรรทัดลงใน TCP แพ็กเก็ตเดียว:

Linux PCAP snapshot

โปรแกรมรันไทม์บน 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 snapshot บน Windows แสดงบรรทัดเดียวตามคำขอเขียน SMB:

Windows PCAP snapshot

โปรแกรมเดียวกันนี้ใช้เวลาประมาณ 10 นาที (~ 2.3Mbps) บน Windows เห็นได้ชัดว่า PCAP ของ Windows แสดงบทสนทนา SMB ที่มีเสียงดังมากพร้อมประสิทธิภาพในการโหลดข้อมูลที่ต่ำมาก

มีการตั้งค่าใด ๆ บน Windows ที่สามารถปรับปรุงประสิทธิภาพการเขียนขนาดเล็กได้หรือไม่? ดูเหมือนว่าจากการดูที่การจับแพ็คเก็ตนั้น Windows ไม่ได้บัฟเฟอร์การเขียนอย่างถูกต้องและจะส่งข้อมูลทีละหนึ่งบรรทัดทันที ในขณะที่บน Linux ข้อมูลถูกบัฟเฟอร์อย่างหนักและมีประสิทธิภาพที่เหนือกว่า แจ้งให้เราทราบว่าไฟล์ PCAP จะมีประโยชน์หรือไม่และฉันสามารถหาวิธีอัปโหลดได้

อัปเดต 10/27/16:

ตามที่กล่าวไว้โดย @sehafoc ฉันได้ลดการmax protocolตั้งค่าเซิร์ฟเวอร์ Samba เป็น SMB1 ด้วยสิ่งต่อไปนี้:

max protocol=NT1

การตั้งค่าด้านบนส่งผลให้มีพฤติกรรมเดียวกัน

ฉันยังลบตัวแปรของ Samba ด้วยการสร้างการแชร์บนเครื่อง Windows 10 อีกเครื่องและมันก็แสดงพฤติกรรมเช่นเดียวกับเซิร์ฟเวอร์ 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" ซึ่งในกรณีนี้คุณจะมีอาการปวดหัวมากขึ้น (ดู/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 และ flushing มากเกินไป หากคุณกำลังใช้ VC ++ คุณอาจลองเปลี่ยนมาใช้อนุพันธ์ Windows GCC เพื่อดูว่าพฤติกรรมการพึ่งพาระบบมีปฏิกิริยาอย่างไรหรือใช้ Wine เพื่อรันโปรแกรมปฏิบัติการ Windows บน Ubuntu

โดยทั่วไปคุณต้องคิดถึงความต้องการของคุณเพื่อพิจารณาว่าการล้างข้อมูลทุกบรรทัดนั้นเหมาะสมหรือไม่ โดยทั่วไปแล้ว endl นั้นเหมาะสมสำหรับสตรีมแบบอินเทอร์แอคทีฟเช่นจอแสดงผล (เราต้องการให้ผู้ใช้เห็นจริง ๆ ว่าเอาต์พุตของเราและไม่ออกมาเป็นระเบิด) แต่โดยทั่วไปไม่เหมาะสำหรับสตรีมประเภทอื่น ๆ รวมถึงไฟล์ ฉันเคยเห็นแอพพลิเคชั่นล้างทุก 1 และ 2 และ 4 และ 8 ไบต์เขียน ... มันไม่สวยเลยที่ระบบปฏิบัติการจะใช้งาน iOS นับล้านเพื่อเขียนไฟล์ 1MB

ตัวอย่างเช่นไฟล์บันทึกอาจต้องล้างข้อมูลทุกบรรทัดหากคุณทำการดีบักข้อขัดข้องเนื่องจากคุณจำเป็นต้องล้างข้อมูลของกระแสก่อนที่จะเกิดข้อผิดพลาด ในขณะที่ไฟล์บันทึกอื่นอาจไม่จำเป็นต้องล้างข้อมูลทุกบรรทัดหากไฟล์นั้นเป็นเพียงการสร้างบันทึกข้อมูลที่ละเอียดซึ่งคาดว่าจะล้างข้อมูลโดยอัตโนมัติก่อนที่แอปพลิเคชันจะยุติ ไม่จำเป็นต้องเป็น / หรือตามที่คุณสามารถหาคลาสด้วยอัลกอริทึมแบบฟลัชที่ซับซ้อนยิ่งขึ้นเพื่อให้เหมาะกับความต้องการเฉพาะ

เปรียบเทียบเคสของคุณกับเคสที่ตัดกันของผู้ที่ต้องการให้แน่ใจว่าข้อมูลของพวกเขายังคงอยู่ในดิสก์อย่างสมบูรณ์และไม่เสี่ยงต่อการบัฟเฟอร์ระบบปฏิบัติการ ( /programming/7522479/how-do-i-ensure-data) -is- เขียนไปยังดิสก์ก่อนปิด fstream )

โปรดทราบว่าตามที่เขียนไว้ outFile.flush () จะฟุ่มเฟือยตามที่ได้ทำการล้างของกระแสที่ล้างออกแล้ว หากต้องการเป็นคนหยาบคายคุณควรใช้ endl เพียงอย่างเดียวหรือดีกว่า "\ n" กับ outFile.flush () แต่ไม่ใช่ทั้งสองอย่าง


ขอบคุณหนึ่งล้าน! คุณสมควรได้รับคะแนนมากกว่า 100 คะแนน แต่นั่นคือทั้งหมดที่ฉันสามารถให้ได้ :) นี่เป็นปัญหาอย่างแน่นอน!
mevatron

2

ฉันมีชื่อเสียงไม่มากพอที่จะแสดงความคิดเห็น (ซึ่งฉันคิดว่าน่าจะดีกว่าหากได้รับการยืนยันในคำตอบนี้)

ฉันสังเกตเห็นว่าการเปลี่ยนแปลงระดับใหญ่อย่างหนึ่งในการติดตามระดับ Linux กับ Windows ของคุณคือคุณกำลังใช้ SMB1 บน Linux และ SMB2 ใน Windows บางทีกลไกการทำงานของแบตช์จะทำงานได้ดีกว่าในแซมบ้าของ SMB1 มากกว่าการติดตั้งแบบเอกสิทธิ์ของ SMB2 ในทั้งสองกรณีสิ่งเหล่านี้ควรอนุญาตสำหรับการแคชฝั่งไคลเอ็นต์จำนวนหนึ่ง

1) บางทีลองตั้งค่าระดับสูงสุดของโพรโทคอลที่ต่ำกว่าใน Samba เพื่อทดลองใช้ Windows ด้วย SMB1 2) ตรวจสอบว่ามีการใช้ oplocks หรือสัญญาเช่าแบบเอกสิทธิ์เฉพาะบุคคล

หวังว่าจะช่วย :)


2

ประสิทธิภาพของการทำงานของไฟล์ระยะไกลเช่นการอ่าน / เขียนโดยใช้โปรโตคอล SMB อาจได้รับผลกระทบจากขนาดของบัฟเฟอร์ที่จัดสรรโดยเซิร์ฟเวอร์และไคลเอนต์ ขนาดบัฟเฟอร์กำหนดจำนวนรอบการเดินทางที่จำเป็นในการส่งข้อมูลจำนวนคงที่ ทุกครั้งที่คำขอและการตอบสนองถูกส่งระหว่างไคลเอนต์และเซิร์ฟเวอร์ระยะเวลาที่ใช้จะเท่ากับเวลาอย่างน้อย latency ระหว่างทั้งสองฝั่งซึ่งอาจมีความสำคัญมากในกรณีของ Wide Area Network (WAN)

SMB buffer - MaxBufferSize สามารถกำหนดค่าผ่านการตั้งค่ารีจิสทรีต่อไปนี้:

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

ประเภทข้อมูล: REG_DWORD

ช่วง: 1024 ถึง 65535 (เลือกค่าตามความต้องการของคุณมากกว่า 5,000)

แต่ SMB SIGNING มีผลต่อขนาดบัฟเฟอร์สูงสุดที่อนุญาต ดังนั้นเราจึงจำเป็นต้องปิดการใช้งานการลงลายมือชื่อใน 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 หนึ่งรายการต่อบรรทัด (สิ่งที่ไม่ควรเกิดขึ้นที่นี่) อาจช่วยเพิ่มเธรดบางตัวในเอ็นจินการเรียกใช้งานได้

ตั้งค่า "ExtraCriticalWorkerThreads" เป็น 2 จากนั้นเป็น 4

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

ค่าเริ่มต้นคือ 0 ซึ่งหมายความว่าจะไม่มีการเพิ่มเธรดตัวทำงานเคอร์เนลที่สำคัญเพิ่มเติม ซึ่งปกติแล้วก็โอเค ค่านี้มีผลต่อจำนวนเธรดที่แคชระบบไฟล์ใช้สำหรับการร้องขอเพื่ออ่านล่วงหน้าและการเขียนด้านหลัง การเพิ่มค่านี้สามารถอนุญาตให้ I / O ที่เข้าคิวได้มากขึ้นในระบบย่อยหน่วยเก็บข้อมูล (ซึ่งดีเมื่อคุณต้องการเขียนทีละบรรทัด) แต่ CPU มีราคาแพงกว่า

เพิ่มความยาวของคิว

การเพิ่มค่า "ExtraCriticalWorkerThreads" จะเพิ่มจำนวนเธรดที่เซิร์ฟเวอร์ไฟล์สามารถใช้เพื่อให้บริการคำร้องขอพร้อมกัน

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.