Benchmarking Postgres on Hetzner servers with pgbench

For an upcoming project, I conducted a comprehensive benchmark of Postgres on both Hetzner VMs and dedicated servers. I won’t go into a detailed analysis of the results (as I am also not a Postgres expert), but I thought sharing them here might be valuable for some of you.

Link to this section  pgbench setup

# AlmaLinux 9
dnf -y module enable postgresql:16
dnf install -y postgresql-server postgresql-contrib postgresql-devel
postgresql-setup --initdb
systemctl start postgresql
sudo -u postgres createdb pgbench_test
sudo -u postgres pgbench -i -s 10 pgbench_test
sudo -u postgres pgbench -c 30 -j 4 -T 120 pgbench_test # write
sudo -u postgres pgbench -S -c 30 -j 4 -T 120 pgbench_test # read

which results in a load of 30 parallel client connections with 4 threads for a duration of 120 seconds.

The test setup has to be kept in mind as it will have different implications on the tested servers: for the small ones, it will require all server resources and actually overload them. For the medium sized servers, it can be considered a “good challenge”. And the large instances will not be pushed to the edge with this setup. However, using different setups across all instance types will make the benchmark meaningless. Hence, there is no other way of choosing a setup which will not cause the small ones to crash while still allowing for “some” load on the large instances.

Personally, I was interested in how much better the bare-metal server and their respective NVMEs perform against the shared cloud VMs. And if there is a significant performance drop for the small cloud servers with the small disks.

According to Hetzner support, all cloud VMs have the same NVMEs and the performance shouldn’t vary between them. The bare-metal root servers have better performing disks in general.

Because I had access to one, I also added an Azure “B1s” managed Postgres flexible server (with max. cons = 400) into the mix, to check how their disks perform against the Hetzner ones.

Some simple general take aways are:

  • multicore performance of the CPU matters (see CAX vs CPX; CAX has better single core but worse multicore vs CPX)
  • PG “transaction” mode improves read-requests substantially
  • pgbouncer + load balancers reduce benchmark scores and increase latency, especially for write-requests, but help a lot in daily practice

Link to this section  Results

Environment W TPS W Latency (ms) R TPS R Latency (ms) Notes Costs / month
CAX11 (2 C;4 GB;40 GB d) 750 40.00 6084 4.93 Single Primary, PGBouncer + HAProxy LB,
pgbouncer “session” mode
$4.6
CAX11 (2 C;4 GB;40 GB d) 797 37.62 7395 4.05 Single Primary, PGBouncer + HAProxy LB,
pgbouncer “transaction” mode
$4.6
CAX21 (4 C;8 GB;40 GB d) 1258 40.00 6084 4.93 Single Primary, PGBouncer + HAProxy LB,
pgbouncer “session” mode
$6.5
CAX11 (2 C;4 GB;2 repl.) 13057 2.30 Two Replicas, PGBouncer + HAProxy LB,
pgbouncer “session” mode
$9.2
CAX11 (2 C;4 GB;40 GB d) 2242 13.38 18555 1.62 Bare Host install, Shared $4.6
CPX11 (2 C;2 GB;40 GB d) 3050 9.8 31341 0.96 Bare Host install, Shared $5
CPX21 (3 C;4 GB;80 GB d) 4475 6.7 49391 0.60 Bare Host install, Shared $8.6
CCX13 (2 C;8 GB;80 GB d) 4351 6.8 33292 0.90 Bare Host install, Dedicated $14
CAX21 (4 C;8 GB;80 GB d) 2683 11.18 30701 0.98 Bare Host install, Shared $6.5
CPX31 (4 C;8 GB;160 GB d) 5375 5.5 58768 0.51 Bare Host install, Shared $15.6
CCX13 (4 C;16 GB;160 GB d) 7369 4.07 69115 0.43 Bare Host install, Dedicated $27
CAX31 (8 C;16 GB;160 GB d) 4404 6.81 46935 0.64 Bare Host install, Shared $12.5
CPX41 (8 C;16 GB;240 GB d) 8490 3.5 107975 0.27 Bare Host install, Shared $28.09
CAX41 (16 C;32 GB;320 GB d) 8836 3.40 128879 0.23 Bare Host install, Shared $27.5
CPX51 (16 C;32 GB;360 GB d) 9877 3.0 136883 0.21 Bare Host install, Shared $61
Azure B1s (2 C;4 GB) 1703 17.61 15442 1.94 $75
AX42 (16 C;64 GB;512 d) 1550 1 19.35 348376 0.09 Bare Host install $54

  1. Something must have gone wrong here as the AX42 should usually come in in the range of the CPX51 for the write benchmark. ↩︎