Tulisan kecil untuk berbagi jaringan SMB lambat pada Windows, lebih cepat dari mount CIFS Linux

10

Saya telah berjuang untuk memperbaiki masalah kinerja dengan pangsa SMB / CIFS saat melakukan penulisan kecil.

Pertama, izinkan saya menjelaskan pengaturan jaringan saya saat ini:

Server

  • Synology DS215j (dengan dukungan SMB3 diaktifkan)

Klien (komputer yang sama dual-booted kabel 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

Saat ini saya sedang menguji kinerja penulisan kecil dengan program berikut yang ditulis dalam C ++ (di GitHub di sini ):

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

Konfigurasi pemasangan Linux:

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

Program run-time di Linux (puncak output jaringan pada ~ 100Mbps):

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

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

Snapshot PCAP yang menunjukkan pemotongan banyak baris menjadi satu paket TCP:

Linux PCAP snapshot

Program run-time di Windows yang diukur dengan 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 di Windows yang menunjukkan satu baris per SMB Tulis Permintaan:

Cuplikan PCAP Windows

Program yang sama ini memakan waktu sekitar 10 menit (~ 2.3Mbps) di Windows. Jelas, PCAP Windows menunjukkan percakapan SMB yang sangat bising dengan efisiensi payload yang sangat rendah.

Apakah ada pengaturan pada Windows yang dapat meningkatkan kinerja penulisan kecil? Tampaknya dari melihat tangkapan paket bahwa Windows tidak buffer menulis dengan benar dan segera mengirimkan data satu baris pada suatu waktu. Padahal, di Linux, data sangat buffered dan dengan demikian memiliki kinerja yang jauh lebih unggul. Beri tahu saya jika file PCAP akan membantu, dan saya dapat menemukan cara untuk mengunggahnya.

Perbarui 10/27/16:

Seperti yang disebutkan oleh @sehafoc, saya mengurangi max protocolpengaturan server Samba ke SMB1 dengan yang berikut ini:

max protocol=NT1

Pengaturan di atas menghasilkan perilaku yang sama persis.

Saya juga menghapus variabel Samba dengan membuat share di mesin Windows 10 lainnya, dan juga menunjukkan perilaku yang sama dengan server Samba, jadi saya mulai percaya ini adalah bug caching tulis dengan klien Windows pada umumnya.

Pembaruan: 10/06/17:

Pengambilan paket Linux penuh (14MB)

Pengambilan paket Windows penuh (375MB)

Pembaruan: 10/12/17:

Saya juga mengatur berbagi NFS dan Windows tidak menulis tanpa buffering untuk ini juga. Jadi, ini jelas merupakan masalah klien Windows yang mendasarinya sejauh yang saya tahu, yang pasti disayangkan: - /

Bantuan apa pun akan dihargai!

mevatron
sumber

Jawaban:

2

C ++ endl didefinisikan ke output '\ n' diikuti oleh flush. flush () adalah operasi yang mahal, jadi Anda biasanya harus menghindari menggunakan endl sebagai garis akhir default Anda karena dapat membuat masalah kinerja yang Anda lihat (dan tidak hanya dengan SMB, tetapi dengan sembarang aliran dengan flush yang mahal termasuk pemintalan lokal) karat atau bahkan NVMe terbaru pada tingkat output yang sangat tinggi).

Mengganti endl dengan "\ n" akan memperbaiki kinerja di atas dengan membiarkan sistem melakukan buffer sebagaimana dimaksud. Kecuali beberapa perpustakaan mungkin menggunakan "\ n", dalam hal ini Anda mengalami sakit kepala lebih lanjut (lihat /programming/21129162/tell-endl-not-to-flush untuk solusi yang menimpa metode sinkronisasi () ).

Sekarang untuk mempersulit, flush () hanya didefinisikan untuk apa yang terjadi di dalam buffer perpustakaan. Efek flush pada sistem operasi, disk, dan buffer eksternal lainnya tidak ditentukan. Untuk Microsoft.NET "Ketika Anda memanggil metode FileStream.Flush, buffer sistem I / O operasi juga memerah." ( https://msdn.microsoft.com/en-us/library/2bw4h516(v=vs.110).aspx ) Ini membuat flush sangat mahal untuk Visual Studio C ++ karena akan melengkapi perjalanan penulisan hingga media fisik di ujung server jauh seperti yang Anda lihat. GCC di sisi lain mengatakan "Pengingat terakhir: biasanya ada lebih banyak buffer yang terlibat daripada hanya pada tingkat bahasa / perpustakaan. Buffer kernel, buffer disk, dan sejenisnya juga akan memiliki efek. Memeriksa dan mengubah mereka tergantung pada sistem . "https://gcc.gnu.org/onlinedocs/libstdc++/manual/streambufs.html ) Jejak Ubuntu Anda tampaknya menunjukkan bahwa sistem operasi / buffer jaringan tidak memerah oleh flush perpustakaan (). Perilaku yang tergantung pada sistem akan menjadi lebih banyak alasan untuk menghindari endl dan pembilasan berlebihan. Jika Anda menggunakan VC ++, Anda dapat mencoba beralih ke turunan Windows GCC untuk melihat bagaimana perilaku ketergantungan sistem bereaksi, atau sebagai alternatif menggunakan Wine untuk menjalankan Windows yang dapat dieksekusi di Ubuntu.

Secara umum, Anda perlu memikirkan persyaratan untuk menentukan apakah pembilasan setiap baris sesuai atau tidak. endl umumnya cocok untuk stream interaktif seperti tampilan (kami membutuhkan pengguna untuk benar-benar melihat output kami, dan tidak dalam semburan), tetapi umumnya tidak cocok untuk jenis stream lainnya termasuk file di mana overhead pembilasan bisa signifikan. Saya telah melihat aplikasi rata pada setiap 1 dan 2 dan 4 dan 8 byte menulis ... itu tidak cukup untuk melihat OS menggiling jutaan IO untuk menulis file 1MB.

Sebagai contoh, file log mungkin perlu membilas setiap baris jika Anda mendebug macet karena Anda perlu menyiram ofstream sebelum kerusakan terjadi; sementara file log lain mungkin tidak perlu menyiram setiap baris jika hanya memproduksi logging informasi verbose yang diharapkan untuk menyiram secara otomatis sebelum aplikasi berakhir. Tidak perlu salah satu / atau karena Anda bisa mendapatkan kelas dengan algoritma flush yang lebih canggih untuk memenuhi persyaratan tertentu.

Bandingkan kasus Anda dengan kasus kontras dari orang-orang yang perlu memastikan data mereka benar-benar bertahan ke disk dan tidak rentan dalam buffer sistem operasi ( /programming/7522479/how-do-i-ensure-data -adalah-ditulis-ke-disk-sebelum-penutupan-fstream ).

Perhatikan bahwa seperti yang ditulis, outFile.flush () berlebihan karena mem-flush ofstream yang sudah memerah. Untuk menjadi bertele-tele, Anda harus menggunakan endl sendiri atau lebih disukai "\ n" dengan outFile.flush () tetapi tidak keduanya.

Doug
sumber
Terima kasih banyak! Anda berhak mendapatkan lebih dari 100 poin, tapi hanya itu yang bisa saya berikan :) Ini pasti masalahnya!
mevatron
2

Saya tidak memiliki reputasi yang cukup untuk memberikan komentar (yang menurut saya lebih baik diberikan tingkat verifikasi pada jawaban ini).

Saya perhatikan bahwa satu variasi besar dalam jejak tingkat Linux vs Windows Anda adalah bahwa Anda menggunakan SMB1 di Linux dan SMB2 di Windows. Mungkin mekanisme batch oplock berkinerja lebih baik dalam samba SMB1 daripada implementasi sewa eksklusif SMB2. Dalam kedua kasus ini harus memungkinkan untuk sejumlah caching sisi klien.

1) Mungkin mencoba mengatur level protokol maks yang lebih rendah di Samba untuk mencoba windows dengan SMB1 2) Validasi bahwa oplocks atau leasing eksklusif dikeluarkan

Semoga ini membantu :)

sehafoc
sumber
2

Kinerja operasi file jarak jauh, seperti baca / tulis, menggunakan protokol SMB dapat dipengaruhi oleh ukuran buffer yang dialokasikan oleh server dan klien. Ukuran buffer menentukan jumlah perjalanan bolak-balik yang diperlukan untuk mengirim jumlah data yang tetap. Setiap kali ketika permintaan dan tanggapan dikirim antara klien dan server, jumlah waktu yang diambil sama dengan setidaknya latensi antara kedua belah pihak, yang bisa sangat signifikan dalam kasus Wide Area Network (WAN).

Buffer SMB - MaxBufferSize dapat dikonfigurasi melalui pengaturan registri berikut:

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

Tipe data: REG_DWORD

Kisaran: 1024 hingga 65535 (Pilih nilai sesuai kebutuhan Anda di atas 5000)

TETAPI TANDA SMB memengaruhi ukuran buffer maksimum yang diizinkan. Jadi kita perlu menonaktifkan penandatangan SMB juga untuk mencapai tujuan kita. Registri berikut perlu dibuat di kedua sisi server dan jika mungkin juga di sisi klien.

HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\LanManWorkstation\Parameters

Nama Nilai: EnableSecuritySignature

Tipe data: REG_DWORD

Data: 0 (nonaktif), 1 (aktif)

Adi Jha
sumber
Terima kasih atas tipnya; Namun, saya mencoba kedua solusi ini dan saya masih melihat perilaku di atas: - /
mevatron
Anda juga ingin memeriksa mengapa "Synology DS215j" tidak menggunakan SMB3. Secara default SMB3 diaktifkan pada Win 8.1.
Adi Jha
1

Fenomena menarik. Inilah yang akan saya coba - Saya tidak tahu apakah ini benar-benar membantu. Jika itu adalah mesin saya, saya akan secara ekstensif menonton pembuat SMB. Salah satunya akan menunjukkan penyebabnya.

Lebih banyak hal untuk dicoba

Tambahkan lebih banyak Worker Threads

Jika SMB_RDR menerima satu permintaan I / O tulis per baris (apa yang seharusnya tidak terjadi di sini), mungkin membantu menambahkan beberapa utas ke mesin eksekusi.

Set "AdditionalCriticalWorkerThreads" ke 2, lalu ke 4.

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

Standarnya adalah 0, yang berarti tidak ada utas pekerja kernel tambahan yang ditambahkan. Yang biasanya ok. Nilai ini memengaruhi jumlah utas yang digunakan cache sistem file untuk permintaan baca-depan dan tulis-balik. Menaikkan nilai ini dapat memungkinkan I / O lebih banyak dalam subsistem penyimpanan (yang bagus, ketika Anda ingin menulis baris demi baris), tetapi lebih mahal CPU.

Tambahkan lebih banyak Panjang Antrian

Meningkatkan nilai "AdditionalCriticalWorkerThreads" meningkatkan jumlah utas yang dapat digunakan server file untuk melayani permintaan bersamaan .

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

Standarnya adalah 20. Indikasi bahwa nilai mungkin perlu ditingkatkan adalah jika antrian kerja SMB2 tumbuh sangat besar (perfcounter 'Server Work Queue \ Queue Length \ SMB2 *'. Harus <100).

bjoster
sumber