CYBERTEC Logo

PostgreSQL performance: Encrypted vs. unencrypted

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. It is a part of CYBERTEC PostgreSQL Enterprise Edition (PGEE).

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

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:

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.

R-O 50: Performance shown by bar chart - TDE

The following image shows the basic architecture of PostgreSQL TDE:

Basic architecture TDE PostgreSQL encryption

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:

R-O 500: Performance shown by bar chart - TDE

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.

R-O 5000: Performance shown by bar chart - TDE

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.

TPC 50: Performance shown by bar chart - TDE

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
TPC 500: Performance shown by bar chart - TDE

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
TPC 5000: Performance shown by bar chart - TDE

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.

CYBERTEC Logo white
CYBERTEC PostgreSQL International GmbH
Römerstraße 19
2752 Wöllersdorf
Austria

+43 (0) 2622 93022-0
office@cybertec.at

Get the newest PostgreSQL Info & Tools


    This site is protected by reCAPTCHA and the Google Privacy Policy & Terms of Service apply.

    ©
    2024
    CYBERTEC PostgreSQL International GmbH
    phone-handsetmagnifiercrosscross-circle
    linkedin facebook pinterest youtube rss twitter instagram facebook-blank rss-blank linkedin-blank pinterest youtube twitter instagram