PostgreSQL® Archiv - Seite 6 von 8 - credativ®

Wichtige Updates – Erste Tests mit CentOS 7 und mögliche Auswirkungen

Das aktuelle Thema Meltdown und Spectre wurde in einem vorhergehenden Artikel bereits ausführlich besprochen. Dort gab es erste kleine Tests mit dem Auswirkungen von den relevanten Securitypatches auf die Geschwindigkeit des Systems. Kernelentwickler hatten bereits darauf hingewiesen, dass unter Umständen mit 5 bis 30 Prozent Geschwindigkeitseinbußen zu rechnen ist.

Es gab einige Fragen zu den Auswirkungen in CentOS 7, da einige der Securitypatches in den Kernel portiert wurden (und damit logischerweise auch in RHEL 7 zu finden sind). CentOS 7 bietet mit dem Kernel 3.10.0-693.11.6 einen aktuellen Patchlevel mit aktuellen Fixes für die beschriebenen Sicherheitsproblemen an, unter anderm auch die Backports für Kernel Page Tables Isolation (KPTI). Um vollständig alle Sicherheitsprobleme zu beheben, muss ferner die Aktualisierungen des Microcodes eingespielt werden (microcode_ctl-2.1-22.2). Red Hat hat hier einen entsprechenden Artikel online gestellt, der die Änderungen erläutert.

Ist das System nach aktuellem Kenntnisstand geschützt, kann dies über die jeweiligen debugfs Einträge abgefragt werden:

$ cat /sys/kernel/debug/x86/ibrs_enabled
0
 
$ cat /sys/kernel/debug/x86/ibpb_enabled
0
 
$ cat /sys/kernel/debug/x86/pti_enabled
1

Auf dem verwendeten virtuellen Testsystem waren IBRS und IBPB jeweils 0, da auf dem Host auch die relevanten Microcode Updates noch nicht zur Verfügung standen. Insbesondere die Variante 2 (Spectre, Branching Poisoning Attack) soll mit IBPB dann auch nicht mehr möglich sein. Ob und wie alle Einträge tatsächlich aktiviert sind, hängt von der verwendeten Plattform ab. Der Red Hat Artikel bietet hier ebenfalls eine Übersicht über die möglichen Konstellationen. Ein Folgeartikel wird sich mit den jeweiligen unterschiedlichen Einstellungen noch beschäftigen und die Performancemessungen hierfür ebenfalls wiederholen.

Mit den obigen Einstellungen für IBRS und IBPB ist das Testsystem gegen die Varianten 1 (Spectre mit Branch Bounds-checking exploit) und Variante 3 (Meltdown, Speculative Cache Loading) geschützt.

Die folgenden Messungen wurden im Vergleich mit dem vorhergehenden Patchlevel 3.10.0-693.11.1 durchgeführt, um die Auswirkungen zu testen.

Die Messungen

Wie alle Messungen sind die Zahlen im folgenden natürlich spezifisch für die verwendete Umgebung. Die Messungen sollen nicht prinzipiell die Leistungsfähigkeit demonstrieren, sondern die Auswirkungen von Änderungen im Kernel zeigen. Als Benchmark dient erneut der PostgreSQL®-eigene Benchmark pgbench mit PostgreSQL® HEAD vom 05.01.2018. Die Tests wurden auf einer CentOS 7 (7.4.1708) VM durchgeführt, ebenfalls jeweils mit 4 und 8 vCPUs. Anders als in den Tests auf der Fedora 27 Instanz standen jedoch 8 GByte RAM zur Verfügung, allerdings sollte das im wesentlichen keine Auswirkungen auf die Messung haben. pgbench wurde zunächst mit 16 Verbindungen und einem pgbench Thread gestartet. Der Testlauf hier ist SELECT-only.

1_CentOS7_KPTI_pgbench_16

Der ältere Kernel bietet bei dieser Teststellung bei 4 vCPUs ca. 10%, bei der Verwendung doppelt sovieler Prozessoren ca. 5% mehr Durchsatz (41045 zu 37050 respektive 53712 zu 51365 Transaktionen pro Sekunde). pgbench bietet auch die Möglichkeit, mehrere Threads für den Benchmark zu nutzen. Die folgende Teststellung verwendet für jede Datenbankverbindung einen eigenen Thread (Schalter -j für pgbench):

2_CentOS7_KPTI_pgbench_16_threads_16_prepared

Der Vergleich verwendet jeweils 8 vCPUs und stellt die Durchsatzraten mit Prepared Statements (Schalter -Mprepared für pgbench) und normale Statements gegenüber (letzteres ist der Standard für pgbench). Hier ergibt sich sogar ein winziger Performancevorteil für den neuen Kernel mit den sicherheitsrelevanten Patches, dieser liegt zwischen 1 und 2%. Damit liegen diese bei diesem Benchmark quasi gleichauf. pgbench unterstützt die Möglichkeit benutzerdefinierte Skripte auszuführen die es gestattet, eigene SQL Befehle für einen Testlauf zu benutzen. KPTI hat seinen größten Geschwindigkeitsnachteil theoretisch bei Workloads, wo sehr viele Context Switches und Systemaufrufe stattfinden. Im folgenden wird ein unrealistisches Szenario getestet, indem pgbench mit den identischen Laufzeitparametern zu den vorhergehenden Testfällen immer ein

SELECT 1;

verwendet. Das Ergebnis stellt sich wie folgt dar:

3_CentOS_KPTI_SELECT_One_prepared_0

Der Einbruch gegenüber dem Kernel mit KPTI ist hier deutlich. Er verliert knapp 16% gegenüber dem Kernel ohne die entsprechenden Fixes, in Zahlen sind es 167352 (3.10.0-693.11.1) gegenüber 147947 (Kernel 3.10.0-693.11.6) Transaktionen pro Sekunden.

Das ganze lässt sich noch weitertreiben, in dem gar keine Abfrage mehr ausgeführt und man daher Parser und alles nachgelagerte der Datenbank außen vor lässt. Man erreicht dies, indem pgbench lediglich ein „;“ als SQL-Skript vorgesetzt bekommt. Dies stresst hauptsächlich nur noch das System selbst, da die Datenbank im Endeffekt nichts mehr zu tun hat und lediglich Prozesse forked. Das Resultat gestaltet sich dann wie folgt:

4_CentOS_KPTI_pgbench_noop

In absoluten Zahlen stehen hier im Schnitt 254574 zu 230021 (Kernel 3.10.0-693.11.1 sowie 3.10.0-693.11.6) gegenüber. Dies entspricht 10% weniger Durchsatz im Falle des neuen Kernels. Interessant ist auch der Vergleich, falls die CPU und der verwendete Kernel kein PCID (Process-Context Identifiers) bieten. Dies bedeutet in den meisten hier getesteten Fällen einen deutlichen Einbruch der Durchsätze. Der Testfall mit pgbench und 16 Datenbankverbindungen SELECT-only (ohne Prepared Statements) mit jeweils einem eigenem pgbench Thread ergibt im Vergleich:

5_CentOS7_KPTI_pgbench_16_nopcid

Im Vergleich zum Kernel ohne KPTI hat das Fehlen der Unterstützung von PCID einen Einbruch um ca. 7% zur Folge (56232 im Vergleich zu 52757 Transaktionen pro Sekunde). Noch deutlicher fällt das Resultat im Vergleich des „noop“-Benchmarks aus. Hier beträgt der Unterschied zwischen dem Kernel ohne KPTI, mit KPTI und dem Fehlen von PCID jeweils 10% und 16%:

6_CentOS7_KPTI_pgbench_16_noop_nopcid

Interessant bei diesen Vergleichen ist noch der Einfluss von schreibenden Transaktionen. Hierzu wurde pgbench anstatt im SELECT-only Modus (Schalter -S) im TPC-B Workload getestet. Der beobachtete Trend der Geschwindigkeitseinbußen von moderat beim Kernel mit KPTI Unterstützung hin zu bemerkenswert lässt sich auch hier beobachten:

7_CentOS7_KPTI_pgbench_16_tpcb_prepared_nopcid

Fazit

In den getesteten Fällen mit pgbench zeigt sich, dass die von den Kernelentwickler pauschal angegebenen Einbußen beim Kernelupgrade durchaus realistisch sind. Allerdings kann nicht pauschal eine spezifische Zahl genannt werden, da die Einbrüche sehr stark abhängig vom Workload sind. pgbench an sich ist bereits ein sehr synthetischer Workload, der zwar die Datenbank stark stressen kann, allerdings mit der realen Welt sehr wenig gemein hat. Selbst hier bedarf es stark unrealistischer Benchmarkkonfigurationen, um die Einbrüche in den genannten Bereichen tatsächlich aufzuzeigen, nie wurde aber der Worstcase von 30 % tatsächlich erreicht. Dies bedeutet nicht, dass es den Workload mit diesen Geschwindigkeitseinbußen tatsächlich nicht gibt. Eher unterstreichen die von uns ermittelten Ergebnisse die Bedeutung von eigenen, möglichst Anwendungsnahen Tests, die spezifisch den eigenen Workload und etwaige zu erwartende Einbußen überprüfen. In der Mehrzahl pendeln sich die Unterschiede zu Ungunsten des CentOS7 Kernels mit Sicherheitspatches in etwa bei 5% ein, es können jedoch durchaus mehr sein. Besonders wenn die Unterstützung von PCID von der Plattform nicht gewährleistet wird, so kann dies deutlich höhere Einbußen nach sich ziehen, bis zu 16% in den hier gezeigten Teststellungen.

Mit Beginn des Jahres 2018 wurden Probleme mit dem Speichermanagement und Intel-Prozessoren öffentlich. Laut diesen Reports ist es offensichtlich möglich, beliebige Bereiche des Kernel- und Userspace Speicherbereiches auszulesen und damit unter Umständen auf sensitive Bereiche zugreifen zu können.

Im Laufe der letzten Tage gab es einige Gerüchte und Vermutungen, in welche Richtung dies alles geht, mittlerweile gibt es ein offizielles Statement der Hacker von Project Zero (Google), die die Erkenntnisse zusammenfassen.

Was ist genau passiert?

Im wesentlichen wurden Angriffsvektoren identifiziert, die über die nicht erfolgreiche, spekulative Ausführung von Code auf einem Prozessor und geschicktes Timing privilegierte Informationen trotz fehlender Berechtigung aus dem Cache der CPU auslesen kann. Hierbei ist es möglich, trotz der fehlenden Berechtigung (sei es aus dem User- oder innerhalb des Kernelspace) Speicherbereiche zu lesen und deren Inhalte zu interpretieren. Dies ermöglich theoretisch breitflächige Einfallstore für Schadsoftware, wie etwa das Ausspionieren sensibler Daten oder der Mißbrauch von Berechtigungen. Man spricht hier von sogenannten Side Channel Attacks. Betroffen sind nach aktuellem Kenntnisstand nicht nur Intel CPUs (von denen man ausschließlich ursprünglich ausging), sondern auch AMD CPUs, ARM sowie POWER8 und 9 Prozessoren.

Was genau geschieht aktuell?

Project Zero fasst im Report die wesentlichen Probleme zusammen. Es existieren mehrere Exploits die mit unterschiedlichen Ansätzen privilegierte Speicherbereiche lesen und damit unberechtigterweise an Informationen in sensiblen Bereichen des Kernels oder anderer Prozesse gelangen können. Da fast alle modernen CPUs die spekulative Ausführung von Anweisungen unterstützen, um ein Leerlaufen ihrer Ausführungseinheiten und damit verbundene hohe Latenzen zu verhindern, sind eine Vielzahl von Systemen theoretisch betroffen. Ein weiterer Ansatzpunkt dieses Angriffsszenarios ist die in aktuellen Systemen vorhandene Art und Weise, wie die Speicherbereiche von User- und Kernelspace interagieren. Tatsächlich war es bisher so, dass diese Speicherbereiche nicht wirklich voneinander getrennt sind, sondern der Zugriff auf diese Bereiche mit einem speziellen Bit abgesichert sind. Der Vorteil dieser nicht vorhandenen Trennung sind insbesondere dann tragend, wenn beispielsweise häufig von User- auf Kernelspace umgeschaltet werden muss.

Die Angriffsszenarien im Einzelnen sind:

  • Spectre

Dieses Angriffsszenario nutzt die in modernen CPUs vorhandene Branch Prediction, d.h. Vorabanalyse über die Wahrscheinlichkeit dass bestimmter Code bzw. -zweige erfolgreich ausgeführt werden können. Hierbei wird die CPU dazu verleitet eigentlich von der Vorhersage nicht berücksichtigten Code spekulativ auszuführen. Diese Attacke kann dann benutzt werden, um schadhaften Code auszuführen. Diese Attacke funktioniert theoretisch auf allen CPUs mit entsprechender Sprungvorhersage, allerdings ist es laut Project Zero hier schwer zusammenfassend zu sagen welche Prozessoren in welcher Art betroffen sind. Spectre hat vor allem Anwendungen im Userspace im Fokus. Da Spectre hauptsächlich dann funktioniert, wenn bereits fehlerhafter Code in entsprechenden Anwendungen vorhanden ist, sollte besonders auf entsprechende Updates geachtet werden.

  • Meltdown

Bei Meltdown wird nun die spekulative Ausführung genutzt, um Code auszuführen, der eigentlich gar nicht final erreicht werden kann. Dies sind hier Exception-Anweisungen mit nachfolgenden Instruktionen, die nie ausgeführt würden. Durch die spekulative Ausführung der CPU werden diese Instruktionen dennoch von der CPU berücksichtigt. Zwar gibt es keine Seiteneffekte durch diese Art der Ausführung, dennoch verbleiben die von der Instruktion belegten Speicheradressen im Cache der CPU und können von dort genutzt werden, um alle Speicheradressen zu testen. Da aktuell der Speicherbereich des Kernels und des Userspaces gleichermaßen zusammenhängend organisiert sind, kann so nicht nur der gesamte Speicherbereich des Kernels, sondern auch aller auf dem System laufenden Prozesse ausgelesen werden. Eine detaillierte Beschreibung der Funktionsweise des Angriffs ist hier zu finden. Meltdown funktioniert nur auf Intel Prozessoren, da nur hier die Privilegien auf den adressierten Speicherbereich bei Out-Of-Order Ausführung nicht mehr geprüft werden.

Beide Szenarios machen sich auf unterschiedliche Art und Weise die entsprechenden Sicherheitslücken zunutze. Die CVEs zu den Lücken sind im einzelnen:

Wie geht es weiter?

Um Meltdown-Attacken vorzubeugen gibt es für Linux, Windows und OSX bereits entsprechende Updates (Letzteres enthält entsprechende Änderungen bereits seit geraumer Zeit. Im wesentlichen trennen diese Updates die Speicherverwaltung für den Kernel- und Userspace völlig auf (unter Linux bekannt als KPTI-Patches, Kernel Page Table Isolation, formals auch KAISER). Hierdurch ist es nicht mehr möglich, durch die Privilege Escalation auf Intelprozessoren auf Speicherbereiche des Kernels ausgehend eines unprivilegierten Kontextes zuzugreifen. RedHat stellt diese ebenso wie CentOS und Fedora bereits mit aktualisierten Kerneln zur Verfügung.

Insbesondere die Meltdown-Attacken werden hierbei wirkungsvoll unterdrückt, für Spectre-Attacken selbst gibt es ausgehend der aktuellen Sachlage keine belastbaren, wirkungsvollen Maßnahmen. Wichtig ist jedoch, dass im Linuxkernel eBPF und die entsprechende Ausführung vom BPF-Code im Kernel deaktiviert wird.

sysctl -a | grep net.core.bpf_jit_enable
sysctl net.core.bpf_jit_enable=0

Die Änderung setzt „root“-Berechtigungen voraus.

Geschwindigkeit aktualisierter Kernel

Durch die Trennung der Speicherverwaltung für Kernel- und Userspace werden Kontextwechsel und Systemaufrufe teurer. Dies sorgt für deutlich höhere Latenzen, insbesondere wenn die Anwendung sehr viele Kontextwechsel (beispielsweise Netzwerkommunikation) verursacht. Die Einbußen hierbei sind schwierig zu bemessen, da nicht jeder Workload wirklich identische Zugriffsmuster zugrunde legt. Für kritische Systeme empfehlen sich daher Lasttests auf identischen Testsystemen falls möglich. Falls nicht möglich sollten die Lastparameter nach der Aktualisierung des Systems sorgfältig beobachtet werden. Man nimmt pauschal Geschwindigkeitseinbußen im Rahmen 5% an, letztendlich wurden jedoch auch Tests der Kernelentwickler mit bis zu 30% Einbußen beobachtet. Da die Page Table Isolation (bis jetzt) nur für x86_64 Architekturen verfügbar ist, treffen diese Zahlen tatsächlich nur auf Maschinen mit Intel Prozessoren zu. Tatsächlich wird KPTI vom Kernel Upstream standardmässig nicht für AMD aktiviert.

Ob KPTI aktiviert ist, lässt sich per Kernel-Log ermitteln:

dmesg -T | grep "page tables isolation"
[Fr Jan  5 10:10:16 2018] Kernel/User page tables isolation: enabled

Insbesondere Anwender von Datenbanken sind hier sensitiv, da zum Beispiel Systeme wie PostgreSQL® in der Regel eine hohe Anzahl Context Switches bei hoher Last verursachen. Bei credativ haben wir den Impact auf einem kleinen virtualisierten System klassifiziert. Grundlage ist ein Fedora 27 System als KVM-Gast mit 4 GByte RAM und schnellem NVMe-Speicher als Grundlage. Dies spielt bei diesem Test jedoch eher ein unbedeutende Rolle, da die mit pgbench durchgeführten Datenbanktests lediglich eine Größe von knapp 750 MByte hat. Der Shared Buffer Pool der PostgreSQL® Instanz war mit 1 GByte so konfiguriert, dass die komplette Datenbank in den Datenbankcache passt. Die Tests wurden jeweils mit 4 und 8 virtuellen Prozessoren durchgeführt. Das Hostsystem verfügt über einen Intel Core i7-6770HQ Prozessor.

Die größte Auswirkung ist zu beobachten, wenn PCID im Kernel nicht vorhanden bzw, deaktiviert ist. PCID ist eine Optimierung, die einen Flush des Translation Lookaside Buffers (TLB) verhindert, wenn ein Context Switch erfolgt. Virtuelle Speicheradressen werden nur dann erfolgreich per TLB aufgelöst, wenn die PCID zum aktuellen Thread auf der jeweiligen CPU passt. PCID steht ab kernel 4.14 zur Verfügung. Der Test vergleicht einen Entwicklerkernel mit Page Table Isolation (PTI) 4.15.0-rc6, aktuellen Fedora Upstreamkernel mit und ohne Sicherheitspatches. PTI kann deaktiviert werden, indem man dem Kernel mittels pti=off beim Booten ein entsprechendes Argument definiert.

Das Fedora Testsystem hat bereits einen sehr aktuellen Kernel (4.14). Der Unterschied zum alten Upstreamkernel 4.14.8 ohne Sicherheitsrelevante Patches beträgt zum neuen Kernel 4.14.11 ca. 6%. pgbench liefert dann folgende Durchsatzraten (Transaction per second):

TPS_KPTI

Legt man den ehemaligen Standardkernel 4.14.8 von Fedora 27 mit 100% zugrunde, ergibt sich folgendes Bild:

Percent_Kernels_KPTI

Die PostgreSQL® Community hat ebenfalls bereits kleinere Tests zum Messen der Auswirkungen durchgeführt. Die Ergebnisse decken sich mit unseren Erkenntnissen. Der neue Kernel 4.14.11 mit den relevanten Patches bietet in etwa diesselbe Performance wie der Entwicklerkernel 4.15.0-rc6 auf dieser Plattform. 4.14.11 ist in diesen Testcases sogar teilweise vor dem alten Upstreamkernel (8 vCPU, Vergleich 4.14.8, grün und 4.14.11, braun). Allerdings liegt der Vorteil hier bei knapp über 1%, so dass man hier eher davon ausgehen kann, dass bei dieser Teststellung keine großen Geschwindigkeitsunterschiede bestehen.

Für Interessierte gibt es zudem eine eigene Seite zu dem Thema. Diese fasst alle wesentliche Informationen zusammen. Empfehlenswert ist auch die Zusammenfassung des Journalisten Hanno Böck auf github, die eine sehr gute Liste aller Patches für Meltdown und Spectre bietet.

Dieser Artikel wurde ursprünglich von Bernd Helmle geschrieben.

PostgreSQL®-Hardware-Appliances von Thomas-Krenn und credativ

Freyung / Mönchengladbach, 28.11.2017 –  Die Thomas-Krenn.AG stellt vier Server-Appliances für den Einsatz des Open-Source-Datenbanksystems PostgreSQL® im Mittelstand und Enterprise-Bereich vor. Dabei handelt es sich um je zwei Systeme auf Intel-Xeon-Basis und zwei auf der OpenPower-Plattform mit POWER8-CPUs. Die Server werden mit der vorinstallierten Software-Appliance „Elephant Shed“ ausgeliefert, die eine vollständige Betriebsumgebung des Datenbanksystems bereitstellt. Den in der Appliance enthaltenen Software Support leistet das Mönchengladbacher Unternehmen credativ, das auch hinter der Entwicklung von Elephant Shed steht.

Die vier Systeme sind auf bestes Preis/Performance-Verhältnis für PostgreSQL® optimiert und wurden gemeinsam mit credativ konzipiert und getestet. Die Version 1.0 der Software-Appliance Elephant Shed ist genau auf diese Hardware abgestimmt. Sie integriert führende Open-Source-Lösungen für Database Monitoring und Alerting, Backup sowie System- und DBMS-Verwaltung. Den Anwendern steht damit ein Gesamtsystem zur Verfügung, das sich schnell und einfach in Betrieb nehmen lässt und kontinuierlich Updates und Security Patches erhält. Sämtliche Software-Komponenten sind Open Source; für den Anwender fallen weder Lizenz- noch Subskriptionskosten an.

Bereits die Hardware der Medium-Konfiguration mit Intel E5-2690v4 CPU mit 14 Cores deckt ein breites Spektrum an Datenbankanwendungen ab. Vier Intel Data Center SSDs dienen dort zum Speichern der Daten. Die High-End-Variante mit zwei Intel Xeon E5-2695v4 CPUs und insgesamt 36 CPU Cores, 512 GB RAM und acht SSDs ist für umfangreiche Datenbank-Anwendungen mit höchsten Ansprüchen an die Performance konzipiert. Die Systeme auf OpenPower-Basis sind hinsichtlich RAM und Storage identisch konfiguriert. Als CPU kommt hier ein 3,325 GHz POWER8 von IBM mit acht Cores und 64 Hardware-Threads zum Einsatz.

Bei unternehmenskritischen Datenbanken muss Service und Support durch kompetente Anbieter sichergestellt sein. Thomas-Krenn und credativ leisten deshalb umfassenden Support für Hard- und Software. Zusätzlich zum Hardware-Support von Thomas-Krenn übernimmt credativ den Support für sämtliche Software-Komponenten der Appliance. Im Gegensatz zu vielen anderen Anbietern koppelt credativ Supportleistungen nicht an bestimmte Hardware. Der Basis-Support plus zwei Inklusiv-Stunden pro Monat kann also für eine beliebige Anzahl von Appliances verwendet werden. Flexible Erweiterungen des Support-Kontingents, beispielsweise 24/7 Support, oder PostgreSQL®-Schulungen, lassen sich problemlos hinzubuchen.

„Unsere Kunden lieben Open Source; auch und gerade bei Datenbank-Systemen, da hier einzelne proprietäre Anbieter die Lizenzschraube immer weiter anziehen. Dem Markt die passenden, attraktiven Open-Source-Angeboten zur Verfügung zu stellen, ist ein fester Bestandteil unserer Mehrwert-Strategie“, so Dr. David Hoeflmayr, CEO der Thomas- Krenn.AG, „Das geht nicht ohne Partner. Die credativ GmbH mit ihrer konsequenten Ausrichtung auf Open Source Software, langjähriger Expertise im PostgreSQL®-Umfeld und seinem fairen, transparenten Support-Modell ist für uns der ideale Partner, um Open-Source-Datenbanksysteme für Mittelstand und Enterprise-Kunden anzubieten.“

Sascha Heuer, Geschäftsführer der credativ GmbH ergänzt: „Die credativ GmbH ist für Ihre klare und konsequente Open Source Strategie international bekannt. Daher freue ich mich sehr, dass wir nun diese Partnerschaft ins Leben rufen konnten, denn auch die Thomas-Krenn AG engagiert sich seit vielen Jahren sehr stark im Open Source Umfeld. Unsere gemeinsame PostgreSQL® Appliance ist in Ihrer Art wahrscheinlich einmalig, und zeigt in eindrucksvoller Weise den enormen Mehrwert von wirklich freien Open Source Projekten. Im Unterschied zu anderen Projekten haben wir uns ganz bewusst für eine vollständig freie Lösung entschieden, die mit keinerlei Lizenz- oder Subskriptionskosten versehen ist und einen Vendor-Lock vollständig vermeidet.“

Über die credativ GmbH:
Die credativ GmbH ist ein herstellerunabhängiges Beratungs- und Dienstleistungsunternehmen mit Standorten in Mönchengladbach und München, sowie Schwesterunternehmen in USA, Indien, Spanien und den Niederlanden. Bereits seit 1999 fokussiert sich die credativ GmbH vollständig auf die Planung und Realisierung professioneller Businesslösungen unter Verwendung von Open Source Software. Seit Mai 2006 betreibt die credativ GmbH das deutsche Open Source Support Center (OSSC) und bietet damit einen professionellen 24×7 Enterprise Support für zahlreiche Open Source Projekte. Darüber hinaus leistet das deutsche PostgreSQL® Competence Center mit seinem dedizierten Datenbank-Team einen umfassenden Service für das objektrelationale Datenbanksystem PostgreSQL®. In Deutschland beschäftigt die credativ GmbH 50 Mitarbeiter.

Über die Thomas-Krenn.AG:
Die Thomas-Krenn.AG ist ein führender Hersteller individueller Server- und Storage-Systeme sowie Anbieter von Lösungen rund um das Rechenzentrum. Zu den mehr als 15.000 Kunden aus ganz Europa gehören Großkonzerne, öffentliche Verwaltung, IT-Dienstleister, Bildungseinrichtungen sowie eine Vielzahl kleiner und mittelständischer Unternehmen. Der Onlineshop der Thomas-Krenn.AG bietet Kunden eine europaweit einzigartige Möglichkeit, in kürzester Zeit maßgeschneiderte Server mit geprüften Komponenten zu konfigurieren und bereits am nächsten Tag zu installieren. Das Unternehmen produziert mit derzeit 150 Mitarbeitern alle Server in Deutschland am Standort Freyung. Seit ihrer Gründung im Jahr 2002 weist die Thomas-Krenn.AG ein stetiges Wachstum aus eigener Kraft auf.

Weitere Informationen:
https://www.thomas-krenn.com/de/loesungen/postgresql.htm
https://www.credativ.de/elephant-shed
https://elephant-shed.io/de/

Kontakt credativ GmbH:
credativ GmbH
Trompeterallee 108
41189 Mönchengladbach
www.credativ.de

Pressekontakt:
Michael Amstadt, Leiter Marketing/Vertrieb DACH
Telefon: +49 2166 9901-160
Telefax: +49 2166 9901-100
E-Mail: michael.amstadt@credativ.de

Weitere Informationen:
Sascha Heuer, Geschäftsführer
Telefon: +49 2166 9901-0
Telefax: +49 2166 9901-100
E-Mail: sascha.heuer@credativ.de

Kontakt Thomas-Krenn.AG:
Thomas-Krenn.AG
Speltenbach-Steinäcker 1
94078 Freyung
www.thomas-krenn.com

Ulrich Wolf
Telefon: +49 8551 9150-721
E-Mail: presse@thomas-krenn.com

Dieser Artikel wurde ursprünglich von Philip Haas geschrieben.

Ab sofort steht die credativ PostgreSQL® Appliance als vollständig freie Open Source-Lösung zum Download zur Verfügung. Die neue Appliance mit dem Namen ‚Elephant Shed PostgreSQL® Appliance‚ bietet eine enorme Erleichterung für den Betrieb von PostgreSQL® im Unternehmenseinsatz. Die zukünftige und langfristige Pflege der Appliance wird durch die PostgreSQL®-Experten der credativ übernommen. Vorbereitete Images für die wichtigsten Cloud- und Virtualisierungsplattformen sind bereits in Arbeit und werden zeitnah für VMWare, Virtualbox, Vagrant und für die Cloud-Plattformen Microsoft Azure, Amazon Web Services und Google Cloud Platform veröffentlicht.

Elephant Shed baut auf bewährten Komponenten auf, die ausschließlich unter anerkannten Open Source Lizenzen veröffentlicht werden. Diese Tools sind eine wirkungsvolle Unterstützung für das Management eines PostgreSQL® Servers. Alle verwendeten Komponenten sind vorinstalliert und in die integrale Automatisierung eingebunden. Die Mehrzahl dieser Tools kann über eine komfortable Weboberfläche benutzt werden.

Service und Support

Für Elephant Shed bietet die credativ einen umfassenden technischen Support mit garantierten Service-Level-Agreements, der optional auch an 365 Tagen im Jahr rund um die Uhr zur Verfügung steht. Eine Unterstützung bei der Installation und Integration, sowie eine Einführung in Elephant Shed ist selbstverständlich auch Bestandteil der Services von credativ.

Für Fragen zu Elephant Shed und unseren Service- und Supportleistungen stehen wir Ihnen gern zur Verfügung.

Weitere Informationen finden Sie auf unserer Elephant Shed-Projektseite sowie auf Github.

Neben anderen Indextypen wie B-tree und BRIN, gibt es in PostgreSQL® seit langer Zeit den Hashindex. Von diesem wurde jedoch bisher oft abgeraten, da dieser Index keine REDO-Informationen im Transaktionslog (Write Ahead Log, WAL) unterstützte und  damit weder Crash noch Replikationssicher war. Stürzte die PostgreSQL® unter Umständen ab, musste der Hashindex mit dem REINDEX Kommando neu erzeugt werden, da ansonsten Inkonistenzen auftreten konnten. PostgreSQL® Standbysysteme konnten bei Abfragen entsprechende Hashindexe nicht verwenden, da durch das Fehlen jeglicher Protokollierungen über das WAL diese nicht repliziert wurden.

In PostgreSQL®10 ändert sich dies, denn mit den Patch write-ahead logging support to hash indexes hat der Hashindex fehlende Funktionen dazugelernt und steht für das Featurerelease 10 bereit. Grund genug die Funktionsweise und Usecases zu beleuchten.

Theorie

In der Theorie sind Hashindexe zunächst recht simpel. Die Voraussetzung ist, dass das Hashing eines Wertes eine Position im Index definiert, welche die Zielinformation beinhaltet. Dadurch kann, mittels nur eines Indexschrittes, die Position im Heap bestimmt werden. Die Laufzeit in Relation zur Datenmenge ist demnach O(1), also somit sind die Zugriffszeiten im Hashindex im Ideal konstant. Ein sortierter Index, wie etwa der B-tree, erreicht dieses Ziel auch, jedoch in der Regel in O(log(n) ), denn hier muss eine Baumstruktur von Wurzel bis Blatt traversiert werden. Dies bedeutet in der Regel mehrere Zugriffszyklen, bis das richtige Blatt gefunden wurde.

Die PostgreSQL® Implementierung des Hashindex basiert dabei auf dem Paper A new Hashing Package for UNIX von Selzer und Yigit. Diese Implementierung erreicht durch die Verwendung einer Metapage, den Zielbuckets sowie Overflowbuckets, dynamisches Wachstum des Indexes, behält jedoch das typische Laufzeitcharakteristikum der Hashindexe bei.

Laufzeit

In der Praxis divergiert primär die Rechenzeit. Hierbei gewinnt der Hash dann, wenn das Hashing des Wertes selbst billiger wird, als die  notwendigen Vergleiche und Sprünge im B-tree. Hier ist eine Differenzierung des Vergleiches notwendig, denn der Vergleich zweier Ganzzahltypen ist beispielsweise deutlich billiger als der alphanumerische Vergleich zweier Zeichenketten, wie das folgende Beispiel anhand einer Sortierung illustriert.

EXPLAIN ANALYZE SELECT id FROM generate_series(1,100000)id ORDER BY 1 DESC Time: 0.3s
EXPLAIN ANALYZE SELECT id::text FROM generate_series(1,100000)id ORDER BY 1 DESC Time: 2.4s

Überträgt man diese Gegebenheit auf die Kosten der notwendigen Vergleiche eines Indexlookups, ergibt sich folgendes Bild:

WAL-Logged Hashindex TPS comparison

Der hier beschriebene Benchmark basiert auf vier nebenläufigen Verbindungen, welche zufällige Elemente aus einer Tabelle selektieren. Diese Elemente sind Textfelder. Bei der Testgruppe ’similar‘, sind die ersten Stellen des Keys identisch, bei ‚random‘ ist die gesamte Zeichenfolge zufällig. Der Datenbestand ist komplett gecached. Gemessen wird die hauptsächlich durch Rechenoperationen bedingte Laufzeit der Abfragen. Die Keys der Lookups werden in den Abfragen durch Funktionen definiert, dadurch sind die beiden Testsets in dem konkreten Durchsatz durch den unterschiedlichen Aufwand nicht miteinander vergleichbar.

CREATE TABLE test(key_1 text, key_2 text);
CREATE INDEX ON test USING HASH(key_1);
CREATE INDEX on test(key_2);
 
Sorted:
INSERT INTO test SELECT repeat('x', :width )||id , repeat('x', :width )|| id FROM generate_series(1, :scale ) id;
 
Random:
INSERT INTO test SELECT substr(md5(id::text)||repeat('x', :width -32 ), 0, :width ) , substr(md5(id::text) || repeat('x', :width -32),0, :width ) FROM generate_series(1, :scale ) id;

 

Es wird deutlich, dass die Kosten der Schlüsselsuche im B-tree mit seiner Länge skalieren. Da ein B-tree von Links nach Rechts vergleicht, ist eine deutliche Regression bei Keys zu erkennen, die über viele Zeichen ähnlich sind, wie es beispielsweise für URIs typisch sein kann.

PageFetches

Die Laufzeit des Hashindex beruht auf der Annahme, das Zieltupel könne durch die vom Hash des Keys berechnete Indexseite bestimmt werden. Die zusätzliche Metapage und gegebenenfalls auftretenden Overflowpages fallen ebenfalls ins Gewicht, doch die Metapage ist immer im Cache, und die Overflowpage statistisch eher unwahrscheinlich.

Dadurch erreicht der Hashindex eine sehr gute Laufzeit bei langsamen Random-Reads und eignet sich damit für Indexe, die selten verwendet werden, für den verfügbaren RAM deutlich zu groß, oder aus anderen Gründen nicht im RAM sind.

WAL-Logged Hashindex Pagefetch Comparison

Der Benchmark zeigt, dass die Pagefetches des Hashindex bei vielen Tupeln weit unter denen des B-tree liegt. Betrachtet man eine Fetchdifferenz von vier mit einer durchschnittlichen IO-Wartezeit der Reads von 8ms wie es für 7200rpm HDDs typisch ist, würden hier Latenzunterschiede von bis zu 32ms pro Abfrage verzeichnet werden. Zudem ist der Randomread Durchsatz jedes Systems technisch limitiert, wodurch der Hash durch bessere Ressourcennutzung mehr Nebenläufigkeit erlauben kann.

Größe

Hashindexe verwenden eine feste Keygröße. Damit ist die Größe des Index nur mit der Tupelmenge und nicht der Tupelgröße korelliert, was einen deutlichen Unterschied zu dem B-tree darstellt. Ein Hashindex ist bei der Betrachtung von Ganzzahltypen zwar bis zu 40% größer, bei variabler Keygröße wie sie bei Zeichenketten oft vorkommt dann jedoch deutlich kleiner.

WAL-Logged Hashindex Size comparison

Upgrade von früheren PostgreSQL® Versionen mit pg_upgrade

Aufgrund der beschriebenen Änderungen ist die physische Repräsentation von Hashindexe zwischen älteren PostgreSQL® Versionen (< 10) und PostgreSQL® 10 nicht mehr kompatibel. Wählt man als Upgradepfad den Weg über physisches Upgrade per pg_upgrade, so müssen alle Hashindexe per REINDEX neu erzeugt werden. pg_upgrade erkennt alle verwendeten Hashindexe in einer Instanz und invalidiert diese. Daher sind diese nicht mehr unmittelbar von der Datenbank nutzbar.  pg_upgrade gibt bei der Überprüfung des Datenbankclusters einen Hinweis aus, ob Hashindexe verwendet werden und diese überführt werden müssen:

Your installation contains hash indexes.  These indexes have different
internal formats between your old and new clusters, so they must be
reindexed with the REINDEX command.  After upgrading, you will be given
REINDEX instructions.

Nach dem pg_upgrade-Lauf findet man Arbeitsverzeichnis ein SQL-Skript reindex_hash.sql, das die notwendigen REINDEX-Kommandos für das Wiederaufbauen der Hashindexe enthält.

Zusammenfassung

Hashindexe bieten sich also besonders dort an, wo teure Operatoren oder große Datensätze den Index definieren. Die Verteilung der zugrundeliegenden Daten sollte zudem zufällig sein, denn der Hashindex unterstützt keine Bereichsabfragen (<, > sowie >= und <=) und auch eine Cacheaffinität ähnlicher Werte ist nicht gegeben. Können diese Annahmen über die Datenmenge getroffen werden, können die Vorteile des Hashindex einen deutlichen Mehrwert erreichen.

Weiterführende Links:

Dieser Artikel wurde ursprünglich geschrieben von Julian Schauder.

Im Zuge der Veröffentlichung von PostgreSQL® 9.5 wurde bereits einen Blogpost zum Thema veröffentlicht um eine grobe Einführung in „Block Rang INdexe“ (BRIN) sowie deren Vor- und Nachteile zu gegeben. Durch PostgreSQL® 10.0 wird hier jedoch ein kleines Update nötig. Sollten Sie sich für eine Einführung in das Thema interessieren, empfiehlt es sich erst den ursprünglichen Post PostgreSQL® 9.5: Block Range Index (BRIN) zu lesen und anschließend dieses Update.

Problem

Eines der Probleme bei Einsatz von BRIN ist, dass sich ändernde Tabellen die Qualität und damit Effektivität des Index verringern. Im Gegensatz zum Btree-Index, dem Standard in PostgreSQL®, muss ein BRIN manuell gepflegt werden. Dies kann z.B. durch den Aufruf von REINDEX oder VACUUM FULL erreicht und durch Cron-Jobs automatisiert werden.

Diese Konstrukte sind jedoch problematisch, oder zumindest unschön und werden auch schnell vergessen. Daher sollten solche „Krücken“ immer mit einem entsprechenden Monitoring überwacht werden.

Lösung in PostgreSQL® 10.0

Mit PostgreSQL® 10.0 ändert sich die Situation jedoch. Die Erweiterungen sind selbstverständlich bereits in der Dokumentation erläutert (BRIN – Index Maintenance). Um die BRIN-Pflege zu automatisieren wurde VACUUM so erweitert, dass es beim bearbeiten einer Tabelle auch die zugehörigen Block-Range-Indizes aktualisieren kann. So wird die Aktualisierung sowohl beim manuellen als auch bei Autovacuum durchgeführt.

Anwendung

Wer bereits Block-Range-Indizes verwendet muss diese entsprechend anpassen. Damit VACUUM die Funktion übernimmt muss für jeden Index autosummarize gesetzt werden. Dies geschieht einfach beim CREATE durch den zusätzlichen Parameter autosummarize=true.

CREATE INDEX brin_test_time_auto_brin ON brin_test USING brin (TIME) WITH (autosummarize=true);
CREATE INDEX brin_test_time_auto_brin_128  ON brin_test USING brin (TIME) WITH (pages_per_range=128,  autosummarize=true);

Wenn Tabellen stark verkleinert werden und die dazugehörigen Indizes auch verkleinert werden sollen ist weiterhin ein VACUUM FULL notwendig. Auf Grund der geringen Größe der BRIN ist ein direkter Nutzen hier jedoch oft nicht gegeben.

Anwendertests

Um das Verhalten der Änderungen und die Auswirkungen besser zu verstehen, wurden von uns einige Tests durchgeführt. Hierbei wurde prompt ein Bug im geänderten Code entdeckt. Dieser führte zu einem Fehler, wenn ein BRIN mit abweichenden pages_per_range und autosummarize sowie CONCURRENTLY angelegt wurde. Trotz, dass es sich hier um eine Developmentversion handelt wurde der Fehler noch in der Nacht von der Community behoben.

Dies ist ein guter Anlass einmal darauf hinzuweisen, als interessierter PostgreSQL®-User, gerade neue Features schon in einer frühen Phase ausgiebig zu testen.

PostgreSQL® besitzt natürlich Regressiontests und auch das Fuzzingtool SQLsmith von unserem Kollegen Andreas Seltenreich trägt zur Qualitätssicherung bei. Jedoch sind ausgiebige Anwendertests immer sinnvoll und auch im eigenen Interesse der Nutzer. Aals Softwareentwickler bietet es sich zudem an, die eigene Anwendung hin und wieder gegen den aktuellen Stand der PostgreSQL®-Entwicklung zu testen. Dies lässt sich natürlich auch gut in die eigene CI-Toolchain integrieren. So wird zusätzlich ganz nebenbei der Zeitaufwand, um die Kompatibilität mit dem nächsten Release sicher zu stellen, deutlich reduziert.

Weiterführende Links

Dieser Artikel wurde ursprünglich von Alexander Sosna verfasst.

Die pgAudit-Erweiterung erlaubt es, Zugriffe auf eine PostgreSQL®-Datenbank feingranular zu auditieren. Unter anderem ist sie ein wichtiger Bestandteil des kürzlich veröffentlichten PostgreSQL® STIG („Security Technical Implementation Guide“) des amerikanischen Verteidigungsministeriums. Von uns im Rahmen des pkg-postgresql Projekts erstellte Debian-Pakete sind nun im offiziellen PostgreSQL® APT-Repository, sowie den Entwickler-Zweigen von Debian und Ubuntu verfügbar.

PostgreSQL® bietet zwar von sich aus konfigurierbare Protollierung an, die von pgAudit ausgegeben Audit-Meldungen gehen hier aber deutlich weiter und decken auch die meisten Compliance-Richtlinien ab. Sie werden auch in das PostgreSQL®-Log geschrieben, allerdings in einem einheitlichen Format und im Gegensatz zu dem üblichen Logging via z.B. log_statement auf der einen Seite deterministisch und umfassend und auf der anderen Seite gezielt. So war es zwar schon bisher möglich z.B. ausgeführte SELECT-Befehle protokollieren zu lassen um etwa nicht erwünschte Zugriffe auf eine bestimmte Tabelle zu sehen, da dies dann allerdings für alle SELECT-Befehle gilt ist dies in der Praxis nicht handhabbar. Mit dem sogenannten Objekt-Audit-Logging von pgAudit ist es möglich, nur Zugriffe auf bestimmte Tabellen in das Audit-Log zu schreiben, indem man einer Auditor-Rolle entsprechende Berechtigungen zuweist z.B.:

Datenbank vorbereiten

CREATE ROLE AUDITOR;
SET pgaudit.role = 'auditor';
CREATE TABLE account
(
    id INT,
    name TEXT,
    password TEXT,
    description TEXT
);
GRANT SELECT (password) ON public.account TO auditor;

Abfragen, die die Spalte password betreffen (und nur solche) erscheinen nun im Audit-Log:

SELECT id, name FROM account;
SELECT password FROM account;
AUDIT: OBJECT,1,1,READ,SELECT,TABLE,public.account,SELECT password FROM account

Inhalt des Logs

Das erste Feld ist entweder SESSION oder OBJECT für den entsprechenden Audit-Logging Typ. Die beiden darauffolgenden Felder sind Statement-IDs, das vierte Feld die Klasse der Abfrage (READ, WRITE, ROLE, DDL usw.), gefolgt von dem Kommando-Typ und (falls zutreffend) dem Objekt-Typ und -Namen; das letzte Feld ist schließlich das tatsächlich ausgeführte Kommando. Für das Auditing entscheidend ist, dass die tatsächlich ausgeführten Befehle protokolliert werden, so dass Umgehungen durch mutwillige Obfuskation nicht möglich sind. Ein Beispiel hierfür aus der pgAudit-Dokumentation ist:

AUDIT: SESSION,1,1,FUNCTION,DO,,,"DO $$
BEGIN
    EXECUTE 'CREATE TABLE import' || 'ant_table (id INT)';
END $$;"
AUDIT: SESSION,1,2,DDL,CREATE TABLE,TABLE,public.important_table,CREATE TABLE important_table (id INT)

Wie man am verwendeten Kommando (Zeilen 1-4) sieht wird hier versucht, den Tabellennamen important_table nicht in der Logdatei erscheinen zu lassen, pgAudit loggt hier allerdings zuverlässig den Tabellennamen (Feld 7), sowie die tatsächlich Ausgeführte CREATE TABLE-Anweisung. Im Fall des konventionellen PostgreSQL®-Logs ist dieser Versuch allerdings erfolgreich, hier wird lediglich der eingegebene Befehl geloggt:

LOG:  statement: DO $$
BEGIN
    EXECUTE 'CREATE TABLE import' || 'ant_table (id INT)';
END $$;

Die pgAudit-Erweiterung kann prinzipiell ab Version 9.5 von PostgreSQL® verwendet werden. Die von uns paketierte Version 1.1 von pgAudit unterstützt offiziell zwar nur 9.6, das erstellte Debian-Paket kann allerdings durch einen zusätzlichen Patch auch mit 9.5 verwendet werden. Auf apt.postgresql.org stehen deshalb Pakete sowohl für 9.6 als auch für 9.5 unter allen unterstützten Debian- und Ubuntu-Version bereit.

 

Lesen Sie auch:

Vor einiger Zeit gab es einen großflächigen Ausfall bei Gitlab. Die Administratoren haben diesen in beispielhafter Weise dokumentiert und auch ein  Post-Mortem dazu veröffentlicht. Wir von credativ haben nun eine erste Änderung für eines der Probleme in Postgres eingebracht, die Datenbank-Administratoren in ähnlicher Lage in Zukunft helfen soll.

Ein Teil des Problems trat bei der Verwendung des pg_basebackup-Programms zum Aufsetzen eines neuen lesenden Postgres-Standbys auf, nachdem der eigentliche Standby auf Grund von zu großem Replikations-Verzug und fehlender Transaktionslog-Archivierung nicht mehr verwendbar war.

Die Administratoren haben pg_basebackup ausgeführt, jedoch dieses mehrmals abgebrochen, nachdem weder im normalen Betrieb, noch mit der Option –verbose eine Ausgabe erfolgte und weder Netzwerkverkehr stattfand noch Daten in das Speichersystem geschrieben wurden. Offenbar haben sie vor jedem Aufruf von pg_basebackup das gewünschte Daten-Verzeichnis gelöscht, wobei schließlich aus Versehen das Datenverzeichnis des Master-Servers gelöscht wurde.

Was die Gitlab-Administratoren zu dem Zeitpunkt nicht wussten: Vor Beginn der Übertragung des Datenverzeichnisses vom entfernten Server muss auf diesem ein sogenannter Checkpoint geschrieben werden, bei dem alle ausstehenden Transaktionslogs in das Datenverzeichnis persistiert werden, so dass dieses konsistent ist. Dies kann bei einer hohen Anzahl an ausstehenden Änderungen an dem Datenbestand unter Umständen mehrere Minuten dauern.

Das Postgres-Projekt hat jetzt mit einer ersten kleinen Änderung auf das Gitlab-Problem reagiert: Zum einen wurde die Durchführung des Checkpoints in der Dokumentation des pg_basebackup-Programms unter „Notes“ erwähnt, zum anderen wurde die Ausgabe von pg_basebackup so angepasst, dass  zumindest bei der Verwendung der –verbose oder –progress Optionen eine hilfreiche Mitteilung bzgl. dem andauernden Checkpoint erfolgt.  Diese Änderungen wurden von credativ erstellt und wurden inzwischen in den offiziellen Postgres-Quellcode aufgenommen und werden auch in den nächsten Wartungs-Releases der Postgres-Versionen 9.4 bis 9.6 enthalten sein.

Seit dem 07. April 2017 befindet sich die aktuelle Entwicklerversion von PostgreSQL® für das nächste Hauptrelease im Feature Freeze. Dies bedeutet, dass keine neuen Features in den aktuellen Entwicklerzweig aufgenommen werden dürfen. Zeit also, einen Blick auf die kommende Version 10.0 der freien Datenbank zu werfen.

Die augenscheinlichste Neuerung finden aufmerksame Leser bereits in der Einleitung dieses Artikels: Die Änderung an der Versionsnummer. Diese folgte seither einer dreistelligen Nomenklatur:

HAUPTVERSION - FIRST . HAUPTVERSION - SECOND . MINOR

Die Hauptversion wird durch die ersten beiden Stellen der Versionsnummer gebildet. Die dritte Stelle gibt immer die sogenannte Minorversion an, also z.B. den Patchlevel der jeweiligen Hauptversion. Aktuell sind also demnach folgende Hauptversionen von PostgreSQL® unterstützt:

  • 9.6
  • 9.5
  • 9.4
  • 9.3
  • 9.2

Hauptversionen sind einander inkompatibel, d.h. ein Datenbankcluster initialisiert mit PostgreSQL® 9.2 kann nicht einfach mit einer Version 9.3 gestartet werden. Datenbankkatalog aber auch binäre Abweichungen spielen hier eine wichtige Rolle, weshalb man nicht einfach durch Installation und Neustart auf eine neue Version wechseln kann. Die dritte Minornummer gibt den Patchlevel der jeweiligen Hauptversion an und diese sind natürlich ohne weiteres durch ein Update der PostgreSQL® Installation aktualisierbar.

Die kommende Version 10 von PostgreSQL® bricht nun mit dieser Methodik und kürzt die Hauptversion auf eine einzige Zahl, die zweite Nummer ist dann der jeweilige Patchlevel:

HAUPTVERSION . MINOR

D.h. mit Erscheinen von PostgreSQL® 10 im Herbst diesen Jahres sieht die Liste der Versionen (vorerst) aus wie folgt:

  • 10
  • 9.6
  • 9.5
  • 9.4
  • 9.3
  • 9.2

PostgreSQL® 10.0 markiert dann die erste Version im neuen Zweig. Die folgenden Patchlevel werden dann 10.1, 10.2, 10.3 usw. bekommen. Die nächste Hauptversion wird dann folglich PostgreSQL® 11.0 heißen. Die Version 9.2 wird dann auch im September 2017 auslaufen. Die alten Versionen werden die bisherige dreistellige Versionsnummer beibehalten.

Dieser Artikel markiert den Auftakt zu einer Serie von Themen rund um die kommende Version von PostgreSQL® 10.

Einleitung

Heute muss nicht mehr argumentiert werden, warum zentrales Logging sinnvoll oder sogar notwendig ist. Die meisten mittelständischen Unternehmen haben mittlerweile ein zentrales Logging oder führen dieses gerade ein.

Wenn die Infrastruktur einmal geschaffen ist, gilt es diese sinnvoll und effizient zu nutzen! Gerade als Infrastrukturbetreiber oder Dienstleister geht es darum verschiedene Akteure, mit verschiedenen Anforderungen, bestmöglich zu unterstützen. So sollte z.B. die Entwicklungsabteilung kontinuierlich Zugriff auf alle Logs ihrer Testsysteme haben. Aus der Produktion werden aber vielleicht nur alle Fehlermeldungen in Echtzeit benötigt, auf Freigabe jedoch auch mehr.

Solche Modelle lassen sich mit graylog® oder Kibana® leicht umsetzen und testen. Die Klassifizierung und Auswertung mag im Testbetrieb oder in kleinen Umgebungen auch mit den PostgreSQL®-Standardeinstellungen gut und performant funktionieren. Werden jedoch sehr viele Datenbanken betrieben oder die Logs lange aufgehoben, kann die Nutzung schnell schwierig werden.

Problemstellung

Die Logeinträge sind zentral erfasst und können prinzipiell verwendet werden. In der Praxis ist es jedoch schwierig bis unmöglich alle relevanten Informationen zeitnah zu extrahieren. Die Suche nach bestimmten Einträgen erfordert Volltextsuchen mit Wildcards, dies ist bei großen Datenbeständen nicht mehr praktikabel ist.

Möchte man beispielsweise bestimmten Gruppen ausschließlich Zugriff auf Logs geben, die bestimmten fachlichen Kriterien entsprechen, z.B. Datenbankname, error_severity oder der gleichen, muss dies über Volltextsuche und fehleranfällige Filter realisiert werden.

Möchte ein DBA z.B. alle Meldungen eines bestimmten Users, einer bestimmten Query oder einer Session sehen, wird hierzu eine besonders aufwendige Indizierung für Wildcard-Suchen benötigt. Alternativ sind solche Anfragen sehr langsam und können nicht sofort beantwortet werden.

Ausgangspunkt:Es wurde bereits ein Zentrales Logging eingeführt, z.B. ELK-Stack oder graylog®.
Ziel:Wir möchten die PostgreSQL®-Logmeldungen semantisch erfassen und dadurch effizient: klassifizieren, gruppieren und auswerten.

Alternative

Die Alternative besteht nun darin, die Logmeldungen semantisch zu erfassen und die einzelnen Felder in einer entsprechenden Datenstruktur abzulegen.

Wird das normale stderr-Log verwendet, gestaltet sich das Parsen als schwierig bis unmöglich, da die einzelnen Felder hier nicht zu erkennen sind. PostgreSQL® bietet jedoch auch die Möglichkeit Logmeldungen im CSV-Format zu produzieren (csvlog). Hiermit werden alle Felder Komma separiert ausgegeben.

Exkurs: Die Idee ist nicht neu. Seit Langem laden einige DBAs ihre Logs direkt wieder in eine PostgreSQL®-Tabelle. So können die Logs mit SQL und allen bekannten Boardmitteln durchsuchen und bearbeiten. Die DBAs sind meist sehr zufrieden mit diesem Konstrukt, es stellt jedoch eine Insellösung dar. Beispieltabelle PostgreSQL® 9.5:

CREATE TABLE postgres_log
(
  log_time timestamp(3) with time zone,
  user_name text,
  database_name text,
  process_id integer,
  connection_from text,
  session_id text,
  session_line_num bigint,
  command_tag text,
  session_start_time timestamp with time zone,
  virtual_transaction_id text,
  transaction_id bigint,
  error_severity text,
  sql_state_code text,
  message text,
  detail text,
  hint text,
  internal_query text,
  internal_query_pos integer,
  context text,
  query text,
  query_pos integer,
  location text,
  application_name text,
  PRIMARY KEY (session_id, session_line_num)
);

Aufbau

Logging

Umsetzung

Das csvlog kann als Grundlage für das effiziente Befüllen eines zentralen Loggingsystems dienen. Um hier die weitere Verarbeitung möglichst einfach zu gestalten und um sich auf kein Loggingsystem festlegen zu müssen, übersetzen wir das Log von CSV nach Json. Im Anschluss kann es dann beliebig eingespeist werden. Im folgenden Beispiel wird TCP verwendet.

Um das Logformat zu ändern müssen in PostgreSQL® folgende Optionen angepasst werden:

#------------------------------------------------------------------------------
# ERROR REPORTING AND LOGGING
#------------------------------------------------------------------------------
 
# - Where to Log -
 
log_destination = 'csvlog'              # Valid values are combinations of
                                        # stderr, csvlog, syslog, and eventlog,
                                        # depending on platform.  csvlog
                                        # requires logging_collector to be on.
 
# This is used when logging to stderr:
logging_collector = on                  # Enable capturing of stderr and csvlog
                                        # into log files. Required to be on for
                                        # csvlogs.
                                        # (change requires restart)
                                        # These are only used if logging_collector is on:
log_directory = '/var/log/postgresql'   # directory where log files are written,
                                        # can be absolute or relative to PGDATA

Zum Parsen und Übersetzen in Json sowie zum Einliefern ins Loggingsystem verwenden wir logstash® mit folgender Konfiguration als Jinja2-Template:

input {
        file {
                "path" => "/var/log/postgresql/*.csv"
                "sincedb_path" => "/tmp/sincedb_pgsql"
                # fix up multiple lines in log output into one entry
                codec => multiline {
                   pattern => "^%{TIMESTAMP_ISO8601}.*"
                   what => previous
                   negate => true
           }
        }
}
 
# Filter is testet for PostgreSQL® 9.5
filter {
        csv {
 columns => [  "pg_log_time", "pg_user_name", "pg_database_name",
               "pg_process_id", "pg_connection_from", "pg_session_id",
               "pg_session_line_num", "pg_command_tag",
               "pg_session_start_time", "pg_virtual_transaction_id",
               "pg_transaction_id", "pg_error_severity", "pg_sql_state_code",
               "pg_sql_message", "pg_detail", "pg_hint", "pg_internal_query",
               "pg_internal_query_pos", "pg_context", "pg_query",
               "pg_query_pos", "pg_location", "pg_application_name"  ]
        }
 
  date {
        #2014-05-22 17:02:35.069 CDT
        match => ["log_time", "YYYY-MM-dd HH:mm:ss.SSS z"]
        }
 
  mutate {
    add_field => {
      "application_name" => "postgres"
    }
  }
 
}
 
output {
        tcp {
                host => "{{ log_server }}"
                port => {{ log_port }}
                codec => "json_lines"
        }
}

Wichtig ist hier, dass der Filter zum Übersetzen der CSV-Felder an die verwendete PostgreSQL®-Hauptversion angepasst wird. Die Felder können sich von Version zu Version unterscheiden. In den meisten Fällen werden neue Felder hinzugefügt.

Auch zu beachten ist, dass logstash® Probleme hat den Timestamp eigenständig zu erkennen. Hier sollte das konkrete Format vorgegeben werden (Zeitzone).

Folgenden Variablen müssen gesetzt werden:

{{ log_server }}Logserver, in unserem Fall ein graylog®
{{ log_port }}Port auf dem Logserver

So konfiguriert, können die Logfiles effizient klassifiziert und durchsucht werden. Auch die Berechtigungen gestalten sich einfacher.

  • Berechtigung auf Datenbankebene => pg_database_name
  • Severity => pg_error_severity
  • Berechtigung für Loggs durch bestimmte Hosts => pg_connection_from
  • Berechtigung für Loggs durch bestimmte Anwendungen => pg_application_name

Wichtig: Das normale stderr-Log sollte in jedem Fall noch mit ins zentrale Logging aufgenommen werden. Hier landen zwar nach dem Start keine normalen Betriebsmeldungen von PostgreSQL® mehr, jedoch Fehlerausgaben von beteiligten Prozessen. Hier kann z.B. die stderr-Ausgabe eines fehlgeschlagenen Archivecommands gefunden werden. Dieses Informationen sind für die Administration essentiell.

Wir unterstützen bereits zahlreiche Kunden dabei das beschriebene Verfahren in Produktion zu betreiben. Falls Sie Fragen zu diesem Thema haben oder Unterstützung benötigen, dann können Sie sich selbstverständlich gern an unser PostgreSQL® Competence Center wenden.

Dieser Artikel wurde ursprünglich von Alexander Sosna verfasst.

Das Repository für Debian- und Ubuntu-Pakete für PostgreSQL® auf apt.postgresql.org wurde um eine weitere Prozessor-Architektur erweitert. Ab sofort stehen auch fertige Binär-Pakete für ppc64el, die little endian-Version der IBM POWER-Architektur, zur Verfügung. Neben amd64 (64-bit x86 Intel) und i386 (32-bit x86 Intel) ist dies die nun dritte unterstützte Variante.

Das heutige Release der neuen PostgreSQL®-Version 9.6 ist bereits im Repository enthalten.

Genau wie auf den bisherigen Architekturen werden alle Pakete für alle PostgreSQL®-Versionen unterstützt, momentan sind dies alle Versionen von 9.1 bis 9.6. Mit nur wenigen Ausnahmen sind alle bisher enthaltenen Pakete nun auch für ppc64el kompiliert worden. [1]

Unterstützt werden die Debian-Versionen 8 (jessie) und unstable (sid), und die Ubuntu-Versionen 14.04 (trusty) und 16.04 (xenial).

Die Arbeiten an diesem Projekt wurden von credativ gemeinsam mit 2ndQuadrant und IBM Italien durchgeführt. Der ppc64el-Buildhost wird vom IBM Power Systems Linux Center in Montpellier bereit gestellt.

Für unsere Support-Kunden unterstützt die credativ natürlich auch den PostgreSQL®-Betrieb auf POWER. Bei Fragen stehen wir gerne zur Verfügung, sprechen Sie uns an!

[1] plv8 ist nicht verfügbar; pg-partman ist noch nicht für 9.6 verfügbar; psqlodbc und libpqtypes sind auf trusty nicht verfügbar.

Mit PostgreSQL® 9.6 wird der bekannte View pg_stat_activity um zwei Spalten erweitert: wait_event und wait_event_type. Die alte Spalte waiting fällt dafür weg.

Hintergrund

PostgreSQL® unterscheidet intern zwischen zwei Lock-Typen: Heavyweight-Locks und Lightweight-Locks (LWLocks). Je nach zu erwartender Dauer des Locks kommt entweder die eine oder die andere Variante zum Einsatz.

Zu Heavyweight-Locks zählen Locks, die sich auf Datenbankobjekte beziehen. Sie werden verwendet, um auf SQL-Ebene gleichzeitige, konfligierende Aktionen gegeneinander abzusichern. So darf beispielsweise eine Tabelle erst gelöscht werden, sobald es keine Transaktionen mehr gibt, die diese verwenden, oder zwei Transaktionen, die ein UPDATE der gleichen Zeile versuchen, müssen auf einander warten. Diese Locks können im View pg_locks eingesehen werden. In Verbindung mit dem View pg_stat_activity kann so herausgefunden werden, wer auf wen wartet. Eine Beispielquery befindet sich im PostgreSQL®-Wiki.

Lightweight-Locks hingegen werden für kurze Locking-Operationen verwendet. Dies beinhaltet zum Beispiel das Füllen der WAL-Buffer (WALBufMappingLock) oder auch das Warten auf das Herausschreiben selbiger (WALWriteLock). Ein weiteres Beispiel ist der Zugriff auf Pages innerhalb des Shared Memory Segments (buffer_content), wie er beim Lesen oder Schreiben von Daten auftritt. Problematisch ist nun, dass Lightweight-Locks, im Gegensatz zu Heavyweight-Locks, nicht in pg_locks oder einem anderen System-View erfasst sind. Um bei Performanceanalysen zu erkennen, auf welchen LWLock gerade gewartet wurde, musste bis dato zu externen Tools Tools wie perf gegriffen werden.

Funktion

Zusätzlich zu den bereits bekannten Statusinformationen wie pid, query_start oder auch query, halten mit PostgreSQL® 9.6 zwei neue Spalten Einzug in pg_stat_activity. Die Spalten wait_event und wait_event_type enthalten detaillierte Locking Informationen. Sie ersetzt zeitgleich die Spalte waiting, die früher je nach Status lediglich TRUE oder FALSE beinhaltete und damit signalisierte, dass auf einen Heavyweight-Lock gewartet wurde.

Die neue Spalte gibt wait_event nun auch Aufschluss darüber ob und auf welche Art von LWLocks gewartet wird. Muss ein Backend auf einen Lock warten, enthält die Spalte wait_event den Namen des Events, andernfalls NULL.

Beispiel

Zur Veranschaulichung des neuen Features bemühen wir das PostgreSQL®-eigene Benchmark-Tool pgbench.

Zunächst erstellen wir uns eine neue Testdatenbank und befüllen diese mit Testdaten.

$ createdb pgbench
$ pgbench -i -s 50 pgbench

Nachdem unsere Datenbank erstellt und gefüllt ist, starten wir pgbench mit 20 gleichzeitigen Verbindungen in 2 Threads:

$ pgbench -c 20 -j 2 -T 300 pgbench 

Schauen wir uns zeitgleich den View pg_stat_activity an, so stellen wir fest, dass viele der Backends auf Locks vom Typ LWLockNamed warten, einen WALWriteLock. Sie warten also darauf, dass die geschriebenen WAL-Records auf die Festplatte geschrieben werden:

psql=# select pid, wait_event, wait_event_type, state, query from pg_stat_activity WHERE wait_event is not NULL;
  pid  |  wait_event   | wait_event_type | state  |                                 query                                  
-------+---------------+-----------------+--------+------------------------------------------------------------------------
 25632 | transactionid | Lock            | active | UPDATE pgbench_branches SET bbalance = bbalance + -3359 WHERE bid = 4;
 25633 | WALWriteLock  | LWLockNamed     | active | END;
 25635 | WALWriteLock  | LWLockNamed     | active | END;
 25636 | transactionid | Lock            | active | UPDATE pgbench_branches SET bbalance = bbalance + 1807 WHERE bid = 1;
 25638 | transactionid | Lock            | active | UPDATE pgbench_branches SET bbalance = bbalance + -603 WHERE bid = 12;
 25639 | transactionid | Lock            | active | UPDATE pgbench_tellers SET tbalance = tbalance + 2794 WHERE tid = 169;
 25640 | WALWriteLock  | LWLockNamed     | active | END;
 25642 | WALWriteLock  | LWLockNamed     | active | END;
 25643 | transactionid | Lock            | active | UPDATE pgbench_branches SET bbalance = bbalance + -4985 WHERE bid = 5;
 25644 | WALWriteLock  | LWLockNamed     | active | END;
 25645 | WALWriteLock  | LWLockNamed     | active | END;
 25646 | WALWriteLock  | LWLockNamed     | active | END;
 25648 | transactionid | Lock            | active | UPDATE pgbench_branches SET bbalance = bbalance + 2700 WHERE bid = 1;
 25649 | transactionid | Lock            | active | UPDATE pgbench_branches SET bbalance = bbalance + -456 WHERE bid = 5;
 25650 | transactionid | Lock            | active | UPDATE pgbench_branches SET bbalance = bbalance + -617 WHERE bid = 17;
 25651 | WALWriteLock  | LWLockNamed     | active | END;
(16 rows)

Ändern wir nun beispielsweise die Einstellung synchronous_commit auf off, so stellen wir fest, dass genau diese WALWriteLocks nicht mehr Auftreten. Die Backends warten nicht mehr darauf, dass ihre Daten auf die Festplatte geschrieben werden:

psql=# SELECT pid, wait_event, wait_event_type, state, query from pg_stat_activity WHERE wait_event is not NULL;
  pid  |  wait_event   | wait_event_type | state  |                                  query                                  
-------+---------------+-----------------+--------+-------------------------------------------------------------------------
 26201 | transactionid | Lock            | active | UPDATE pgbench_branches SET bbalance = bbalance + -1065 WHERE bid = 7;
 26203 | transactionid | Lock            | active | UPDATE pgbench_tellers SET tbalance = tbalance + -3052 WHERE tid = 173;
 26204 | transactionid | Lock            | active | UPDATE pgbench_branches SET bbalance = bbalance + -2375 WHERE bid = 5;
(3 rows)

Fazit

Das oben gezeigte Beispiel veranschaulicht, wie detailliert nun Einsicht in das Locking der Datenbank genommen werden kann. Besonders für Analysen der Datenbankperformance bietet dies entscheidende Vorteile gegenüber den bisherigen Möglichkeiten.

Details

Detailliertere Informationen zu den verwendeten Lock-Typen, deren Bedeutung und Verwendung hat die PostgreSQL®-Dokumentation. Wem dies nicht ausreicht, dem bietet die Datei src/backend/storage/lmgr/README im Sourcecode weitere Informationen über Locking in PostgreSQL®.

Bei Fragen steht Ihnen außerdem unser PostgreSQL® Competence Center zu Verfügung.

PostgreSQL® 9.6 befindet sich aktuell in der Beta Phase. Ein Release- Datum steht aktuell noch nicht fest. Wer die neue Version bereits im Vorfeld testen möchte, findet den aktuellen Tarball unter www.postgresql.org. Für Debian und Ubuntu stehen auf apt.postgresql.org bereits vorgefertigte Pakete bereit.