Du verwendest einen veralteten Browser. Es ist möglich, dass diese oder andere Websites nicht korrekt angezeigt werden. Du solltest ein Upgrade durchführen oder ein alternativer Browser verwenden.
ich will in einem Servlet einen Connection-Pool halten, um den ständigen Aufbau von Connections zu unterbinden.
Macht es Sinn mehrere Connections mit den selben Parametern zu instantiieren?
Also z.B. 4 Connections, die auf die Datenbank "MyDatabase" zeigen?
Oder macht es keinen Sinn?
Im Moment sieht meine Architektur so aus, dass ich in einer config-File einige Statements in PreparedStatement-Syntax definiere. Dieses file wird von einer DAO-Klasse eingelesen.
Eine über die DAO-Klasse erzeugte Connection erzeugt dann die Prepared Statements.
Diese, wie auch die Connection, werden in HashMaps für den Einsatz vorgehalten.
ich will in einem Servlet einen Connection-Pool halten, um den ständigen Aufbau von Connections zu unterbinden.
Macht es Sinn mehrere Connections mit den selben Parametern zu instantiieren?
Also z.B. 4 Connections, die auf die Datenbank "MyDatabase" zeigen?
Oder macht es keinen Sinn?
Klar kann (und sollte) ein Connection Pool mehrere Connections zu der gleichen Ressource halten. Warum auch nicht? Der Pool soll dir ja möglichst schnell eine freie Verbindung zu der Resource geben. Wenn du immer nur eine Connection hast würde der Pool ja blocken wenn z.B. ein zweiter Thread eine Connection anfragt.
Die Frage war eher so gemeint: Verbindungen aufbauen ist zwar teuer, aber wenn eine Connection parallele Zugriffe ermöglicht, wie sinnvoll wären dann mehrere Connections.
Diesbezüglich war ich einfach unbewandert.
Soweit hat sich das aber erst mal geklärt!
Danke übrigens für den Apache Commons-Hinweis!
Gibt es eine generische Implementierung für Connection Pools?
Ich frage, weil nicht jedes Objekt das ich in einem Pool vorhalten möchte, auch eine SQL-Connection ist.
Die Implementierung der entsprechenden Objekte ist eigentlich MultiThread-save, sodass parallele Requests über diese Objekte (HTTP-Requests) wohl kein Problem darstellen.
Macht hier ein Pooling auch Sinn?
Das kommt darauf an.
Bei uns im Firmennetz dauert der Aufbau einer Connection ca 50 Millisekunden.
Das läßt sich unter Umständen verkraften.
Bei Connections über das Internet kann das durchaus ganz anders aussehen.
Ich denke man muß von Fall zu Fall entscheiden was sinnvoll ist.
Die Nachteile von Connectionpools werden gerne verschwiegen.
Eine?
Dutzende, eine wurde schon genannt... manche JDBC Treiber (MYSQL, etc. pp.) liefern schon einen, hoffe du hattest nicht vor den selber zu implementieren.
Interessant, bisher habe ich noch von keinem gehört - jedenfalls nicht, bei einer sauberen Implementierung. Hast Du da Erfahrungen oder Fallbeispiele?
Eine?
Dutzende, eine wurde schon genannt... manche JDBC Treiber (MYSQL, etc. pp.) liefern schon einen, hoffe du hattest nicht vor den selber zu implementieren.
Nein, Connection Pools gibt es genügend, da muss man nicht selbst ansetzen.
Ich bezog meine Frage eher auf einen "Object Pool".
Beispielsweise möchte ich HttpClients in einem Pool vorhalten - die Frage die sich mir hier stellt, ist, ob ich das mit einem Connection-Pool auch machen kann, oder nicht.
Die zweite Frage wäre dann, wenn der HttpClient multithread-fähig ist, wie viel Sinn macht es dann, einem Pool von denen vorzuhalten.
Beste Grüße und danke für das zahlreiche Feedback!
Unsere Entwickler benutzen grundsätzlich Connection Pools.
Die ein oder andere Anwendung hatt aber Performanceprobleme.
Will sagen die Anwender beschweren sich über schlechte Antwortzeiten.
Damit kommen die Entwickler zu uns (Datenbankadministration).
Und was machen wir?
Dank der Connection Pools können wir noch nicht einmal sagen ob das überhaupt stimmt.
Wir wissen noch nicht einmal, ob es sich dabei um ein Datenbankproblem handelt.
Von einer Ursachenforschung sind wir weit entfernt.
Bei einer klassischen Anwendung macht der Anwender als erstes ein CONNECT und am Ende wird die Verbindung beendet.
Dann sehen wir mit unserer Monitorsoftware auf den ersten Blick:
Wie lange hatt der Anwender gewartet.
Wieviel dieser Zeit wurde im Datenbanksystem verbracht.
Diese grundlegenden Informationen fehlen uns beim Verwenden von Connection Pools.
Unsere Entwickler benutzen grundsätzlich Connection Pools.
Die ein oder andere Anwendung hatt aber Performanceprobleme.
Will sagen die Anwender beschweren sich über schlechte Antwortzeiten.
Damit kommen die Entwickler zu uns (Datenbankadministration).
Und was machen wir?
Dank der Connection Pools können wir noch nicht einmal sagen ob das überhaupt stimmt.
Wir wissen noch nicht einmal, ob es sich dabei um ein Datenbankproblem handelt.
Von einer Ursachenforschung sind wir weit entfernt.
Bei einer klassischen Anwendung macht der Anwender als erstes ein CONNECT und am Ende wird die Verbindung beendet.
Dann sehen wir mit unserer Monitorsoftware auf den ersten Blick:
Wie lange hatt der Anwender gewartet.
Wieviel dieser Zeit wurde im Datenbanksystem verbracht.
Diese grundlegenden Informationen fehlen uns beim Verwenden von Connection Pools.
Hat die Software denn keinen Debug-Mode?
Ich mache das ganz gerne so, dass ich über bestimmte Parameter einen Modus auslöse, bei dem ich auf alles was die Performance beschleunigt verzichte, sofern solche Probleme auftreten können.
Ich dachte eigentlich, dass das "normal" wäre.
Habt ihr diese Möglichkeiten denn grundsätzlich nicht bzw. nicht daran gedacht?
Dann macht eine Poolnutzung allerdings weniger Sinn - außer als zentrale Ablagestelle für alle möglichen HttpClients. Vermute ich jetzt mal. Oder?
Danke für den Link!
Hat die Software denn keinen Debug-Mode?
Ich mache das ganz gerne so, dass ich über bestimmte Parameter einen Modus auslöse, bei dem ich auf alles was die Performance beschleunigt verzichte, sofern solche Probleme auftreten können.
Ich dachte eigentlich, dass das "normal" wäre.
Habt ihr diese Möglichkeiten denn grundsätzlich nicht bzw. nicht daran gedacht?
Ich als Datenbankadministrator habe diese Möglichkeiten jedenfalls nicht.
Unsere Entwickler scheinen auch keine Ahnung zu haben, wie sie das Problem angehen sollen.
Zumal die Software nur zur Hälfte in unserer Firma entwickelt wurde. Den Rest hatt eine externe Firma gemacht.
Die haben auch keine Idee was zu tun ist.
Jedenfalls führt das dazu, das sich die Anwender ca einmal im Monat bei unseren Chefs beschweren.
Die sagen zu uns wir sollten uns mal drum kümmern. Wir konnten bisher nur durch Unfähigkeit glänzen.
Im nächsten Monat beschweren sich die Anwender wieder. Und so weiter und so fort.
Es ist zwar OT und wurde sicherlich schon mal gecheckt, aber die Queries nutzen alle die vorgegebenen Indices - auch in der Reihenfolge, wie sie es tun sollten, oder?
Es mag zwar trivial sein, aber manchmal hat man im Join eine kleine Zeile vergessen, die dann einen Unterschied von mehreren 1000 Prozent an Performanceunterschied ausmachen.
Allerdings regt diese Erfahrung definitiv zum stärkeren Nachdenken an.
Es ist zwar OT und wurde sicherlich schon mal gecheckt, aber die Queries nutzen alle die vorgegebenen Indices - auch in der Reihenfolge, wie sie es tun sollten, oder?
Es mag zwar trivial sein, aber manchmal hat man im Join eine kleine Zeile vergessen, die dann einen Unterschied von mehreren 1000 Prozent an Performanceunterschied ausmachen.
Allerdings regt diese Erfahrung definitiv zum stärkeren Nachdenken an.
Hmh, ich kann Datenbankseitig einen Trace einschalten, der mir alle SQL-Statements und ihre Laufzeit anzeigt.
Es kommen ca 100-1000 Statements pro Sekunde. Die Laufzeit liegt von wenigen tausenstel bis zu wenigen hundertstel Sekunden.
Wie finde ich da die Stecknadel im Heuhaufen.
Alle Statements, die ich mir angekuckt habe scheinen ok zu sein. Aber ich sehe den Wald vor lauter Bäumen nicht.
Jedenfalls kann ich es nicht an einem einzelnen Statement festmachen. Aber wer weiss schon wie viele Statements eine Aktion eines Anwenders umfasst.
Wie gesagt, ich weiss noch nicht mal ob es überhaupt am Datenbanksystem liegt.
Ganz trivial im Client einfach eine Laufzeitmessung machen und wegloggen? Idealerweise sind ja die Datenbankrequests gut gekapselt - dann einfach in der aufrufenden Methode in ein log schreiben lassen was die Laufzeit ausgibt. Evtl erst ab einem gewissen Threshold zusammen mit den an die Query übergebenen Parameter.
Der Zusammenhang: Klasse ist thread-safe und Objekte in Pool vorhalten, erschließt sich mir noch nicht. Was erhoffst du dir davon, HttpClient im Pool vorzuhalten? Ist die Instanzierung teuer oder verbraucht ein Objekt davon massig Speicher?
Der Zusammenhang: Klasse ist thread-safe und Objekte in Pool vorhalten, erschließt sich mir noch nicht. Was erhoffst du dir davon, HttpClient im Pool vorzuhalten? Ist die Instanzierung teuer oder verbraucht ein Objekt davon massig Speicher?
Es handelt sich dabei um Klassen, die den Apache Commons HttpClient nutzen. Ich habe bisher noch keine Benchmarks durchgeführt, aber ich vermute mal, dass es sich beim HttpClient um ein Leichtgewicht handelt.
Der Hintergrund ist folgender: Ich habe ein Servlet mit REST-Api, welches wiederum die eigene Antwort durch den Response eines anderen Servlets anreichert.
(Servlet A fragt Servlet B nach Antwort und kombiniert die eigene Antwort mit der von B)
Der Enduser leitet seine Anfrage dabei an Servlet A. Servlet A ist verantwortlich für die Verifizierung und implementiert einen wichtigen Teil der Business-Logik, die von Servlet B getrennt bleiben muss.
Servlet A implementiert einen Client für Servlet B.
Dieser Client benötigt bei der Erzeugung einige Informationen, die aus einer Datenbank ausgelesen und aufbereitet werden müssen.
Ich möchte den Client daher in einem Pool (hier als Cache gedacht) aufbewahren, um die Requests an die Datenbank möglichst gering zu halten. Das hat den Hintergrund, dass statt einer Datenbank auch ein Config-File für die Wiedergabe derartiger Informationen zuständig sein könnte und ich Zugriffe auf das FS so gering wie möglich halten will.
Zurück zu Deiner Ausgangsfrage:
Der Zusammenhang: Klasse ist thread-safe und Objekte in Pool vorhalten, erschließt sich mir noch nicht.
Jeder Enduser erhält einen eigenen Client, den ich im Pool vorhalte. Bei dem Enduser handelt es sich dabei nicht um menschliche User, sondern um Maschinen, die ihrerseits Anfragen an die besagte Applikation weiterleiten.
Insgesamt werden wohl 100-200 verschiedene Enduser auf die Applikation zugreifen, was 100-200 verschiedene Clients im Pool ausmacht.
Jetzt zum Thread-Safe-Teil: Macht es Sinn, die Anzahl auf 400-800 zu erhöhen (4 HttpClients pro Enduser, falls dieser enorm viele Requests absendet), oder nicht? Ich versuche hierbei gerade den HttpClient mit der SQL-Connection zu vergleichen.
Ich hoffe das Anliegen ist jetzt etwas verständlicher.
Jeder Enduser erhält einen eigenen Client, den ich im Pool vorhalte. Bei dem Enduser handelt es sich dabei nicht um menschliche User, sondern um Maschinen, die ihrerseits Anfragen an die besagte Applikation weiterleiten.
Insgesamt werden wohl 100-200 verschiedene Enduser auf die Applikation zugreifen, was 100-200 verschiedene Clients im Pool ausmacht.
Jetzt zum Thread-Safe-Teil: Macht es Sinn, die Anzahl auf 400-800 zu erhöhen (4 HttpClients pro Enduser, falls dieser enorm viele Requests absendet), oder nicht? Ich versuche hierbei gerade den HttpClient mit der SQL-Connection zu vergleichen.
Ich hoffe das Anliegen ist jetzt etwas verständlicher.
Jein. Wenn du den "ConnectionPool" mit einem Commons Pool, z.B. dem GenericKeyedObjectPool implementiert hast wird der Pool dafür sorgen das er einen optimalen "Bestand" an Resourcen hat. Da kannst du halt dich mit der Poolconfig einem optimalen Wert nähern, z.B. wieviel "Connections" immer verfügbar bleiben müssen (minIdle) oder wie der Pool reagieren soll wenn das Maximum an Objecten überschritten ist,
Neben der PoolConfig die viel ausmacht ist es natürlich wichtig die ObjectFactory richtig zu implementieren und auch das der Client immer nach dem borrowObject auf jeden Fall eine releaseObject aufruft.
Aber dem Pool fest 4 Objecte pro möglichen Client zuweisen würd ich nicht machen. Zumal das mit dem CommonsPool auch nicht so einfach geht - macht aber auch wenig Sinn.
Wie viel Sinn macht es dafür überhaupt einen Pool zu nutzen?
Kann ich das nicht auch einfach in einem eigenen Cache implementieren, der auf einer HashMap aufsetzt?
Ich hole mir dann via get den Client für die aktuelle Anfrage.
Ich prüfe dann noch, ob der Client nicht vielleicht zu alt ist etc. und gebe ihn dann an den RequestHandler weiter.
Ich stelle mir deshalb vor, so etwas zu tun, weil der Client ja thread-safe ist. Das heißt 10 Threads können parallel mit dem selben Client arbeiten, ohne sich gegenseitig in die Quere zu kommen.
Die Frage, die sich mir jetzt stellt, ist, macht so ein Vorgehen gegenüber einem Pool aus sagen wir 4 Clients für einen hochfrequentierten Enduser nicht eigentlich mehr Sinn? Wozu den Client im Pool vorhalten, wenn ich immer die selbe Instanz - weil thread-safe - wiederverwenden kann?
Vorausgesetzt natürlich, ich habe keine Synchronized-Blocks in dem HttpClient (das müsste ich noch nachprüfen), dann ist auch bei Thread-Safety nicht gegeben, dass der Client wirklich parallel arbeiten kann.
Neben der PoolConfig die viel ausmacht ist es natürlich wichtig die ObjectFactory richtig zu implementieren und auch das der Client immer nach dem borrowObject auf jeden Fall eine releaseObject aufruft.
Ich verstehe gerade Bahnhof, liegt aber wohl eher daran, dass ich mir die Pools noch genauer ansehen muss.
Es geht mir hier auch eher ums Konzept - bei Connections macht es Sinn, weil ich nicht parallel mehrere Requests über die Selbe Connections senden kann. Ich möchte gerade herausfinden, ob ich den selben Sachverhalt auch auf den HttpClient übertragen kann.
Der Pool selber hält eine Menge an Objecten vor und hat unter anderem die Methoden [c]borrowObject[/c] und [c]releaseObject[/c]. Um Objecte zu erzeugen oder zu zerstören gibt man dem Pool eine ObjectFactory mit welche die entsprechenden Methoden anbietet.
Ein Client will jetzt also ein Object aus dem Pool haben. Dazu ruft er [c]Pool.borrowObject[/c] auf. Der Pool prüft dann ob es eine "freie" Instanz gibt und übergibt diese dem Client. Wenn nicht ruft der Pool die [c]Factory.createObject[/c] auf und erhöht somit der Zahl der grade aktiven Objecte im Pool. Nachdem der Client mit dem Object gemacht hat was er machen musste ruft der client [c]Pool.releaseObject[/c] auf. Damit wandert das Object zurück in den Pool und kann bei dem nächsten [c]Pool.borrowObject[/c] Call wieder herausgegeben werden
Zu deinen Connections:
Nein, auch damit kannst du nicht eine Connection parallel mit mehren Clients nutzen. Du musst immer die Connection an einen Client binden und wieder zurückgeben wenn du fertig bist. Wenn du das nicht explizit machst, dann macht es das Pooling implizit. sprich z.b. schon im MySQL Treiber.
Also machst du im Client quasi:
1) Connection c = Pool.getConnection
2) c.doQuery();
3) c.release();
Während dieses Blocks wird diese Connection nicht an einen weiteren Client gegeben. Erst nach dem release ist die connection wieder verfügbar.
Natürlich könntest du das alles mit einer HashMap und vielen hunderten an Objecten machen. ABER was eine Pool Implementierung dir abnimmt ist die Verwaltung der Objecte. Das heißt welche grade frei sind und welche "belegt". Ausserdem werden immer nur soviele Objecte im Pool gehalten wie du brauchst. Sprich es ist wesentlich resourcen schonender.
Die Pool API macht es wirklich sehr bequem mit Object Pools zu arbieten und ich würde es einer HashMap mit Objecten in deinem Fall vorziehen. Sprich:
1) HttpClient h = Pool.getHttpClient
2) h.doRequest();
3) h.release();
Das reduziert die Zahl der aktiven HttpClients und du musst dir um die Verwaltung der HttpClient Instanzen auch keine Sorgen machen. Und sei es nur das initiale Befüllen der HashMap.
Der Pool selber hält eine Menge an Objecten vor und hat unter anderem die Methoden borrowObject und releaseObject . Um Objecte zu erzeugen oder zu zerstören gibt man dem Pool eine ObjectFactory mit welche die entsprechenden Methoden anbietet.
Ein Client will jetzt also ein Object aus dem Pool haben. Dazu ruft er Pool.borrowObject auf. Der Pool prüft dann ob es eine "freie" Instanz gibt und übergibt diese dem Client. Wenn nicht ruft der Pool die Factory.createObject auf und erhöht somit der Zahl der grade aktiven Objecte im Pool. Nachdem der Client mit dem Object gemacht hat was er machen musste ruft der client Pool.releaseObject auf. Damit wandert das Object zurück in den Pool und kann bei dem nächsten Pool.borrowObject Call wieder herausgegeben werden
Ist das gerade Pseudocode? Ich frage, weil c.release() gar nicht implementiert wird - ich habe das schon an mehreren Stellen gesehen, aber nirgends einen Hinweis in den Dokus gefunden ( auch nicht in der Apache API).
Oder meinst Du eher:
1) PoolableConnection c = Pool.getConnection()
2) c.doQuery()
3) c.close() //returns c to its pool
Die Pool API macht es wirklich sehr bequem mit Object Pools zu arbieten und ich würde es einer HashMap mit Objecten in deinem Fall vorziehen. Sprich:
1) HttpClient h = Pool.getHttpClient
2) h.doRequest();
3) h.release();
Das habe ich soweit verstanden. Aber meine Frage scheint irgendwie noch unklar.
Nehmen wir mal ein einfaches Beispiel - weg von Connections, HttpClients etc.
Dies hier ist meine Klasse:
Code:
public class MyClass {
public int increment(int x, int y)
{
return (x+y);
}
}
Diese Klasse ist Threadsafe und absolut parallel arbeitend. Hundert Threads könnten myClass.increment(x, y) aufrufen, ohne sich gegenseitig zu behindern, weil sie keine gemeinsamen Ressourcen austauschen, außer der MyClass-Instanz.
Meine Frage ist jetzt eigentlich: Macht es Sinn die MyClass-Instanz in einem Pool vorzuhalten, der ggf. mehrere MyClass-Instanzen vorhält? Oder macht es keinen Sinn, weil die hier vorliegenden Methoden absolut parallel arbeiten und ich daher durch einen Pool von mehreren MyClass-Instanzen keinen Performanceschub erhalte?
Statt der increment-Methode könnte man hier jetzt auch eine hochkomplexe Methode vorstellen, die aber auch nur auf den Methoden-Input-Parametern arbeitet und nichts mit Objekten außerhalb der Methode macht.
Ich frage mich, ob das hier Sinn macht - denn die Klasse ist Threadsafe und man kann mit ihr parallel arbeiten.
Anders formuliert:
Was ist schneller (in der Ausführung, alle Objekte sind bereits erzeugt):
100 Threads, die alle die Selbe MyClass-Instanz nutzen, um die Methode increment() zu verwenen.
100 Threads, wovon jeweils 25 die selbe MyClass-Instanz nutzen,...
100 Threads, wovon jeder seine eigene MyClass-Instanz nutzt...
Davon abhängig wäre Sinn und Unsinn bezüglich des Einsatzes eines Pools für Klassen, die die vorliegenden Eigenschaften besitzen.
1) Ja - die code beispiele waren nur PseudoCode. In wirklichkeit würdest du sowas machen
Java:
Pool p = Pool.getInstance();
Object o = p.borrowObject("somekeyforobject");
try{
// do something with the object
} catch (Exception e){
// handle exception
} finally {
// make sure the object is always returned to the pool
Pool.releaseObject(o);
}
In deinem Beispiel:
100 Threads die die gleiche Instanz nutzen? Nein - würd ich nciht machen. Was machst du wenn du in Zukunft irgendwann mal die klasse erweitern willst und sie auf einmal nicht mehr Threadsafe ist?
100 Threads, 25 MyClass: Sehr stranges Design, greift Argument 1 und verkompliziert die Sache nur - warum 25?.
100 Threads jeder eine Klasse: Ja, würd ich in diesem Beispiel so machen. Wenn die Klasse so simpel is, klein und schnell erzeugt würd ich mir da gar nicht groß den Kopf zerbrechen und jedem Thread eine mitgeben, bzw anlegen lassen.
Pools lohnen sich imho wenn:
1) das Erzeugen der Shared Objecte aufwändig ist, z.B. Connections
2) die Ressourcen limitiert sind, sprich du hättest zwar gerne 500 eigene Objekte, aber ab 100 Objekte wird es dir zu speicherhungrig.
100 Threads die die gleiche Instanz nutzen? Nein - würd ich nciht machen. Was machst du wenn du in Zukunft irgendwann mal die klasse erweitern willst und sie auf einmal nicht mehr Threadsafe ist?
Das ist ein Argument - daran habe ich noch gar nicht gedacht.
Nur zur Festigung meines Verständnises über Java-Threads:
Gehen wir aber mal davon aus, dass die Klasse Threadsafe *EDIT* und parallelisierbar sein muss und der Programmierer sonst Mist gebaut hat,... wie schaut's da aus? Nach meinem Verständnis sollten 100 Threads mit der Selben Instanz die selbe Performance haben, wie 100 Threads mit 100 Instanzen, richtig?
die Ressourcen limitiert sind, sprich du hättest zwar gerne 500 eigene Objekte, aber ab 100 Objekte wird es dir zu speicherhungrig.
Gibt's da ne Möglichkeit zu testen wie groß ein Objekt (in Byte, Megabyte etc.) ist? Das wäre ganz interessant, um mal festzustellen, wie viele HttpClients ich mir überhaupt im Pool leisten kann.