Nutzung von UNIX-Sockets über JDBC-Treiber in Docker-Containern

von Tobias Kraft
Blog-Banner Nutzung von UNIX-Sockets über JDBC-Treiber in Docker-Containern

In diesem Artikel untersuchen wir die Nutzung von Unix-Sockets mit dem JDBC-Treiber (Java Database Connectivity) für den Zugriff von einer Java-Applikation auf eine Postgres-Datenbank. Es wird auf die notwendigen Konfigurations-Anpassungen eingegangen sowie das Für und Wider im Vergleich zur Nutzung des TCP/IP Stacks beleuchtet.

Die Standard Java-Applikation mit Datenbank

Wird mit einer Java-Applikation auf eine Datenbank zugegriffen, dann erfolgt dies über einen JDBC-Treiber. Die meisten Java-Applikationen konfigurieren den JDBC-Treiber für die Nutzung von TCP/IP. Damit ist es möglich, auf Datenbanken zuzugreifen, die auf anderen Servern oder über das Netzwerk bereitgestellt werden. Dies ist besonders nützlich in verteilten Systemen, wo die Datenbank auf einem separaten Host läuft.

Wird die Applikation mit docker compose betrieben, dann werden in der Konfigurations-Datei docker-compose.yml die Applikation und Datenbank jeweils als eigener Service definiert. Die Grundstruktur sieht wie nachfolgend beispielhaft dargestellt aus.

services:
  application:
    restart: unless-stopped
    image: reg.exensio.de/simulator/measure:1.1.0
    depends_on:
      - postgres
    ...
    networks:
      - default
  postgres:
    image: postgres:13.15
    restart: unless-stopped
    ...
    networks:
      - default

Für den Zugriff auf die Datenbank zeigt die JDBC-Treiber URL auf den internen Hostnamen der Datenbank, der dem Service-Namen entspricht, und hat folgenden Grundaufbau:

jdbc:postgresql://postgres:5432/appdb

Sind die genutzten Services in einer docker-compose Datei definiert, erfolgt der Betrieb auf dem gleichen Hostsystem, sodass die Frage berechtigt ist, ob nicht auch Unix-Sockets für die Verbindung genutzt werden können.

Warum Unix-Sockets?

Unix-Sockets sind nur für Prozesse auf demselben Host zugänglich. Somit sind sie sehr sicher, da das Risiko eliminiert ist, dass Datenverkehr über das Netzwerk abgefangen wird.

Des Weiteren haben Unix-Sockets eine geringere Latenz als TCP/IP, da sie keine Netzwerk-Protokolle wie IP und TCP verarbeiten müssen. Sie haben dadurch weniger Overhead und bieten eine schnellere Kommunikation zwischen Prozessen. Dies kann wiederum zu einer Leistungsverbesserung führen.

Für unseren Anwendungsfall sind potenzielle Performance-Verbesserungen der wesentliche Grund für den in Erwägung gezogenen Wechsel zu Unix-Sockets.

Konfiguration und Anpassungen

Für die Nutzung von Unix-Sockets wird die Bibliothek junixsocket benötigt, die als weitere Abhängigkeit in unsere Java-Applikation eingebunden wird. Diese Bibliothek wird vom Postgres JDBC-Treiber angesprochen. Die Zugriffs-URL für JDBC-Datenbanktreiber muss hierfür angepasst werden.

jdbc:postgresql://localhost:5432/appdb?socketFactory=org.newsclub.net.unix.AFUNIXSocketFactory$FactoryArg&socketFactoryArg=/socket-postgresql/.s.PGSQL.5432

Drei Konfigurations-Änderungen sind in der URL vorzunehmen:

  • Als host wird localhost angegeben und nicht mehr der bisherige docker service Name postgres
  • Der Parameter socketFactory referenziert die Initialisierungsklasse für den Unix-Socket aus der Bibliothek junixsocket
  • Über den Parameter socketFactoryArg wird der Pfad zum Unix-Socket der Datenbank festgelegt

Jeder docker Container läuft in seinem eigenen Kosmos und kann standardmäßig nicht auf Dateien außerhalb seines Systems zugreifen. Außerdem kann auch nicht von außen auf Dateien innerhalb des Containers zugegriffen werden. Der Einsatz von Unix-Sockets erfordert jedoch, dass der JDBC-Treiber der Java-Applikation auf den Socket der Datenbank zugreifen kann. Wie wird hier vorgegangen?

Mit der Nutzung von docker Volumes wird der Socket des Datenbank-Containers auf dem Host-System bereitgestellt. Im Applikations-Container wird der gleiche Datei-Pfad des Host-Systems ebenfalls als lesendes Volume eingebunden, sodass ein Zugriff aus beiden Containern möglich ist.

Im aufgeführten Beispiel ist das Verzeichnis socket-postgresql auf dem Host-System als Austausch-Verzeichnis konfiguriert.

services:
  application:
    restart: unless-stopped
    image: reg.exensio.de/simulator/measure:1.1.0
    depends_on:
      - postgres
    volumes:
      - ./socket-postgresql:/socket-postgresql
    ...
    networks:
      - default
  postgres:
    image: postgres:13.15
    restart: unless-stopped
    volumes:
      - ./socket-postgresql:/var/run/postgresql:ro
    ...
    networks:
      - default

Wie änderen sich die Laufzeiten?

Es erfolgten verschiedene Messungen mit beiden Varianten, wobei jeweils drei Test-Durchläufe durchgeführt wurden:

  1. Einfache Abfrage für drei kleine Datenbanktabellen mit nur jeweils ca. 100 Einträgen. 150.000 Lookup-Queries mit sich ändernden Sortierbedingungen
  2. Einfache Abfragen auf Datenbanktabellen mit mehr als 1.000.000 Einträge. 5.000 Lookup-Queries mit sich ändernden Sortierbedingungen
  3. 50 komplexe select-Abfragen mit offset Verschiebungen, die generell Laufzeiten von über einer Sekunde haben

Die erste Variante zeigte Laufzeit-Verbesserungen im Bereich von ca. 20 %, die zweite Variante brachte noch ca. 10 % und die dritte Variante war für beide Varianten gleich schnell.

Dies zeigt, dass potenzielle Performance-Vorteile stark vom Applikations-Typ abhängig sind. Werden viele kleine Abfragen ausgeführt, um beispielsweise einzelne Datensätze auszulesen, kann durchaus ein nennenswerter Performance-Vorteil erwirtschaftet werden. Der Aufwand hierfür ist überschaubar, da nur Konfigurations-Änderungen vorzunehmen sind. Werden Performance-Optimierungen im Code vorgenommen, dann ist die Umsetzung wesentlich aufwändiger und damit teurer.

Werden hingegen in einer Anwendung viele Listen angezeigt, auf denen der Anwender über die Oberfläche filtern und sortieren kann, sind Abfragen tendenziell komplexer und werden nicht so oft ausgeführt. In solchen Anwendungs-Fällen sind also kaum Laufzeit-Verbesserungen zu erwarten.

Fazit

Bevor der JDBC-Treiber von TCP/IP auf Unix-Sockets umgestellt wird, sollte auf repräsentativen Datenkonstellationen untersucht werden, ob sich in der konkreten Applikation überhaupt Performance-Vorteile ergeben und wie groß ein potenzieller Performance-Gewinn ist.
 
Unabhängig von eventuell optimierten Laufzeiten, muss im Einzelfall betrachtet werden, ob die Nutzung von Unix-Sockets möglich und sinnvoll ist.
Folgende Fragen können als Hilfestellung dienen:
  • Ist eine Nutzung mit der verwendeten Architektur überhaupt möglich?
  • Schränke ich mich durch die Umstellung zukünftig ein?
    • Kann ich dadurch später nicht skalieren, weil alles auf einer Maschine laufen muss?
    • Werden unter Umständen Hürden bei einer Migration zu einem anderen Hoster oder nach Kubernetes aufgebaut?

Zurück

© 2006-2024 exensio GmbH
Einstellungen gespeichert
Datenschutzeinstellungen

Wir nutzen Cookies auf unserer Website. Einige von ihnen sind essenziell, während andere uns helfen, diese Website und Ihre Erfahrung zu verbessern.

Sie können Ihre Einwilligung jederzeit ändern oder widerrufen, indem Sie auf den Link in der Datenschutzerklärung klicken.

Zu den gesetzlichen Rechenschaftspflichten gehört die Einwilligung (Opt-In) zu protokollieren und archivieren. Aus diesem Grund wird Ihre Opt-In Entscheidung in eine LOG-Datei geschrieben. In dieser Datei werden folgende Daten gespeichert:

 

  • IP-Adresse des Besuchers
  • Vom Besucher gewählte Datenschutzeinstellung (Privacy Level)
  • Datum und Zeit des Speicherns
  • Domain
×
Irving Tschepke
Irving Tschepke
Dipl.-Wirtsch.-Ing.
Peter Soth
Peter Soth
Dipl.-Inform. (FH)
Wir antworten in wenigen Stunden.
Oder rufen Sie einfach an:
×
Irving Tschepke
Irving Tschepke
Dipl.-Wirtsch.-Ing.
Peter Soth
Peter Soth
Dipl.-Inform. (FH)
Wir antworten in wenigen Stunden.
Oder rufen Sie einfach an:
You are using an outdated browser. The website may not be displayed correctly. Close