Lasttests: Wie werden Anfragen pro Sekunde generiert?

14

Ich habe eine Serverkomponente, die über Zeroc-ICE läuft. Als ich es laden wollte, dachte ich, dass die Verwendung einer parallelen Bibliothek zum Erstellen mehrerer Anforderungen dies tun würde. Aber es wird nicht so enden. Das Verwenden der Parallel (Parallel.For) -Bibliothek aus C # war anscheinend einfacher, aber es scheint nicht genau zu sein, dass alles parallel im selben Moment generiert wird. Es kann also nicht die Definition für das Erstellen von N Anforderungen pro Sekunde sein. Wie soll ich das machen Ich denke, jeder, der zuerst Lasttests durchführen möchte, würde darüber nachdenken.

  1. Was ist der effiziente Weg, um tatsächlich N Anfragen in wirklich einer Sekunde zu erstellen?

  2. Ein weiterer Mythos handelt von der parallelen Programmierung. Bitte klären Sie uns auf, wenn Sie in C # oder .Net generell parallele Programmiermuster verwendet haben. Stellen Sie sich vor, ich habe 5 Prozesse. Wie werden alle fünf Prozesse gleichzeitig gestartet? Was bedeutet es für meinen Ressourcenverbrauch? Ich habe versucht, in viele Materialien zu lesen, die über das Internet verfügbar sind, aber ich bekomme immer mehr Fragen als die Antwort auf meine Fragen.

  3. Ich habe Parallel.For verwendet und N Threads erstellt und die Zeit gemessen. Dann habe ich dasselbe mit Task.Factory.start für die Aufzählung von Aufgaben versucht. Die gemessene Zeit war unterschiedlich. Was genau ist der Unterschied zwischen diesen? Wann und für welche Zwecke sollte ich die entsprechenden Klassen verwenden? Wir haben oft viele Reichtümer, aber es ist nur so, dass wir nicht genau wissen, wie wir uns voneinander unterscheiden können. Dies ist ein solcher Fall für mich, nicht in der Lage zu finden, warum ich nicht eine von der anderen verwenden sollte.

  4. Ich habe die Stoppuhr verwendet, um diese Zeiten zu messen, die als die besten gelten. In dem Szenario, in dem ich eine Komponente beim Laden teste, ist dies die Methode zum Messen der Reaktionszeit. Stoppuhr scheint für mich die beste Lösung zu sein. Alle Meinungen sind willkommen.

ps: Es gibt viele Lasttest-Tools für Webanwendungen. Meins ist ein kundenspezifischer Fall von Serverkomponenten. Und meine Frage bezieht sich eher auf das Erstellen von N Threads pro Sekunde.

Alle Meinungen sind willkommen. Denken Sie nur nicht, dass es so sehr keine Programmierfrage ist. Es ist selbstverständlich. Es sollte für jeden Programmierer, der die Leistung seines Produkts selbst testen möchte, ein Kinderspiel sein. Ich habe viele Optionen ausprobiert und musste dann darauf zurückgreifen, wie ich es tatsächlich tun sollte.

König
quelle
Die FAQ sagt, ob es sich um ein spezifisches Programmierproblem handelt und ob es sich um ein praktisches, beantwortbares Problem im Programmierberuf handelt, das gestellt werden kann. Menschen, die skeptisch sind und dies anzeigen. Bitte kommentieren.
König
Was meinst du mit "im selben Augenblick"? Ich frage mich, ob Sie TPL oder PLinq dazu zwingen können.
Gert Arnold
Meine Frage ist über das Erzeugen von N Anträgen pro Sekunde. Der gleiche Zeitpunkt in diesem Szenario war für mein Verständnis der Verwendung der parallelen Threads auf parallele Weise gedacht.
König
Haben Sie eine sequentielle Analyse durchgeführt?
3
Es mag sich um die Programmierung handeln, aber Ihr Beitrag enthält einfach zu viele Fragen (mindestens 4). Ich würde es auf die eine Frage reduzieren, die Sie stellen möchten, bevor es geschlossen wird, weil es zu breit ist. Geben Sie relevante Informationen an (z. B. die soeben erwähnte 10000, Anzahl der Kerne in Ihrer Testmaschine). Das Anzeigen von Code hilft normalerweise.
Gert Arnold

Antworten:

10

Ich habe nicht alle Antworten. Hoffentlich kann ich etwas Licht ins Dunkel bringen.

Um meine vorherigen Aussagen zu .NETs Threading-Modellen zu vereinfachen, müssen Sie lediglich wissen, dass die Parallel Library Tasks verwendet und der standardmäßige TaskScheduler für Tasks den ThreadPool verwendet. Je höher Ihre Position in der Hierarchie ist (ThreadPool befindet sich unten), desto mehr Aufwand haben Sie beim Erstellen der Elemente. Dieser zusätzliche Aufwand bedeutet sicherlich nicht, dass er langsamer ist, aber es ist gut zu wissen, dass er vorhanden ist. Letztendlich hängt die Leistung Ihres Algorithmus in einer Umgebung mit mehreren Threads von seinem Design ab. Was sequentiell gut abschneidet, läuft möglicherweise nicht so gut parallel. Es sind zu viele Faktoren involviert, um Ihnen feste und schnelle Regeln zu geben. Sie ändern sich je nachdem, was Sie tun möchten. Da Sie sich mit Netzwerkanforderungen befassen, werde ich versuchen, ein kleines Beispiel zu geben.

Lassen Sie mich feststellen, dass ich kein Experte für Steckdosen bin und so gut wie nichts über Zeroc-Ice weiß. Ich weiß ein bisschen über asynchrone Operationen Bescheid, und hier wird es Ihnen wirklich helfen. Wenn Sie eine synchrone Anfrage über einen Socket senden Socket.Receive(), wird Ihr Thread beim Aufruf blockiert, bis eine Anfrage eingeht. Das ist nicht gut. Dein Thread kann keine Anfragen mehr stellen, da er blockiert ist. Mit Socket.Beginxxxxxx () wird die E / A-Anforderung gestellt und in die IRP-Warteschlange für den Socket gestellt, und Ihr Thread wird fortgesetzt. Dies bedeutet, dass Ihr Thread tatsächlich Tausende von Anfragen in einer Schleife stellen kann, ohne dass diese blockiert werden!

Wenn ich Sie richtig verstehe, verwenden Sie Anrufe über Zeroc-Ice in Ihrem Testcode und versuchen nicht, einen http-Endpunkt zu erreichen. In diesem Fall kann ich zugeben, dass ich nicht weiß, wie Zeroc-Ice funktioniert. Ich würde allerdings vorschlagen , im Anschluss an die Beratung hier aufgeführt , insbesondere den Teil: Consider Asynchronous Method Invocation (AMI). Die Seite zeigt dies:

Durch die Verwendung von AMI erhält der Client den Steuerthread zurück, sobald der Aufruf gesendet wurde (oder, wenn er nicht sofort gesendet werden kann, in die Warteschlange gestellt wurde), sodass der Client diesen Thread in der Zwischenzeit für andere nützliche Aufgaben verwenden kann .

Das scheint das Äquivalent zu dem zu sein, was ich oben unter Verwendung von .NET-Sockets beschrieben habe. Möglicherweise gibt es andere Möglichkeiten, die Leistung zu verbessern, wenn Sie versuchen, viele Sendevorgänge durchzuführen, aber ich würde hier oder mit einem anderen Vorschlag beginnen, der auf dieser Seite aufgeführt ist. Sie waren in Bezug auf das Design Ihrer Anwendung sehr vage, sodass ich genauer sein kann als oben. Denken Sie daran, verwenden Sie nicht mehr Threads als unbedingt erforderlich , um das zu erledigen, was Sie benötigen. Andernfalls wird Ihre Anwendung wahrscheinlich viel langsamer ausgeführt, als Sie möchten.

Einige Beispiele im Pseudocode (versucht, es so nah wie möglich am Eis zu machen, ohne dass ich es wirklich lernen muss):

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();
}

Ein besserer Weg:

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

Denken Sie daran, dass mehr Threads! = Bessere Leistung beim Versuch, Sockets zu senden (oder wirklich etwas zu tun). Threads sind insofern keine Zauberei, als sie automatisch jedes Problem lösen, an dem Sie arbeiten. Idealerweise möchten Sie 1 Thread pro Kern, wenn ein Thread nicht viel Zeit damit verbringt, zu warten, dann können Sie mehr rechtfertigen. Das Ausführen jeder Anforderung in einem eigenen Thread ist eine schlechte Idee, da Kontextwechsel auftreten und Ressourcen verschwendet werden. (Wenn Sie alles sehen möchten, was ich darüber geschrieben habe, klicken Sie auf Bearbeiten und sehen Sie sich die früheren Überarbeitungen dieses Beitrags an. Ich habe ihn entfernt, da er nur das Hauptproblem zu trüben schien.)

Sie können diese Anfrage definitiv in Threads stellen, wenn Sie eine große Anzahl von Anfragen pro Sekunde stellen möchten. Gehen Sie jedoch bei der Thread-Erstellung nicht über Bord. Finde ein Gleichgewicht und bleibe dabei. Sie erzielen eine bessere Leistung, wenn Sie ein asynchrones Modell im Vergleich zu einem synchronen Modell verwenden.

Ich hoffe das hilft.

Christopher Currens
quelle
Warum redest du so viel über Leistung? Das scheint nicht das zu sein, was die OP will.
Svick
@svick na ja, der ursprüngliche Beitrag von ops hatte ursprünglich 4 Fragen und sie stellten Fragen zur Leistung von parallelen vs. Letztendlich hat seine Frage zwar mit Leistung zu tun, da er die Grundidee richtig hat, aber anscheinend an seiner Umsetzung fehlt. Ich glaube meine spitzen Antworten am Ende beantworten die Frage er nicht bearbeitet hat.
Christopher Currens
Ich musste meine Fragen reduzieren, weil sie zum Abschluss abstimmen wollten. Nun scheint es hier gültig zu sein, sie zu haben. @ChristopherCurrens +1 guter Punkt für den Unterschied zwischen Threadpool und Aufgaben. Das hat mein Verständnis erweitert. Aber ich stecke immer noch fest, wie es wirklich möglich ist, einige N Anfragen pro Sekunde zu generieren. Was genau ist der beste Weg das zu tun?
König
@King - Ich glaube, ich war nicht so klar, wie ich dachte. Die letzten 3-4 Absätze, von denen ich dachte, sie würden dir helfen. Ich hatte angenommen, dass Sie bereits eine Art Schleife verwenden. Wenn Sie dies getan haben, besteht das Problem darin, dass Ihre Socket-Sende- / Empfangsvorgänge blockiert sind und somit Ihre Anforderungen verlangsamen. Vielleicht finde ich etwas Zeit, um ein Beispiel für einen Pseudocode zu veröffentlichen.
Christopher Currens
Ich habe kein Problem damit, sie tatsächlich über ICE zu senden. Das Problem ist, was die Implementierung definiert, die tatsächlich N Anforderungen erzeugt, und etwas, das dieser Zahl N entspricht.
König
2

Ich werde Frage 1) überspringen und gleich zu Frage 2 übergehen, da dies im Allgemeinen ein akzeptabler Weg ist, um das zu erreichen, was Sie suchen. Um in der Vergangenheit n Nachrichten pro Sekunde zu erzielen , können Sie einen einzelnen Prozess erstellen, mit dem p AppDomains gestartet werden. Grundsätzlich startet jede AppDomain eine Anforderungsschleife erst, wenn ein bestimmter Zeitpunkt erreicht ist (mithilfe eines Timers). Diese Zeit sollte für jede AppDomain gleich sein, um sicherzustellen, dass sie zum gleichen Zeitpunkt auf Ihren Server trifft.

So etwas sollte für das Senden Ihrer Anfragen funktionieren:

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

Dies wird wahrscheinlich die Leistung auf jedem Computer beeinträchtigen, auf dem Sie es ausführen, sodass Sie immer eine ähnliche Art von Schleife von mehreren verschiedenen Computern implementieren können, wenn Sie über die Ressourcen verfügen (indem Sie Prozesse anstelle von Anwendungsdomänen verwenden).

Geben Sie für Ihre dritte Frage diesen Link ein: http://www.albahari.com/threading/

Schließlich sollte eine Stoppuhr mit einem Trefferzähler gekoppelt werden, um sowohl die Dauer als auch die eindeutigen Treffer auf Ihrem Server zu verfolgen. Damit sollten Sie nachträglich einige Analysen durchführen können.

Chris
quelle
2
Welchen möglichen Grund müssten Sie hier separate AppDomains erstellen? Das scheint völlig unnötig.
Svick
0

Kümmere dich nicht um Fäden, wenn N einigermaßen klein ist. Verwenden Sie die Wanduhrzeit ( DateTime.Now), um N Anforderungen pro Sekunde zu generieren . Nehmen Sie sich die Zeit vor und nach der Anforderung und fügen Sie ein hinzu Sleep, um die nächste Anforderung zu verzögern.

Zum Beispiel mit 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)

Das ist nicht perfekt; Vielleicht finden Sie, dass Sleepdas nicht genau ist. Sie können die Abweichungen fortlaufend zählen (vor der X-ten Anforderung sollte die Zeit später X-1 / N betragen) und die Ruhezeit entsprechend anpassen.

Sobald N zu groß wird, erstellen Sie einfach M Threads und lassen jeden Thread N / M-Anforderungen auf dieselbe Weise generieren.

MSalters
quelle
Ich muss sehr viele Anfragen generieren. Dies kann also nicht die Option sein, da mein Speicher (4 GB RAM) bereits vor 100 Threads aufgebraucht wird.
König
Ich habe 20.000 Anfragen pro Sekunde von einem einzelnen Thread in 250 KB Code erstellt. Sie haben ohnehin nicht genug CPUs, um 100 Threads auszuführen (diese Klasse von Computern enthält keine 4 GB). Das nächste Problem wäre, all diese Anfragen herauszuschieben. Haben Sie 10 Gbit / s Ethernet zwischen Ihrem Load Creator und Ihrem Server? Vielleicht möchten Sie Ihre tatsächlichen Anforderungen überprüfen.
MSalters
Zur Verdeutlichung habe ich so etwas wie 20+ Gbit / s. Das ist also kein Problem. Über die Klasse der Maschinen: Worauf würden Sie sich beziehen? Anzahl Prozessoren?
König
@King: um 100 Threads zu pushen würde ich einen 48 Core Rechner erwarten. SGI verkauft zum Beispiel Maschinen mit so vielen Kernen, aber auf solchen bekommt man normalerweise 32 GB oder mehr.
MSalters
0

Der einfachste Weg, Lasttests für ein .NET-Projekt durchzuführen, ist der Kauf der Ultimate Edition von Visual Studio. Dies wird mit einem integrierten Testwerkzeug geliefert, mit dessen Hilfe alle Arten von Tests einschließlich Belastungstests durchgeführt werden können. Lasttests können durchgeführt werden, indem virtuelle Benutzer entweder auf einem einzelnen PC oder auf mehrere verteilt für eine größere Anzahl von Benutzern erstellt werden. Auf den Zielservern kann auch ein kleines Programm installiert werden, das zusätzliche Daten für die Dauer des Tests zurückgibt.

Dies ist zwar teuer, aber die ultimative Edition enthält viele Funktionen. Wenn also alle verwendet würden, wäre der Preis angemessener.

Ryathal
quelle
0

Wenn Sie möchten, dass alle X-Threads genau zur gleichen Zeit auf Ihre Ressource treffen, können Sie jeden Thread hinter einen Countdown-Latch setzen und eine kurze Wartezeit zwischen den Semaphorprüfungen festlegen.

C # hat eine Implementierung (http://msdn.microsoft.com/en-us/library/system.threading.countdownevent(VS.100).aspx).

Zur gleichen Zeit, wenn Sie Ihr System einem Stresstest unterziehen, möchten Sie möglicherweise auch die Rennbedingungen überprüfen. In diesem Fall möchten Sie für jeden Thread Ruheperioden einrichten, die mit zufälliger Häufigkeit und Peaks / Furloughs über die Zeit oszillieren.

In ähnlicher Weise möchten Sie möglicherweise nicht nur schnell mehrere Anforderungen senden, sondern können Ihren Server auch erfolgreicher in einen schlechten Zustand versetzen / seine tatsächliche Leistung testen, indem Sie eine kleinere Anzahl von Threads einrichten, die mehr Zeit für das Konsumieren und Zurücksenden von Nachrichten aufwenden und weiter über den Socket, da Ihr Server wahrscheinlich seine eigenen Threads hochfahren muss, um langsam laufende Nachrichten zu verarbeiten.

Keith Brings
quelle