PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Skalieren von Verbindungen in PostgreSQL mithilfe von Connection Pooling

Das Öffnen einer Datenbankverbindung ist ein kostspieliger Vorgang, und Verbindungspooling wird verwendet, um Datenbankverbindungen offen zu halten, damit sie wiederverwendet werden können. Dadurch wird vermieden, dass Netzwerksitzungen wiederholt geöffnet, authentifiziert und die Autorisierung überprüft werden müssen. Das Pooling hält die Verbindungen aktiv, sodass bei einer späteren Anforderung einer Verbindung eine der aktiven verwendet wird, anstatt eine von Grund auf neu erstellen zu müssen.

Verbindungspooling

Das Verbindungspooling ist zu einer der gängigsten Methoden zum Umgang mit Datenbankverbindungen vor einer Abfrageanforderung geworden. Wir denken normalerweise, dass eine Verbindung zur Datenbank schnell ist, aber das ist nicht der Fall, besonders wenn eine große Anzahl von Clients eine Verbindung herstellt. Ohne Verbindungspooling würde eine Anfrage bis zu 35–50 ms dauern, um eine Verbindung herzustellen, aber 1–2 ms, wenn Verbindungspooling verwendet wird. Beim Verbindungspooling werden daher Datenbankverbindungen vorab zugewiesen und dann wiederverwendet, wenn neue Clients eine Verbindung herstellen

Gründe für Connection Pooling

  1. Um einen Absturz Ihres Servers zu vermeiden. PostgreSQL-Server sind je nach Speicherparameter auf eine Anzahl von Clients beschränkt, die sie gleichzeitig verarbeiten. Wenn diese Zahl überschritten wird, werden Sie am Ende den Server zum Absturz bringen. Beim Verbindungspooling verwenden Clients eine festgelegte Anzahl von Verbindungen.
  2. Anfrageverarbeitung erleichtern. Normalerweise werden Datenbankanfragen seriell nach dem First-In-First-Out-Kriterium ausgeführt. Bei einer großen Anzahl von Kunden würde dies ewig dauern, um diesen Prozess zu erreichen. Daher sollte der Ansatz darin bestehen, eine einzige Verbindung mit Pipeline-Anforderungen herzustellen, die gleichzeitig und nicht einzeln ausgeführt werden können.
  3. Verbessern Sie die Sicherheit. Häufig beinhaltet eine Verbindung einen Handshake, der durchschnittlich 25-35 ms dauern kann, über den ein SSL hergestellt wird, Passwörter überprüft werden und die Konfigurationsinformationen geteilt werden. All diese Arbeit für jeden verbundenen Benutzer führt zu einer umfangreichen Speichernutzung. Beim Verbindungspooling wird jedoch die Anzahl der Verbindungen reduziert, wodurch Speicherplatz gespart wird.

Arten von Connection Pooling

Grundsätzlich gibt es zwei Arten des Verbindungspoolings, es gibt jedoch eine dritte Art von Problemumgehung, die wie eine Verbindungspooling-Strategie funktioniert, die als dauerhafte Verbindungen bekannt ist.

Beständiges Verbindungspooling

Dieser Ansatz beabsichtigt, eine anfängliche Verbindung von dem Zeitpunkt an aktiv zu halten, zu dem sie initiiert wird. Es enthält die Verbindungspooling-Funktionen nicht vollständig, aber gut genug, um eine kontinuierliche Verbindung bereitzustellen. Es ist sehr hilfreich für eine kleine Gruppe von Client-Verbindungen, deren Overhead zwischen 25 und 50 ms liegen kann. Eine Einschränkung bei diesem Ansatz besteht darin, dass er auf eine Anzahl von Verbindungen zur Datenbank beschränkt ist, wobei normalerweise eine einzige Verbindung pro Eintrag zum Server besteht.

Framework-Verbindungspooling

Framework-Verbindungspooling findet auf Anwendungsebene statt, wobei immer dann, wenn Ihr Serverskript gestartet wird, ein Pool von Verbindungen eingerichtet wird, um später eintreffende Abfrageanforderungen zu verarbeiten.

Eigenständiges Verbindungspooling

Für jede Verbindung zur Datenbank wird ein Overhead-Speicher zwischen 5 und 10 MB verbraucht, um eine Anfrage zu beantworten. Das ist nicht ganz gut für eine große Anzahl von Verbindungen. Die Verwendung des Framework-Verbindungspoolings kann durch diese Anzahl von Verbindungen begrenzt werden, da es zu einer großen Speicherauslastung kommen kann. Wir entscheiden uns daher für die Verwendung des Standalone-Verbindungspoolings, das gemäß Postgres-Sitzungen, -Anweisungen und -Transaktionen konfiguriert ist. Der mit diesem Ansatz verbundene Hauptvorteil ist:minimale Overhead-Kosten von etwa 2 KB für jede Verbindung.

Wenn Sie eine Connection-Pooling-Klasse erstellen, sollte sie die folgenden Faktoren erfüllen, um die Datenbankleistung zu steigern:

  1. Verbindungen vorbelegen
  2. Verfügbare Verbindungen überwachen
  3. Neue Verbindungen zuweisen
  4. Warten Sie, bis eine Verbindung verfügbar ist
  5. Verbindung schließen
Laden Sie noch heute das Whitepaper PostgreSQL-Verwaltung und -Automatisierung mit ClusterControl herunterErfahren Sie, was Sie wissen müssen, um PostgreSQL bereitzustellen, zu überwachen, zu verwalten und zu skalierenLaden Sie das Whitepaper herunter

Verbindungen vorbelegen

Das Sicherstellen von mehr Verbindungen im Voraus erleichtert die Bearbeitung von Anfragen zu dem Zeitpunkt, an dem die Anwendung gestartet wurde. Wenn Ihr Server beispielsweise mit Java entwickelt wurde, können Sie mithilfe des folgenden Codes Vektoren verwenden, um verfügbare Leerlaufverbindungen zu speichern.

availableConnections = new Vector(connections); 
busyConnections = new Vector();
for(int i=0; i<connections; i++) {
availableConnections.addElement(makeNewConnection()); 
}

Verfügbare Verbindungen überwachen

Die Klasse sollte in der Lage sein, in einer Liste der belegten Verbindungen nach jeder freien Verbindung zu suchen und diese zurückzugeben. Dies geschieht im Wesentlichen, um eine Verbindung wiederzuverwenden oder nicht verwendete Verbindungen zu schließen. Manchmal kommt es bei Verbindungen zu einer Zeitüberschreitung, daher ist es beim Zurückgeben einer Verbindung sehr wichtig zu prüfen, ob sie noch offen ist. Wenn nicht, müssen Sie diese Verbindung verwerfen und den Vorgang wiederholen. Wenn eine Verbindung verworfen wird, wird ein Slot geöffnet, der verwendet werden kann, um eine neue Verbindung zu verarbeiten, wenn das Limit erreicht ist. Dies kann mit

erreicht werden
public synchronized Connection getConnection() throws SQLException {
if (!availableConnections.isEmpty()) { Connection existingConnection =
(Connection)availableConnections.lastElement(); int lastIndex = availableConnections.size() - 1; availableConnections.removeElementAt(lastIndex); if (existingConnection.isClosed()) {
notifyAll(); // Freed up a spot for anybody waiting.
return(getConnection()); // Repeat process. } else {
busyConnections.addElement(existingConnection);
return(existingConnection); }
} }

Neue Verbindung zuweisen

Sie sollten in der Lage sein, einen Hintergrund-Thread zu starten, um eine neue Verbindung zuzuweisen, wenn kein Leerlauf verfügbar ist und wenn das Verbindungslimit fast erreicht ist.

if ((totalConnections() < maxConnections) && !connectionPending) { // Pending = connecting in bg
makeBackgroundConnection(); }
try {
wait(); // Give up lock and suspend self.
} catch(InterruptedException ie) {} return(getConnection()); // Try again.

Warten auf eine neue Verbindung

Wenn keine Leerlaufverbindung vorhanden ist und das Verbindungslimit erreicht wurde, sollte die Konfiguration in der Lage sein, ohne kontinuierliches Pooling auf eine neue verfügbare Verbindung zu warten. Wir können dies mit der Wait-Methode tun, die eine Thread-Synchronisationssperre bereitstellt und den Thread anhält, bis eine Benachrichtigung bereitgestellt wurde.

try {
     wait();
} catch(InterruptedException ie) {} 
return(getConnection());

Für eine gute Anwendungsethik sollten Clients nicht in Echtzeit auf eine Verbindung warten, sondern Sie werden mit dem folgenden Code eine Ausnahme auslösen, wenn Verbindungen fehlen:

throw new SQLException("Connection limit reached");

Schließen der Verbindung

Wenn Verbindungen von der Garbage Collection erfasst werden, sollten Sie sie schließen, anstatt dies explizit zu tun. Wenn Sie jedoch einen expliziten Ansatz zum Schließen einer Verbindung wünschen, können Sie Folgendes verwenden:

public synchronized void closeAllConnections() {
// The closeConnections method loops down Vector, calling // close and ignoring any exceptions thrown. closeConnections(availableConnections); availableConnections = new Vector(); closeConnections(busyConnections);
busyConnections = new Vector();
}

Schlussfolgerung

Das Verbindungspooling für PostgreSQL hilft uns, die Anzahl der Ressourcen zu reduzieren, die für die Verbindung mit der Datenbank erforderlich sind, und verbessert die Verbindungsgeschwindigkeit mit der Datenbank. Dies wird erreicht, indem Verbindungen zur DB gepoolt, diese Verbindungen beibehalten und somit die Anzahl der zu öffnenden Verbindungen reduziert wird.