Test di carico: come generare richieste al secondo?

14

Ho un componente server che gira su Zeroc-ICE. Quando volevo caricarlo, pensavo che usare la libreria parallela per creare più richieste potesse farlo. Ma finisce per finire in quel modo. L'uso della libreria Parallel (Parallel.For) da C # apparentemente era più semplice, ma non sembra che stia generando esattamente tutto parallelo nello stesso istante. Quindi non può essere la definizione per la creazione di N richieste al secondo. Come dovrei farlo? Immagino che chiunque voglia eseguire test di caricamento per primo ci penserebbe davvero.

  1. Qual è il modo più efficace per creare effettivamente richieste N in ogni secondo?

  2. Un altro mito riguarda la programmazione parallela. Per favore ci illumini, se hai usato schemi di programmazione paralleli in C # o .Net in generale. Immagina di avere 5 processi. Come inizieranno tutti e cinque i processi contemporaneamente. Cosa significa per il mio consumo di risorse? Ho provato a leggere molti dei materiali disponibili in rete ma ricevo sempre più domande di quante siano la risposta alle mie domande.

  3. Ho usato Parallel.For e ho creato N threads e misurato il tempo. Poi ho provato la stessa cosa usando Task.Factory.start per l'enumerazione delle attività. Il tempo misurato era diverso. Quindi, qual è esattamente la differenza tra l'utilizzo di questi? Quando dovrei usare le classi corrispondenti e per quali scopi esattamente? spesso abbiamo molte ricchezze ma è solo che non sappiamo distinguere l'una dall'altra. Questo è uno di questi casi per me, non riuscire a trovare il motivo per cui non dovrei usarne uno dall'altro.

  4. Ho usato la classe cronometro per misurare questi tempi che pretendono di essere i migliori. Nello scenario in cui eseguo il test di un componente, quale sarebbe il modo di misurare il tempo di risposta. Il cronometro sembra essere la soluzione migliore per me. Qualsiasi opinione è gradita.

ps: ci sono molti strumenti di test del carico per le applicazioni web. Il mio è un caso personalizzato di componenti del server. E la mia domanda riguarda più la creazione di N threads al secondo.

Tutte le opinioni sono benvenute. Non pensate che sia così tanto una domanda di programmazione. È naturalmente. Dovrebbe suonare le campane per ogni programmatore che voglia fare il QE da solo per conoscere le prestazioni del suo prodotto, di prima mano da solo. Ho provato molte opzioni e poi ho dovuto ricorrere a come dovrei farlo davvero?

    
posta King 19.01.2012 - 22:27
fonte

5 risposte

10

Non ho tutte le risposte. Spero di poter versare qualche luce su di esso.

Per semplificare le mie precedenti dichiarazioni sui modelli di threading di .NET, è sufficiente sapere che Libreria parallela utilizza Attività e TaskScheduler predefinito per Attività, utilizza il ThreadPool. Più in alto vai nella gerarchia (ThreadPool è in fondo), maggiore è il sovraccarico che hai quando crei gli oggetti. Quel sovraccarico in più certamente non significa che sia più lento, ma è bello sapere che è lì. In definitiva, le prestazioni dell'algoritmo in un ambiente multi-thread si riducono al suo design. Ciò che esegue bene può in modo sequenziale, non si comporta altrettanto bene in parallelo. Ci sono troppi fattori coinvolti per darti regole ferree e veloci, cambiano a seconda di ciò che stai cercando di fare. Dato che hai a che fare con le richieste di rete, proverò a dare un piccolo esempio.

Permettetemi di affermare che non sono un esperto con le prese e non conosco quasi nulla di Zeroc-Ice. So di bit sulle operazioni asincrone, ed è qui che ti aiuterà davvero. Se si invia una richiesta sincrona tramite un socket, quando si chiama Socket.Receive() , il thread si bloccherà fino a quando non viene ricevuta una richiesta. Questo non va bene. La tua discussione non può fare più richieste dal momento che è bloccata. Usando Socket.Beginxxxxxx (), la richiesta I / O verrà creata e inserita nella coda IRP per il socket e il thread continuerà. Questo significa che il tuo thread potrebbe effettivamente fare migliaia di richieste in un loop senza alcun blocco!

Se sto capendo correttamente, stai utilizzando le chiamate tramite Zeroc-Ice nel tuo codice di test, in realtà non provando a raggiungere un endpoint http. Se è così, posso ammettere che non so come funziona Zeroc-Ice. Tuttavia, suggerirei di seguire il consiglio elencato qui , in particolare la parte: Consider Asynchronous Method Invocation (AMI) . La pagina mostra questo:

By using AMI, the client regains the thread of control as soon as the invocation has been sent (or, if it cannot be sent immediately, has been queued), allowing the client to use that thread to perform other useful work in the mean time.

Quale sembra essere l'equivalente di ciò che ho descritto sopra usando socket .NET. Potrebbero esserci altri modi per migliorare le prestazioni quando si tenta di eseguire molte mandate, ma inizierei qui o con qualsiasi altro suggerimento elencato in quella pagina. Sei stato molto vago riguardo al design della tua applicazione, quindi posso essere più specifico di quanto non sia stato sopra. Ricorda, non utilizzare più thread di assolutamente necessario per ottenere ciò che hai bisogno, altrimenti probabilmente troverai la tua applicazione molto più lenta di quanto vuoi.

Alcuni esempi in pseudocodice (cercavo di renderlo il più vicino possibile al ghiaccio senza che io dovessi realmente impararlo):

var iterations = 100000;
for (int i = 0; i < iterations; i++)
{
    // The thread blocks here waiting for the response.
    // That slows down your loop and you're just wasting
    // CPU cycles that could instead be sending/receiving more objects
    MyObjectPrx obj = iceComm.stringToProxy("whateverissupposedtogohere");
    obj.DoStuff();
}

Un modo migliore:

public interface MyObjectPrx : Ice.ObjectPrx
{
    Ice.AsyncResult GetObject(int obj, Ice.AsyncCallback cb, object cookie);
    // other functions
}

public static void Finished(Ice.AsyncResult result)
{
    MyObjectPrx obj = (MyObjectPrx)result.GetProxy();
    obj.DoStuff();
}

static void Main(string[] args)
{
    // threaded code...
    var iterations = 100000;
    for (int i = 0; i < iterations; i++)
    {
        int num = //whatever
        MyObjectPrx prx = //whatever
        Ice.AsyncCallback cb = new Ice.AsyncCallback(Finished);
        // This function immediately gets called, and the loop continues
        // it doesn't wait for a response, it just continually sends out socket
        // requests as fast as your CPU can handle them.  The response from the
        // server will be handled in the callback function when the request
        // completes.  Hopefully you can see how this is much faster when 
        // sending sockets.  If your server does not use an Async model 
        // like this, however, it's quite possible that your server won't 
        // be able to handle the requests
        prx.GetObject(num, cb, null);
    }
}

Ricorda che più thread! = prestazioni migliori quando provi a inviare socket (o davvero a fare qualcosa). I thread non sono magici in quanto risolveranno automaticamente qualsiasi problema tu stia lavorando. Idealmente, vuoi 1 thread per core, a meno che un thread non passi molto del suo tempo ad aspettare, quindi puoi giustificare di averne di più. L'esecuzione di ogni richiesta nel proprio thread è una cattiva idea, poiché si verificheranno interruttori di contesto e spreco di risorse. (Se vuoi vedere tutto ciò che ho scritto a riguardo, fai clic su modifica e guarda le revisioni precedenti di questo post. L'ho rimosso poiché sembrava solo che il problema principale fosse oscurato.)

Puoi sicuramente fare queste richieste nei thread, se vuoi fare un gran numero di richieste al secondo. Tuttavia, non esagerare con la creazione del thread. Trova un equilibrio e attaccalo. Otterrai prestazioni migliori se utilizzi un modello asincrono rispetto a un modello sincrono.

Spero che questo aiuti.

    
risposta data 19.01.2012 - 23:48
fonte
2

Salterò sulla domanda 1) e passerò direttamente al n. 2, poiché è generalmente un modo accettabile per realizzare ciò che stai cercando. In passato per raggiungere n messaggi al secondo è possibile creare un singolo processo che quindi lancerà p AppDomains. Ogni AppDomain inizia semplicemente a eseguire un ciclo di richiesta una volta raggiunto un certo punto nel tempo (utilizzando un timer). Questa volta dovrebbe essere la stessa per ogni AppDomain per garantire che inizino a colpire il server nello stesso momento.

Qualcosa del genere dovrebbe funzionare per inviare le tue richieste:

WaitCallback del = state => 
{ 
    ManualResetEvent[] resetEvents = new ManualResetEvent[10000]; 
    WebClient[] clients = new WebClient[10000]; 

    for (int index = 0; index < 10000; index++) 
    { 
        resetEvents[index] = new ManualResetEvent(false); 
        clients[index] = new WebClient(); 

        clients[index].OpenReadCompleted += new OpenReadCompletedEventHandler (client_OpenReadCompleted); 

        clients[index].OpenReadAsync(new Uri(@"<REQUESTURL>"), resetEvents[index]); 
    } 

    bool succeeded = ManualResetEvent.WaitAll(resetEvents, 10000); 
    Complete(succeeded); 

    for (int index = 0; index < 10000; index++) 
    { 
        resetEvents[index].Dispose(); 
        clients[index].Dispose(); 
    } 
}; 

while(running)
{
    ThreadPool.QueueUserWorkItem(del);
    Thread.Sleep(1000);
}

Questo probabilmente schiaccerà le prestazioni su qualunque macchina tu stia eseguendo, quindi potresti sempre implementare un tipo simile di loop da diversi computer se hai le risorse (usando i processi invece dei domini delle app).

Per la terza domanda, dai a questo link un link link

Infine, un cronometro dovrebbe essere associato a un contatore di colpi per tracciare sia la durata che l'amp; colpi unici sul tuo server. Questo dovrebbe consentire di eseguire alcune analisi dopo il fatto.

    
risposta data 19.01.2012 - 23:29
fonte
0

Non preoccuparti dei thread, se N è ragionevolmente piccolo. Per generare N richieste al secondo, usa il tempo di wall clock ( DateTime.Now ). Prendi il tempo sia prima che dopo la richiesta, quindi aggiungi un Sleep per ritardare la richiesta successiva.

Ad esempio, con N = 5 (200 ms):

Before request: 12:33:05.014
After request: 12:33:05.077
Sleep(137)
Before request: 12:33:05.214
After request: 12:33:05.271
Sleep(131)

Questo non è perfetto; potresti scoprire che Sleep non è esatto. È possibile mantenere un conteggio delle deviazioni (prima delle X'th richieste, il tempo dovrebbe essere X-1 / N più tardi) e regolare di conseguenza il periodo di sospensione.

Una volta che N diventa troppo grande, puoi semplicemente creare thread M e lasciare che ogni thread generi richieste N / M nello stesso modo.

    
risposta data 20.01.2012 - 12:37
fonte
0

Il modo più semplice per ottenere test di carico per qualsiasi progetto .NET è acquistare l'ultima versione di Visual Studio. Questo viene fornito con strumenti di test integrati per aiutare a preformare tutti i tipi di test compresi i test di carico. I test di carico possono essere preformati creando utenti virtuali su un singolo PC o distribuiti su più per un numero maggiore di utenti, inoltre è disponibile un piccolo programma che può essere installato sui server di destinazione per restituire dati aggiuntivi per la durata del test. / p>

Tuttavia, questo è costoso, ma l'ultima versione include molte funzionalità, quindi se fossero state utilizzate tutte sarebbe un prezzo più ragionevole.

    
risposta data 27.01.2012 - 15:41
fonte
0

Se si desidera che tutti i thread X colpiscano la risorsa allo stesso tempo, è possibile inserire ciascun thread dietro un latch per il conto alla rovescia e specificare un breve periodo di attesa tra i controlli semaforo.

C # ha un'implementazione (http://msdn.microsoft.com/en-us/library/system.threading.countdownevent (VS.100) .aspx).

Allo stesso tempo, se stai sottoponendo a stress il tuo sistema potresti voler controllare anche le condizioni di gara, nel qual caso vorresti impostare i periodi di sonno dei thread su ciascun thread che oscilla nel tempo con frequenza e picchi randomizzati / congedi.

Allo stesso modo potresti non voler inviare solo più richieste, potresti avere un migliore successo nel mettere il tuo server in cattivo stato / testare le sue prestazioni reali impostando un numero minore di thread che impiegano più tempo a consumare e inviando messaggi avanti e indietro sul socket, poiché probabilmente il server avrà bisogno di avviare i propri thread per gestire i messaggi lenti in corso.

    
risposta data 01.02.2012 - 22:01
fonte

Leggi altre domande sui tag