Huge Pages und ihr Nutzen für PostgreSQL

DevOps

Die Standard Page Größe ist 4 K bei Linux. Der Einsatz von Huge Pages, also Pages mit z.B. einer Größe von 2 MB, reduziert die CPU Kosten beim Laden von großen zusammenhängenden Bereichen in den Hauptspeicher (Memory Management). PostgreSQL ist hier ein schönes Beispiel, wenn Shared Buffers in Gigabyte Größe verwendet werden.

Wie können aber nun Huge Pages für PostgreSQL genutzt werden? - In der PostgreSQL Konfiguration ist das mit dem Einstellen des postgresql.conf Parameters huge_pages möglich. Er kann folgende Ausprägungen haben:

  • try - der Standardwert, bei dem PostgreSQL versucht, vorhandene Huge Pages zu nutzen, ansonsten aber ohne arbeitet
  • on - PostgreSQL startet ausschließlich, wenn genügend Huge Pages verfügbar sind
  • off - es werden keine Huge Pages genutzt

Die aktuelle Einstellung ist schnell ermittelt.

 

psql -U postgres -c "SHOW huge_pages;"
 huge_pages
------------
 try

 

Geändert werden kann sie bequem per ALTER SYSTEM, benötigt danach aber einen Neustart.

 

psql -U postgres -c "ALTER SYSTEM SET huge_pages = 'on';"

 

Zuerst ist aber zu prüfen, ob der Kernel überhaupt für Huge Pages konfiguriert wurde. In vielen Distributionen ist das der Fall. Dies kann unter CentOS/7 so geprüft werden.

 

grep HUGETLB /boot/config-$(uname -r)
...
CONFIG_HUGETLBFS=y
CONFIG_HUGETLB_PAGE=y

 

Die Größe einer Huge Page ist 2 MB, es geht aber bei Bedarf auch größer. Der Wert ist in den Hauptspeicher Informationen ersichtlich.

 

grep ^Hugepagesize /proc/meminfo
Hugepagesize:       2048 kB

 

Als Nächstes lässt sich die minimal notwendige Anzahl an Huge Pages für PostgreSQL berechnen. Dazu wird mit der PID des PostgreSQL postmaster Prozesses der Prozessspeicherwert mit pmap ermittelt.

 

head -1 $PGDATA/postmaster.pid
1210

pmap 1210 | awk '/rw-s/ && /zero/ {print $2}'
145608K

 

Die 145608 K werden durch die Huge Page Size Größe dividiert und das Ergebnis wird auf eine ganze Zahl aufgerundet.

 

echo "145608/2048" | bc
71

 

Es werden also in diesem Fall mindestens 71 Huge Pages für den Betrieb von PostgreSQL mit der aktuellen Shared Buffers Größe benötigt.

Den Wert können wir jetzt per sysctl oder aber, und das ist besser, per eigenem tuned-adm Profil dauerhaft setzen. Die minimale tuned.conf beinhaltet nur das Performance Profil, das Deaktivieren der Transparent Huge Pages (THP) und der Anzahl der Huge Pages. THP zu deaktivieren ist sinnvoll, da diese zu einem Performance-Verlust führen können.

 

mkdir /etc/tuned/proventa-postgres

echo "[main]
include=throughput-performance

[vm]
transparent_hugepages=never
vm.nr_hugepages=71" >> /etc/tuned/proventa-postgres/tuned.conf

chmod +x /etc/tuned/proventa-postgres/tuned.conf

 

Das Tuning Profil wird per tuned-adm aktiviert und ist dann auch für einen Reboot persistiert.

 

tuned-adm profile proventa-postgres

tuned-adm active
Current active profile: proventa-postgres
Zuletzt ist zu prüfen, ob die Parameter den gewünschten Effekt haben.
cat /sys/kernel/mm/transparent_hugepage/enabled
always madvise [never]

cat /proc/meminfo | grep -i huge
AnonHugePages:      8192 kB
HugePages_Total:       71
HugePages_Free:        71
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:       2048 kB

 

Ein kleiner Test mit pgBench auf einer PostgreSQL 12 Standardkonfiguration, aber huge_pages = on, zeigt ebenfalls, dass die TPS durch das Aktivieren der Huge Pages steigen. Gängige Zugewinne liegen zwischen 5 - 25 %, wobei der zu erwartende Wert je nach bereits erfolgtem Tuning geringer ausfallen wird.

Ohne Huge Pages:

 

pgbench -U postgres -c 10 -j 2 -t 10000 pgbench
starting vacuum...end.
transaction type: <builtin: TPC-B (sort of)>
scaling factor: 300
query mode: simple
number of clients: 10
number of threads: 2
number of transactions per client: 10000
number of transactions actually processed: 100000/100000
latency average = 11.348 ms
tps = 881.191874 (including connections establishing)
tps = 881.245757 (excluding connections establishing)

 

Mit Huge Pages:

 

pgbench -U postgres -c 10 -j 2 -t 10000 pgbench
starting vacuum...end.
transaction type: <builtin: TPC-B (sort of)>
scaling factor: 300
query mode: simple
number of clients: 10
number of threads: 2
number of transactions per client: 10000
number of transactions actually processed: 100000/100000
latency average = 8.642 ms
tps = 1157.174142 (including connections establishing)
tps = 1157.269086 (excluding connections establishing)

 

Zum Schluss ist zu erwähnen, dass per tuned-adm noch mehr Parameter auf Betriebssystemebene angepasst werden können, damit PostgreSQL mehr Leistung erbringt.

Wer sich über Postgresql- und Datenbankthemen austauschen oder beraten möchte, kann gerne direkt Kontakt mit mir aufnehmen. >>Zum Kontaktformular

Dirk Aumueller Autor

Dirk Aumueller arbeitet als Associate Partner für die Proventa AG. Sein technologischer Schwerpunkt liegt bei Datenbankarchitekturen mit PostgreSQL sowie Data Management Lösungen mit Pentaho. Zusätzlich zu seinen Datenbanktransformations-Projekteinsätzen ist er regelmäßig als PostgreSQL Trainer unterwegs und betreut Studenten bei ihren Abschlussarbeiten. Seine fachlichen Erfahrungen erstrecken sich über die Branchen Telco und Financial Services.

Tags