PostgreSQL TDE is an Open Source version of PostgreSQL which encrypts data before storing it safely on disk. It’s therefore a more secure and thus a more enterprise-ready variation of the database. That’s why CYBERTEC PostgreSQL Enterprise Edition (PGEE) also relies heavily on encryption.

PostgreSQL performance analysis

People often ask about the performance differences between encrypted and unencrypted PostgreSQL. To answer this question, we have conducted a comprehensive performance analysis to shed some light on this important topic, and to give users a way to compare various PostgreSQL settings and their performance. Our performance tests have been conducted using the following hardware and software components:

Hardware setup

CPU: AMD Ryzen 5950X — 16 cores / 32 thread, 72MB cache, support for AES-NI

MEMORY: 64GB RAM — DDR4 2666 ECC dual channel

STORAGE: SSD Samsung 980 PRO — nvme, PCIe v4 ×4

simple lvm volume, XFS filesystem, exclusive use

Software in use

OS: Linux Centos 7.9.2009, kernel 5.10.11-1.el7.elrepo.x86_64

PostgreSQL: postgresql13-13.1-3PGDG.rhel7.x86_64 from PGDG repo

PostgreSQL 13.1 TDE: built locally with the standard compile options used for PGDG packages using base GCC 4.8.5 20150623 (Red Hat 4.8.5-44)

PostgreSQL 13.1 TDE: built locally with the standard compile options used for PGDG packages using software collection devtoolset-9 GCC 9.3.1 20200408 (Red Hat 9.3.1-2) and -march=znver2

We have used a few scripts to run these benchmarks in an automated way. You can download the tools for free from our Github page.

Side notes

Since results were performed on a solid-state drive without proper TRIM management, the second version of all these analysis is being prepared, with proper TRIM (-o discard mount option) and scales adjusted to better emphasize the impact of a data set on available memory:

  • small (order of magnitude smaller than shared buffers) – scale 12
  • just below shared buffers limit (90% of shared buffers) – scale 900
  • larger than shared buffers but still fits in RAM (120% of shared buffers) – scale 1600
  • larger than RAM (120% of RAM) – scale 5000

Other params and tooling will be the same.

Benchmarking methodology for PostgreSQL

All tests were performed locally using a freshly initialized, empty cluster (fresh initdb). Therefore caching effects on the PostgreSQL-side are not relevant.

The following configurations were tested:

  1. stock — standard PostgreSQL installation using binaries from PGDG packages.
  2. TDE-4 — PostgreSQL TDE installation with encryption disabled, using binaries compiled with gcc 4.8
  3. TDE-9 — PostgreSQL TDE installation with encryption disabled, using binaries compiled with gcc 9.3 and optimized for znver2
  4. TDE-4-e — PostgreSQL TDE installation with encryption enabled, using binaries compiled with gcc 4.8
  5. TDE-9-e — PostgreSQL TDE installation with encryption enabled, using binaries compiled with gcc 9.3 and optimized for znver2

Note that we did not just compare standard PostgreSQL with PostgreSQL TDE, but also tried various compiler versions. You will find out that the compiler does indeed have a major impact, which might come as a surprise to many.

PostgreSQL configuration

The following PostgreSQL configuration has been used (postgresql.conf). These variables have been determined using the CYBERTEC configurator:

max_connections = 100
unix_socket_directories = '/var/run/postgresql'
port = 15432
shared_preload_libraries = 'pg_stat_statements'
shared_buffers = 16GB
work_mem = 64MB
maintenance_work_mem = 620MB
effective_cache_size = 45GB
effective_io_concurrency = 100
huge_pages = try
track_io_timing = on
track_functions = pl
wal_level = logical
max_wal_senders = 10
synchronous_commit = on
checkpoint_timeout  = '15 min'
checkpoint_completion_target = 0.9
max_wal_size = 1GB
min_wal_size = 512MB
wal_compression = on
wal_buffers = -1
wal_writer_delay = 200ms
wal_writer_flush_after = 1MB
bgwriter_delay = 200ms
bgwriter_lru_maxpages = 100
bgwriter_lru_multiplier = 2.0
bgwriter_flush_after = 0
max_worker_processes = 16
max_parallel_workers_per_gather = 8
max_parallel_maintenance_workers = 8
max_parallel_workers = 16
parallel_leader_participation = on
enable_partitionwise_join = on
enable_partitionwise_aggregate = on
jit = on

Database sizes used during the benchmark were as follows:

  • 15: 244–287MB
  • 20: 332–404MB
  • 25: 400–458MB
  • 30: 479–543MB
  • 35: 557–629MB
  • 50: 793–880MB
  • 500: 7849–8028MB
  • 5000: 78409–78756MB (exceeds total available memory)

For each scale factor, the following benchmarks were measured (using default options):

  • standard read-only benchmark (pgbench built-in)
  • standard TPC-like read/write benchmark (pgbench built-in) – before each TPC run, the database was re-indexed to avoid the impact of index usage on results

Concurrency is a major factor if you want to benchmark in a professional environment. The following settings were used:

  • 12
  • 16 — number of physical cores
  • 20
  • 24
  • 28
  • 32 — number of hardware threads
  • 36
  • 40
  • 44
  • 48

PostgreSQL benchmarking results

Read-only benchmarks for PostgreSQL TDE

The following section contains the results of our investigation. Let’s start with a read-only benchmark and a scale factor of 50, which translates to 880 MB of data (small database):

R-O
50
connectionsstockTDE-4TDE-4-eTDE-9TDE-9-e
12598.004,94652.870,65640.867,94651.161,67668.317,19
16717.080,83806.152,21795.300,37794.494,71821.915,21
20735.584,04813.589,44801.139,14807.197,44829.891,65
24757.834,24818.350,37809.893,87817.332,59832.810,15
28865.626,22911.020,73896.977,27909.858,10916.804,18
321.095.158,471.212.918,761.175.538,121.182.331,491.233.930,94
36885.519,57958.732,55931.091,56967.514,37986.631,16
40847.388,93943.701,45915.369,45919.076,23964.899,29
44830.018,15914.696,79901.860,60913.789,27954.813,04
48818.142,23916.199,48894.018,17901.936,11964.656,08

 

Take a look at the first row (12 connections). Standard PostgreSQL will yield 598.000 read-only transactions per second which is a good number. In general, we have found that AMD CPUs are really efficient these days, and greatly outperform IBM POWER9 and many others. What we do notice is that the compiler makes a real difference. 651k TPS vs. 598k TPS is a whopping 9% improvement which basically comes for “free”. gcc 9 is doing really well here.

TDE performance R-O 50

The following image shows the basic architecture of PostgreSQL TDE:

TDE architecture

What is also important to see is that there is basically no difference between encrypted and non-encrypted runs. The reason for that is simple: PostgreSQL encrypts 8k blocks before sending them to disk and decrypts them when a block is fetched from the operating system. Therefore, there is no difference between the encrypted and unencrypted performance. What you see are, basically, fluctuations, which are totally expected.

 

Let’s take a look at the same data. In this case, we are using a scale factor 500 which translates to 8 GB of data

R-O
500
connectionsstockTDE-4TDE-4-eTDE-9TDE-9-e
12583.003,70623,487,99611.303,93615.277,51628.507,18
16723.460,41772.852,04750.083,11761.129,07782.628,12
20750.054,44782.333,97770.649,65778.393,73795.200,14
24755.796,29792.365,30773.744,79787.903,80802.164,80
28842.270,11890.584,06872.163,41886.265,42895.721,71
321.087.753,871.166.292,931.124.810,041.133.026,801.170.395,10
36881.376,33926.521,14901.508,03914.466,29948.293,12
40860.762,15911.308,67875.478,96911.961,05912.369,46
44857.354,28895.126,03863.349,07878.027,97916.855,40
48853.062,65881.192,84858.566,69882.463,09910.616,50

 

The picture is pretty similar to what we observed with the small database. We are still 100% in RAM and therefore there is no real performance difference between PostgreSQL TDE with encryption on or encryption off. What you see are mostly fluctuations:

TDE performance R-O 500

 

The final test was conducted with a scale factor of 5000. The important part is that the database has grown so large that there is no way to keep it in RAM anymore. Thus we can observe a major drop in performance:

R-O
5000
connectionsstockTDE-4TDE-4-eTDE-9TDE-9-e
1278.858,9275.226,3974.968,6580.913,5382.063,75
16104.880,2799.974,7599.921,82106.414,78107.763,35
20126.328,88120.898,40119.139,41124.199,94125.980,44
24143.740,06139.041,17134.917,30136.937,95140.407,50
28156.813,58152.443,32147.754,62148.286,04152.065,41
32170.999,35162.929,84156.527,94157.810,55164.181,20
36180.937,04171.578,25165.513,33167.660,63172.848,70
40189.501,24180.439,46173.084,98174.142,58179.936,11
44196.615,29187.607,67178.765,27179.044,87185.212,72
48201.491,30192.716,50183.124,81183.379,49190.149,00

 

You have to keep in mind that going to disk is many many times more expensive than doing some pointer arithmetic in shared memory. A lot of latency is added to each individual query which leads to low TPS if there are not enough connections. On SSD’s this effect can be reduced a bit by adding a bit more concurrency. However, adding concurrency only works up to a certain point until the capacity of the disk is exceeded.

TDE performance R-O 5000

Read-write benchmarks for PostgreSQL TDE

After this brief introduction to read-only benchmarks, we can focus our attention on read-write workloads. We use the standard mechanisms provided by pgbench here.

The first thing we notice is that performance is a lot lower. There are two reasons for that:

  • A read-write transaction in pgbench has many more commands
  • PostgreSQL has to flush (fsync) changes to disk on commit

Let’s take a look at the data:

TPC
50
connectionsstockTDE-4TDE-4-eTDE-9TDE-9-e
123.580,133.520,692.014,562.014,162.024,19
164.537,574.493,652.548,152.565,762.547,17
205.311,455.374,373.002,805.091,042.995,52
246.192,006.208,623.432,044.998,443.420,59
286.904,776.766,713.784,674.923,473.803,69
327.626,487.473,484.134,594.725,004.139,35
368.040,797.838,614.456,765.474,014.463,35
408.389,518.408,854.697,797.043,244.713,90
448.971,148.853,694.983,574.982,574.965,51
489.246,479.085,385.191,757.751,705.170,42

 

The price of encryption starts to tell. We see that the performance of the encrypted variants can be significantly lower than that of the non-encrypted setup.

TDE performance tpc 50

 

The picture is similar in case the amount of data is increased to a pgbench scale factor of 500:

TPC
500
connectionsstockTDE-4TDE-4-eTDE-9TDE-9-e
124.088,594.098,602.201,373.106,543.080,33
165.417,765.372,612.818,173.400,993.278,76
206.716,896.688,043.437,783.712,333.672,65
247.792,777.903,354.021,374.484,284.576,07
289.061,497.850,114.631,354.926,105.150,77
3210.399,7010.428,755.235,095.515,015.818,24
3611.631,8211.737,265.811,996.056,266.381,50
4012.998,9112.986,146.349,066.911,436.526,33
4414.201,9814.301,646.913,727.360,127.472,31
4814.908,4115.259,677.489,468.097,427.650,18

 

TDE performance TPC 500

 

Now let’s inspect the test using a scale-factor of 5000. What we clearly see is that overall performance dramatically decreases. The reason is of course that a lot of the data has to come from the disk. We therefore see a fair amount of disk wait and latency:

TPC
5000
connectionsstockTDE-4TDE-4-eTDE-9TDE-9-e
124.232,584.350,822.176,312.183,952.167,18
165.466,425.259,302.908,342.960,762.908,90
204.791,086.854,993.385,013.415,353.381,12
244.676,965.967,643.983,863.993,323.994,85
284.568,794.544,864.514,534.547,604.537,21
325.151,625.085,775.058,355.087,525.029,79
365.658,665.718,435.507,315.616,755.511,39
406.138,716.167,155.952,185.948,256.007,10
446.437,956.569,216.453,016.356,466.432,60
486.968,817.012,236.807,956.845,926.791,73

 

TDE performance TPC 5000

Note that all results have to be taken with a grain of salt. Run-times can always vary slightly. This is especially true if SSD’s are in use. We have seen that over and over again. The performance level we can expect will also highly depend on the PostgreSQL cache performance. Remember: every time a block is sent to disk or read into shared buffers, the encryption/decryption magic has to happen. Thus it can make a lot of sense to run PostgreSQL TDE with higher shared_buffers settings than you would normally do, in order to reduce the impact of security.

CONTACT US

If you are aiming for better PostgreSQL database performance, we suggest checking out our consulting services. We can help you to speed up your database considerably. We offer timely delivery, professional handling, and over 20 years of PostgreSQL experience.

Contact us >>

 

Also: check out PostgreSQL Transparent Data Encryption for transparent and cryptographically safe data (cluster) level encryption. TDE helps you to secure your most valuable asset: your data.

Check out TDE >>