2010-05-05 12 views
15

Sto costruendo uno strumento che trasferisce set di dati di streaming molto grandi (possibilmente dell'ordine di terabyte in un singolo flusso, di routine tra decine di gigabyte) da un server all'altro. La parte client dello strumento leggerà i blocchi dal disco di origine e li invierà attraverso la rete. Il lato server leggerà questi blocchi dalla rete e li scriverà su un file sul disco del server.Come ottimizzare le prestazioni di caricamento dei file http.sys

In questo momento sto cercando di decidere quale trasporto utilizzare. Le opzioni sono TCP non elaborato e HTTP.

Davvero, davvero, voglio essere in grado di utilizzare HTTP. HttpListener (o WCF se voglio seguire quella rotta) rende facile il collegamento all'API HTTP Server (http.sys) e posso ottenere gratuitamente autenticazione e SSL. Il problema adesso sono le prestazioni.

Ho scritto un semplice cablaggio di test che invia 128K blocchi di byte NULL utilizzando l'idioma I/O asincrono BeginWrite/EndWrite, con BeginRead/EndRead async sul lato server. Ho modificato questa imbracatura di test in modo da poter eseguire questa operazione con le operazioni HTTP PUT tramite HttpWebRequest/HttpListener o con scritture socket vecchie con TcpClient/TcpListener. Per escludere problemi con schede di rete o percorsi di rete, sia il client che il server si trovano su una macchina e comunicano su localhost.

Sul mio server di test Windows 2008 R2 a 12 core, la versione TCP di questo cablaggio di test può inviare byte a 450 MB/s, con un utilizzo minimo della CPU. Nella stessa casella, la versione HTTP del cablaggio di test è compresa tra 130 MB/se 200 MB/s, a seconda di come l'ho modificata.

In entrambi i casi l'utilizzo della CPU è basso e la maggior parte dell'uso della CPU è il tempo del kernel, quindi sono abbastanza sicuro che l'utilizzo di C# e del runtime .NET non sia il collo di bottiglia. La scatola ha due processori Xeon X5650 a 6 core, 24 GB di RAM DDR3 con classificazione singola ed è utilizzata esclusivamente da me per il mio test delle prestazioni.

Conosco già le modifiche al client HTTP come ServicePointManager.MaxServicePointIdleTime, ServicePointManager.DefaultConnectionLimit, ServicePointManager.Expect100Continue e HttpWebRequest.AllowWriteStreamBuffering.

Qualcuno ha qualche idea su come ottenere prestazioni HTTP.sys superiori a 200 MB/s? Qualcuno l'ha visto esibirsi bene in qualsiasi ambiente?

UPDATE:

Ecco un po 'più in dettaglio sulle prestazioni che sto vedendo con TcpListener vs HttpListener:

In primo luogo, ho scritto un test TcpClient/TcpListener. Sulla mia casella di prova è stato in grado di spingere 450 MB/s.

Quindi, utilizzando il reflector, ho scoperto come ottenere l'oggetto Socket raw sottostante a HttpWebRequest e ho modificato il test del client HTTP per utilizzarlo. Ancora nessuna gioia; appena 200 MB/s.

La mia teoria corrente è che http.sys è ottimizzato per il tipico caso d'uso di IIS, che è un sacco di piccole richieste simultanee e molte risposte simultanee e possibilmente grandi. Ipotizzo che per raggiungere questa ottimizzazione MSFT abbia dovuto farlo a spese di ciò che sto cercando di realizzare, che è un throughput molto alto su una singola richiesta molto grande, con una risposta molto piccola.

Per quello che vale, ho anche provato fino a 32 operazioni HTTP PUT simultanee per vedere se poteva ridimensionare, ma non c'era ancora gioia; circa 200 MB/s.

È interessante notare che sulla mia workstation di sviluppo, che è un Xeon Precision T7400 quad-core con Windows 7 a 64 bit, l'implementazione di TcpClient è di circa 200 MB/se la versione HTTP è di circa 200 MB/s. Una volta che lo porto su un server di fascia più alta che esegue Server 2008 R2, il codice TcpClient arriva a 450 MB/s, mentre il codice HTTP.sys rimane intorno a 200.

A questo punto ho purtroppo concluso che HTTP.sys non è lo strumento giusto per il lavoro che ho bisogno di fare, e dovrò continuare ad usare il protocollo del socket laminato a mano che stiamo usando da sempre.

+1

Bella domanda ben studiata. Come utente di HttpListener, guarderò questo. +1 (dopo aver messo da parte i miei sentimenti sentendo parlare di uno sviluppatore con una piattaforma di sviluppo più potente della mia) – spender

+0

Grazie :) Non diventare ancora verde con l'invidia; Tempo condivido questa scatola con altri due sviluppatori (capita che sia il mio turno adesso ma dopo devo consegnarlo a qualcun altro). Dato che la scatola ha consumato il budget che avrebbe dovuto essere usato per sostituire il mio vecchio laptop di sviluppo. Oh bene; La contabilità dà, la contabilità toglie. – anelson

+0

non è esattamente una risposta, ma mi chiedo come un'utilità come Unison gestirà questo http://alliance.seas.upenn.edu/~bcpierce/wiki/index.php?n=Main.UnisonFAQTips –

risposta

2

Non riesco a vedere troppo di interesse tranne che per questo Tech Note. Potrebbe valere la pena avere un violino con MaxBytesPerSend

+0

Sì, l'ho visto davvero. Il motivo per cui non ho interferito con 'MaxBytesPerSend' era che nel mio caso, HTTP.sys non sta facendo l'invio; Sto facendo un HTTP PUT con un grande carico utile, che HTTP.sys riceve e trasmette al mio server basato su HttpLisener. Inoltre, una finestra TCP più grande dovrebbe beneficiare di collegamenti con larghezza di banda elevata combinata con elevata latenza; poiché il mio test viene eseguito sull'interfaccia di loopback, la latenza è asintotica a zero. Grazie comunque per il suggerimento. Tienili in arrivo! – anelson

0

Se stai per inviare file sulla LAN, UDP è la strada da percorrere, perché il sovraccarico del TCP è uno spreco in quel caso. Il TCP fornisce la tariffa limitando per evitare troppi pacchetti persi, mentre con UDP l'applicazione deve risolverlo da solo. NFS farebbe il lavoro, se non fosse che sei bloccato con Windows; ma sono sicuro che ci devono essere cose pronte per UDP. Utilizzare anche lo strumento "iperf" (disponibile su Linux, probabilmente anche Windows) per confrontare il collegamento di rete indipendentemente dal protocollo. Alcune schede di rete sono semplici schifezze e dipendono troppo dalla CPU, il che limiterà la velocità a 200 mbit. Si desidera una scheda di rete appropriata con i propri processori (non si conoscono i termini esatti per inserirla).

+0

Grazie per il suggerimento, ma per vari motivi sono bloccato con HTTP. Sono abbastanza familiare con il sovraccarico introdotto da TCP, ma questo da solo non tiene conto della penalizzazione delle prestazioni che sto pagando qui. Usando il TCP non elaborato, ero in grado di spostare 450 MB/s, rispetto a poco più di 200 MB/s con HTTP.sys, quindi chiaramente c'è un sovraccarico specifico per l'implementazione HTTP. Utilizzo una scheda NIC GigE Intel PRO/1000 dual-port PCI-Express x4 con offload TCP, ma non è nemmeno rilevante dal momento che il test che sto eseguendo si trova sull'interfaccia di loopback. – anelson

+0

Trovo strano che tu rimanga bloccato con HTTP, qualcosa come TFTP sarebbe molto meglio. Che ne dici di sperimentare alcune implementazioni HTTP da riga di comando, ad es. arricciatura più qualche banale server HTTP in C? Da quello che stai dicendo sembra ovvio che si tratta di una limitazione del software, quindi prova altre implementazioni. Probabilmente vuoi un server che memorizza i file? – Andreas

Problemi correlati