SMB ağ paylaşımına küçük yazma işlemleri Windows'da yavaş, CIFS Linux montajında ​​hızlı


10

Küçük yazılar yazarken bir KOBİ / CIFS payı ile performans sorununu çözmek için uğraşıyorum.

İlk olarak, mevcut ağ kurulumumu açıklayayım:

Sunucu

  • Synology DS215j (SMB3 desteği etkinken)

İstemciler (aynı bilgisayar çift önyüklemeli kablolu Gig-E)

  • Ubuntu 14.04.5 LTS, Güvenilir Tahr
  • Windows 8.1

smb.conf'yi

[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

Şu anda (GitHub üzerinde C ++ ile yazılmış aşağıdaki program ile küçük yazma performansını test ediyorum burada ):

#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 yapılandırması:

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

Linux'ta program çalışma süresi (~ 100Mbps'de ağ çıkışını artırır):

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

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

Birçok satırın tek bir TCP paketine parçalanmasını gösteren PCAP anlık görüntüsü:

Linux PCAP anlık görüntüsü

PowerShell tarafından ölçülen Windows'ta program çalışma zamanı:

> 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 Yazma İsteği başına tek satır gösteren Windows PCAP anlık görüntüsü:

Windows PCAP anlık görüntüsü

Aynı program Windows'ta yaklaşık 10 dakika (~ 2.3Mbps) alır. Açıkçası, Windows PCAP, çok düşük taşıma kapasitesi verimliliği ile çok gürültülü bir KOBİ konuşması gösterir.

Windows'ta küçük yazma performansını artırabilecek ayarlar var mı? Paket yakalamalarına bakıldığında, Windows'un yazmaları düzgün bir şekilde arabelleğe almadığı ve verileri bir kerede bir satır olarak gönderdiği görülmektedir. Oysa, Linux'ta, veriler yoğun bir şekilde arabelleğe alınır ve bu nedenle çok daha üstün bir performansa sahiptir. PCAP dosyalarının yardımcı olup olmayacağını bana bildirin ve bunları yüklemek için bir yol bulabilirim.

Güncelleme: 10/27/16:

@Sehafoc tarafından belirtildiği gibi Samba sunucuları max protocolayarını SMB1 olarak aşağıdakilerle indirdim:

max protocol=NT1

Yukarıdaki ayar aynı davranışla sonuçlandı.

Ayrıca başka bir Windows 10 makinesinde bir paylaşım oluşturarak Samba değişkenini kaldırdım ve aynı zamanda Samba sunucusuyla aynı davranışı sergiliyor, bu yüzden bunun genel olarak Windows istemcileri ile bir yazma önbellekleme hatası olduğuna inanmaya başlıyorum.

Güncelleme: 10/06/17:

Tam Linux paket yakalama (14MB)

Tam Windows paket yakalama (375MB)

Güncelleme: 10/12/17:

Ayrıca bir NFS paylaşımı ayarladım ve Windows da bunun için arabelleğe alma olmadan yazıyor. Yani, kesinlikle altta yatan bir Windows istemci sorunu anlayabildiğim kadarıyla, bu kesinlikle talihsiz: - /

Herhangi bir yardım mutluluk duyacağız!

Yanıtlar:


2

C ++ endl '\ n' çıktısını ve ardından sifonu verecek şekilde tanımlanır. flush () pahalı bir işlemdir, bu nedenle endl'yi varsayılan satır sonu olarak kullanmaktan kaçınmalısınız çünkü tam olarak gördüğünüz performans sorununu yaratabilir (ve sadece SMB ile değil, aynı zamanda yerel eğirme dahil pahalı bir yıkama ile herhangi bir akışla) pas veya hatta en son NVMe'yi gülünç derecede yüksek bir çıktı oranında).

Endl'nin "\ n" ile değiştirilmesi, sistemin istendiği gibi arabelleğe almasına izin vererek yukarıdaki performansı düzeltir. Bazı kütüphaneler "\ n" üzerinde akabilir, bu durumda daha fazla baş ağrınız olur (sync () yöntemini geçersiz kılan bir çözüm için bkz. Https://stackoverflow.com/questions/21129162/tell-endl-not-to-flush . ).

Şimdi işleri karmaşıklaştırmak için, flush () yalnızca kütüphane arabelleklerinde ne olduğu için tanımlanır. Floşun işletim sistemi, disk ve diğer harici tamponlar üzerindeki etkisi tanımlanmamıştır. Microsoft.NET için "FileStream.Flush yöntemini çağırdığınızda, işletim sistemi G / Ç arabelleği de temizlenir." ( https://msdn.microsoft.com/tr-tr/library/2bw4h516(v=vs.110).aspx ) Bu, Visual Studio C ++ için özellikle pahalıya mal olur; gördüğünüz gibi uzak sunucunuzun uzak ucundaki fiziksel medya. Öte yandan GCC, "Son bir hatırlatma: genellikle yalnızca dil / kütüphane düzeyindekilerden daha fazla arabellek var. Çekirdek arabellekleri, disk arabellekleri ve benzerleri de bir etkiye sahip olacak. Bunların incelenmesi ve değiştirilmesi sisteme bağlı ."https://gcc.gnu.org/onlinedocs/libstdc++/manual/streambufs.html ) Ubuntu izlemeleriniz, işletim sistemi / ağ arabelleklerinin kitaplık sifonu () tarafından temizlenmediğini gösteriyor gibi görünüyor. Sisteme bağımlı davranış, endl ve aşırı yıkamayı önlemek için daha fazla sebep olacaktır. VC ++ kullanıyorsanız, sistem bağımlı davranışların nasıl tepki verdiğini görmek için bir Windows GCC türevine geçmeyi veya alternatif olarak Ubuntu'da Windows yürütülebilir dosyasını çalıştırmak için Wine'ı kullanmayı deneyebilirsiniz.

Daha genel olarak, her hattın yıkanmasının uygun olup olmadığını belirlemek için gereksinimlerinizi düşünmeniz gerekir. endl genellikle ekran gibi etkileşimli akışlar için uygundur (kullanıcının çıktımızı görmesini ve patlamaları değil aslında görmesini isteriz), ancak genellikle temizleme yükünün önemli olabileceği dosyalar da dahil olmak üzere diğer akış türleri için uygun değildir. Ben her 1 ve 2 ve 4 ve 8 bayt yazma uygulamaları floş gördüm ... OS 1 milyon dosya yazmak milyonlarca IO eziyet görmek hoş değil.

Örnek olarak, bir kilitlenme hata ayıklaması yapıyorsanız, bir günlük dosyasının her satırı temizlemesi gerekebilir; çünkü kilitlenme gerçekleşmeden önce akışı temizlemeniz gerekir; ancak başka bir günlük dosyasının, uygulama sonlandırılmadan önce otomatik olarak temizlenmesi beklenen ayrıntılı bilgi günlüğü oluşturuyorsa, her satırı temizlemeye gerek olmayabilir. Özel gereksinimlere uyacak şekilde daha karmaşık bir yıkama algoritmasına sahip bir sınıf türetebileceğiniz için / veya olması gerekmez.

Davanızı, verilerinin bir diske tamamen kalıcı olduğundan ve bir işletim sistemi arabelleğinde savunmasız olmadığından emin olmaları gereken durumlarla karşılaştırın ( /programming/7522479/how-do-i-ensure-data -fiske kapatılmadan önce diske yazılır ).

Yazıldığı gibi, outFile.flush () öğesinin, daha önceden temizlenmiş bir akışı temizlediği için gereksiz olduğunu unutmayın. Bilgiçlikçi olmak için endl'i tek başına veya tercihen outFile.flush () ile "\ n" kullanmış olmalısınız, ancak ikisini birden kullanmamalısınız.


Milyonlarca kez teşekkürler! 100'den fazla puan hak ediyorsun, ama tüm verebilirim :) Bu kesinlikle sorun oldu!
mevatron

2

Yorum bırakmak için yeterli üne sahip değilim (bu cevabın doğrulama seviyesi göz önüne alındığında daha iyi olacağını düşünüyorum).

Linux ve Windows düzey izlemenizdeki büyük bir varyansın Linux'ta SMB1 ve Windows'ta SMB2 kullandığınızı fark ettim. Belki de toplu işlem kilitleme mekanizması SMB1 samba'da SMB2 özel kiralama uygulamasından daha iyi performans gösterir. Her iki durumda da bunlar bir miktar istemci tarafı önbelleğe almayı mümkün kılmalıdır.

1) SMB1 ile pencereleri denemek için Samba'da daha düşük bir maksimum protokol seviyesi ayarlamayı deneyin.

Bu yardımcı olur umarım :)


2

SMB protokolünü kullanarak okuma / yazma gibi uzak dosya işlemlerinin performansı, sunucular ve istemciler tarafından ayrılan arabelleklerin boyutundan etkilenebilir. Arabellek boyutu, sabit miktarda veri göndermek için gereken gidiş-dönüş sayısını belirler. İstemci ve sunucu arasında istek ve yanıtların gönderildiği her seferinde, geçen süre, her iki taraf arasındaki gecikme süresine eşittir, bu da Geniş Alan Ağı (WAN) durumunda çok önemli olabilir.

SMB arabelleği - MaxBufferSize aşağıdaki kayıt defteri ayarıyla yapılandırılabilir:

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

Veri tipi: REG_DWORD

Aralık: 1024 ila 65535 (5000'in üzerinde gereksiniminize göre değer seçin)

ANCAK KOBİ İŞARETİ izin verilen maksimum arabellek boyutunu etkiler. Bu nedenle, hedefimize ulaşmak için KOBİ imzalamayı da devre dışı bırakmamız gerekiyor. Aşağıdaki kayıt defteri hem sunucu tarafında hem de mümkünse istemci tarafında oluşturulmalıdır.

HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\LanManWorkstation\Parameters

Değer Adı: EnableSecuritySignature

Veri tipi: REG_DWORD

Veri: 0 (devre dışı), 1 (etkin)


Bahşiş için teşekkürler; Ancak, bu ilaçların her ikisini de denedim ve hala yukarıdaki davranışı görüyorum: - /
mevatron

Ayrıca "Synology DS215j" neden SMB3 kullanmadığını kontrol etmek istersiniz. SMB3 varsayılan olarak Win 8.1'de etkindir.
Adi Jha

1

İlginç bir fenomen. İşte deneyeceğim - Bu gerçekten yardımcı olursa hiçbir fikrim yok. Benim makinem olsaydı, KOBİ perfcounters'ı yoğun bir şekilde izlerdim. Bunlardan biri olacaktır nedenini gösteriyor.

Denenecek daha fazla şey

Daha fazla Çalışan İş Parçacığı Ekle

SMB_RDR'nin satır başına bir yazma G / Ç İsteği alması durumunda ( burada olmaması gerekir ), yürütme motoruna bazı iş parçacıkları eklemek yardımcı olabilir .

"AdditionalCriticalWorkerThreads" değerini 2, sonra 4 olarak ayarlayın.

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

Varsayılan değer 0'dır; başka bir kritik çekirdek işçi iş parçacığı eklenmez. Hangi genellikle ok. Bu değer, dosya sistemi önbelleğinin okuma ve geri yazma istekleri için kullandığı iş parçacığı sayısını etkiler. Bu değeri arttırmak olabilir daha fazla depolama alt sisteminde / O I sıraya için (eğer yazma hattı-by-line istediğinizde, iyi olan) izin, ancak daha fazla CPU pahalı.

Daha fazla Kuyruk Uzunluğu ekle

"AdditionalCriticalWorkerThreads" değerinin artırılması, dosya sunucusunun eşzamanlı isteklere hizmet vermek için kullanabileceği iş parçacığı sayısını artırır .

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

Varsayılan değer 20'dir. Değerin artırılması gerekebileceğinin bir göstergesi, SMB2 çalışma kuyruklarının çok büyük büyüyüp arttığının göstergesidir (perfcounter 'Sunucu Çalışma Kuyrukları \ Kuyruk Uzunluğu \ SMB2 *'. <100 olmalıdır).

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.