pgio - I/O Workload Generator

Database

pgio ist ein von Kevin Closson, Autor von SLOB für Oracle Datenbanken, implementiertes und unter der Apache 2.0 Lizenz auf Github veröffentlichtes Tool zum Testen der I/O Performance einer Plattform mit installiertem PostgreSQL.

Als Demo-Umgebung steht eine per Vagrant angelegte CentOS 7(.4) VM mit installiertem EnterpriseDB Advanced Server 10 zur Verfügung. In der postgresql.conf ist der Parameter shared_buffers = 512MB angepasst. Ansonsten ist die Konfiguration nach Installation nicht verändert worden.

Zusätzlich wurde noch das sysstat Paket installiert. 

 

​sudo yum install -y sysstat

Installation

Die Installation und die nachfolgende Demo wird als User enterprisedb ausgeführt.

 

sudo su - enterprisedb

 

Nun geht die Installation von pgio schnell, da das Release 1.0 nur von Github heruntergeladen und extrahiert werden muss.

 

wget github.com/therealkevinc/pgio/archive/1.0.tar.gz

tar -xvzf 1.0.tar.gz
pgio-1.0/
pgio-1.0/LICENSE
pgio-1.0/NOTICE
pgio-1.0/README
pgio-1.0/RELEASE
pgio-1.0/pgio-2019.09.21-v_1.0.tar.gz
pgio-1.0/pgio.conf
pgio-1.0/pgio.sql
pgio-1.0/pgio_audit_table.sql
pgio-1.0/pgio_get_rand.sql
pgio-1.0/pgio_reduce_free_memory.sh
pgio-1.0/pgio_table_sizes.sql
pgio-1.0/runit.sh
pgio-1.0/setup.sh

tar -xvzf pgio-2019.09.21-v_1.0.tar.gz

cd pgio

 

Die Shellskripte im pgio Verzeichnis werden ausführbar gemacht.

 

chmod +x *.sh

Konfiguration

Die Konfiguration von pgio erfolgt über die Konfigurationsdatei pgio.conf. In dieser Datei sind die folgenden Parameter enthalten, die das Anpassen des Workloads an die Postgres Instanz und Plattform ermöglichen.

 

UPDATE_PCT=0
RUN_TIME=120
NUM_SCHEMAS=4
NUM_THREADS=2
WORK_UNIT=255
UPDATE_WORK_UNIT=8
SCALE=1G

DBNAME=pg10
CONNECT_STRING="pg10"

CREATE_BASE_TABLE=TRUE

PARAMETER

BEDEUTUNG

UPDATE_PCT

Anteil an SQL Update Statements

RUN_TIME

Ausführungsdauer des runit.sh Skripts in Sekunden

NUM_SCHEMAS

Alle durch das setup.sh Skript generierten Daten liegen entweder in einem einzigen Schema oder aber werden mit diesem Parameter in n Schemas angelegt; VORSICHT: Mit Schema wird in der Dokumentation Tabelle gemeint!

| NUM_THREADS |

setup.sh nutzt n parallele Ladeprozesse

runit.sh nutzt n parallele Sessions pro Schema während der Workload Generation

| WORK_UNIT | Setzt das Limit des BETWEEN im Select Statement, so dass n zufällig gewählte Blöcke ausgewählt werden; bei einem kleineren Wert als 255 sind mehr Select Statements notwendig, um den gleichen IOPS zu erreichen | | UPDATE_WORK_UNIT | Definiert die logische Abfolge des Workloads der Select/Update Statements, wobei die Select Statements mehr Blöcke als die Updates nutzen | | SCALE | Menge an initial generierten Daten pro Schema durch setup.sh entweder als

n multipliziert mit 8 Kilobyte

nM für Größe in Megabyte

nG für Größe in Gigabyte

| | DBNAME | Datenbank in der alle Objekte für den Test erzeugt werden | | CONNECT_STRING | Parameter zur Übergabe an psql, wobei Umgebungsvariablen, .pgpass Datei und die Authentifikation bereits konfiguriert sind | | CREATE_BASE_TABLE | setup.sh erzeugt beim ersten Start eine Quelltabelle um alle weiteren Tabellen zu beladen; bei dem Wert true wird diese Quelltabelle bei erneuten Ausführungen nicht erneut erzeugt |

Demo

Für die Demo wird die pgio.conf angepasst:

 

UPDATE_PCT=15
RUN_TIME=120
NUM_SCHEMAS=4
NUM_THREADS=2
WORK_UNIT=255
UPDATE_WORK_UNIT=8
SCALE=1G

DBNAME=pgiotest
CONNECT_STRING="pgiotest"

CREATE_BASE_TABLE=TRUE

 

Es wird für 2 Minuten mit einem 15%igen Update-Anteil, verteilt über 4 Tabellen, mit jeweils 2 Sessions (insgesamt also 8) gearbeitet. Die Skalierung auf 1 GB erwirkt dabei, dass Postgres nicht nur die Pages in den Shared Buffers nutzt, sondern auch Pages aus dem Filesystem nachgeladen werden.

Bevor jedoch das setup.sh Skript gestartet werden kann, wird die die Datenbank für den Test angelegt.

 

psql -c "CREATE DATABASE pgiotest;"
CREATE DATABASE

 

Nun erzeugt das setup.sh Skript die Tabellen und Daten.

 

./setup.sh

Job info:      Loading 1G scale into 4 schemas as per pgio.conf->NUM_SCHEMAS.
Batching info: Loading 2 schemas per batch as per pgio.conf->NUM_THREADS.
Base table loading time: 1 seconds.
Waiting for batch. Global schema count: 2. Elapsed: 0 seconds.
Waiting for batch. Global schema count: 3. Elapsed: 6 seconds.
Waiting for batch. Global schema count: 4. Elapsed: 10 seconds.
Waiting for batch. Global schema count: 4. Elapsed: 14 seconds.

Group data loading phase complete.         Elapsed: 14 seconds.

 

Die Quelltabelle und die 4 konfigurierten Tabellen sind jetzt im Schema public zu sehen.

 

psql -c "\d+" pgiotest

 

Nun kann das runit.sh Skript ausgeführt werden und ein erstes Ergebnis liefern.

 

/runit.sh
Date: Thu Jul  2 15:11:05 UTC 2020
Database connect string: "pgiotest".
Shared buffers: 512MB.
Testing 4 schemas with 2 thread(s) accessing 1G (131072 blocks) of each schema.
Running iostat, vmstat and mpstat on current host--in background.
Launching sessions. 4 schema(s) will be accessed by 2 thread(s) each.
pg_stat_database stats:
          datname| blks_hit| blks_read|tup_returned|tup_fetched|tup_updated
BEFORE:  pgiotest | 16676782 |  38983698 |     50520035 |    48666552 |      300444
AFTER:   pgiotest | 25059243 |  48270369 |     67758497 |    65899715 |      407222
DBNAME:  pgiotest. 4 schemas, 2 threads(each). Run time: 120 seconds. RIOPS >77388< CACHE_HITS/s >69853<

 

Interessant bei dem Ergebnis sind die Spalten tup_fetched und tup_updated, da sie die geladenen und aktualisierten Zeilen während dem Test darstellen. Je höher die Werte sind, desto besser. Mit dem in der letzten Zeile dargestellten Wert für Read IOPS (RIOPS) kann geprüft werden, ob die Plattform den “versprochenen” IOPS Wert liefert.

Buffered I/O vs. Direct I/O

Es ist wichtig zu verstehen, dass pgio RIOPS und nicht Read Physical IOPS (RPIOPS) anzeigt. Das kommt daher, dass Postgres Dateien nicht mit dem O_Direct Flag öffnet, was bedeutet, dass es “buffered” I/O ist. Das “buffering” wird über physikalischen Hauptspeicher des Linux Page Caches abgewickelt. Dies fällt beim Vergleich der I/O Werte mit iostat auf und wurde in einem Beitrag von Kevin Closson inklusive der Möglichkeit dies zu umgehen beschrieben. Dies ist auch einer der Gründe, warum das runit.sh Skript iostat während dem Test mitlaufen lässt.

pgio bietet mit dem Shellskript pgio_reduce_free_memory.sh die Möglichkeit, den freien Hauptspeicher zu beschränken und das Page Caching zu auszuschalten. Dabei übergibt man dem Shellskript den frei zu bleibenden Wert in Gigabyte. In diesem Beispiel wird der freie Hauptspeicher auf 1 GB beschränkt. Das Skript muss als User root ausgeführt werden.

 

./pgio_reduce_free_memory.sh 1

Enter "YES" to consume free memory leaving only 1GB free (27.0 % of all RAM) : YES
Taking action to reduce free memory down to 1GB available.
              total        used        free      shared  buff/cache   available
Mem:        3880616      223872     3000852      564988      655892     2915544
Swap:       2097148           0     2097148

Attempting to allocate 954 huge pages
MemAvailable:     965872 kB
HugePages_Total:     954

 

Ein Blick mit free zeigt, dass nur noch 1 GB freier Hauptspeicher vorhanden ist.

 

free -h

              total        used        free      shared  buff/cache   available
Mem:           3.7G        2.1G        1.0G        551M        641M        941M
Swap:          2.0G          0B        2.0G

 

Jetzt wird pgio als User enterprisedb erneut mit runit.sh ausgeführt.

 

/runit.sh
Date: Mon Jul  6 11:33:05 UTC 2020
Database connect string: "pgiotest".
Shared buffers: 512MB.
Testing 4 schemas with 2 thread(s) accessing 1G (131072 blocks) of each schema.
Running iostat, vmstat and mpstat on current host--in background.
Launching sessions. 4 schema(s) will be accessed by 2 thread(s) each.
pg_stat_database stats:
          datname| blks_hit| blks_read|tup_returned|tup_fetched|tup_updated
BEFORE:  pgiotest | 25935119 |  49904563 |     71082946 |    67417878 |      417047
AFTER:   pgiotest | 26049609 |  50508466 |     71779636 |    68110975 |      421718
DBNAME:  pgiotest. 4 schemas, 2 threads(each). Run time: 120 seconds. RIOPS >5032< CACHE_HITS/s >954<

 

Der nun erreichte RIOPS Wert von 5032 wird jetzt mit den Disk-Statistiken verglichen. Es ist ersichtlich, dass die Werte sich nun annähern.

Das wird zusätzlich durch einen Vergleich des RIOP-Wertes mit den iostat-Daten bestätigt.

 

grep sda1 iostat.out | sed 1d | awk '{ x=x+$4 } END { print x / NR }'

5131.47

Aufräumen

Im Hintergrund hat pgio beim Ausführen von runit.sh iostat, vmstat und mpstat mitlaufen lassen. Dabei wird pro Befehl eine Ausgabedatei erzeugt.

  • iostat.out
  • vmstat.out
  • mpstat.out
  • pgio_diskstats.out
  • pgio_objects_creation.out
  • pgio_session_detail.out 

Werden die Daten nicht weiter benötigt, können sie wieder gelöscht werden, da sie je nach Testlänge recht beachtliche Größen erreichen können.

 

rm ./*.out

Fazit

pgio bietet die komfortable Möglichkeit mit PostgreSQL die I/O Performance der darunter liegenden Plattform zu testen. Dabei ist die Installation und Konfiguration leicht und verständlich durchzuführen. Das Nutzen von pgio ist einerseits besonders zu empfehlen, wenn (Cloud) Service Provider auf die zugesicherten Rahmenbedinungen hin gestest werden sollen. Andererseits lässt sich vor Inbetriebnahme einer Datenbank testen, welches Filesystem (z.B. xfs oder ext4) mit welchen Mount Optionen (z.B. sync) Sinn macht.

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