Datenbankverbindungs-Pooling mit multi-threaded Service

8

Ich habe einen .NET 4 C # -Dienst, der die TPL-Bibliotheken für das Threading verwendet. Wir haben es kürzlich auf Connection Pooling umgestellt, da eine Verbindung zu einem Engpass für die Verarbeitung wurde.

Bisher haben wir eine lock-Klausel verwendet, um die Thread-Sicherheit für das Verbindungsobjekt zu steuern. Wenn die Arbeit gesichert würde, würde die Warteschlange als Tasks existieren und viele Threads (Tasks) würden auf der lock-Klausel warten. In den meisten Szenarien warten Threads nun auf Datenbank-E / A und arbeiten VIEL schneller.

Jetzt, da ich jedoch Verbindungspooling verwende, haben wir ein neues Problem. Sobald die maximale Anzahl von Verbindungen erreicht ist (100 Standard), gibt es eine Zeitüberschreitung, wenn weitere Verbindungen angefordert werden (siehe Pooling-Info ). Wenn dies geschieht, wird eine Ausnahme ausgelöst, die besagt, dass die Verbindungsanforderung abgelaufen ist.

Alle meine IDisposables sind innerhalb von Anweisungen, und ich verwalte meine Verbindungen ordnungsgemäß. Dieses Szenario tritt auf, weil mehr Arbeit angefordert wird, als der Pool verarbeiten kann (was erwartet wird). Ich verstehe, warum diese Ausnahme ausgelöst wird, und ich weiß, wie ich damit umgehen kann. Eine einfache Wiederholung fühlt sich an wie ein Hack. Ich merke auch, dass ich die Timeout-Zeit über die Verbindungszeichenfolge erhöhen kann, aber das fühlt sich nicht wie eine feste Lösung an. Im vorherigen Entwurf (ohne Pooling) würden Arbeitselemente aufgrund der Sperre in der Anwendung verarbeitet.

Was ist eine gute Möglichkeit, dieses Szenario zu bearbeiten, um sicherzustellen, dass alle Arbeiten verarbeitet werden?

    
Andy Christianson 06.01.2012, 18:32
quelle

3 Antworten

10

Ein anderer Ansatz ist die Verwendung eines Semaphors um den Code, der Verbindungen abruft aus dem Pool (und, hoffentlich, gibt sie zurück). Ein Sempahor ist wie eine Lock-Anweisung, außer dass es eine konfigurierbare Anzahl von Requestoren gleichzeitig erlaubt, nicht nur eine.

So etwas sollte tun:

%Vor%     
Chris Shain 06.01.2012, 19:11
quelle
2

Sie können den Parallelitätsgrad steuern, indem Sie die Methode Parallel.ForEach() wie folgt verwenden:

%Vor%

In diesem Fall habe ich den Grad auf 100 gesetzt, aber Sie können einen Wert wählen, der für Ihre aktuelle Implementierung des Verbindungspools sinnvoll ist.

Diese Lösung setzt natürlich voraus, dass Sie eine Sammlung von Arbeitselementen haben. Wenn Sie jedoch neue Aufgaben über externe Mechanismen wie eingehende Webanfragen erstellen, ist die Ausnahme eigentlich eine gute Sache. An diesem Punkt würde ich vorschlagen, dass Sie die Datenstruktur der gleichzeitigen Warteschlange verwenden, in der Sie die Arbeitselemente platzieren und sie als Worker-Threads verfügbar machen können.

    
Phil Klein 06.01.2012 18:45
quelle
0

Die einfachste Lösung besteht darin, das Verbindungszeitlimit auf die Zeitspanne zu erhöhen, in der Sie eine Anforderung blockieren möchten, bevor ein Fehler zurückgegeben wird. Es muss eine gewisse Zeit sein, die "zu lang" ist.

Dadurch wird der Verbindungspool effektiv als Arbeitswarteschlange mit einem Timeout verwendet. Es ist viel einfacher als zu versuchen, eines selbst zu implementieren. Sie müssten überprüfen, ob der Verbindungspool fair ist (FIFO).

    
Nicholas Butler 06.01.2012 19:01
quelle