For optimum performance, a PostgreSQL database depends on the operating system parameters being defined correctly. Poorly configured OS kernel parameters can cause degradation in database server performance. Therefore, it is imperative that these parameters are configured according to the database server and its workload. In this post, we will discuss some important Linux kernel parameters that can affect database server performance and how these should be tuned.

SHMMAX / SHMALL

SHMMAX is a kernel parameter used to define the maximum size of a single shared memory segment a Linux process can allocate. Until version 9.2, PostgreSQL uses System V (SysV) that requires SHMMAX setting. After 9.2, PostgreSQL switched to POSIX shared memory. So now it requires fewer bytes of System V shared memory.

Prior to version 9.3 SHMMAX was the most important kernel parameter. The value of SHMMAX is in bytes.

Similarly, SHMALL is another kernel parameter used to define system-wide total amount of shared memory pages. To view the current values for SHMMAX, SHMALL or SHMMIN, use the ipcs command.

PostgreSQL uses System V IPC to allocate shared memory. This parameter is one of the most important kernel parameters. Whenever you get following error messages, it means that you have an older version PostgreSQL and you have a very low SHMMAX value. Users are expected to adjust and increase the value according to the shared memory they are going to use.

Possible misconfiguration errors

If SHMMAX is misconfigured, you can get an error when trying to initialize a PostgreSQL cluster using the initdb command.

Similarly, you can get an error when starting the PostgreSQL server using the pg_ctl command.

Be aware of differing definitions

The definition of the SHMMAX/SHMALL parameters is slightly different between Linux and MacOS X. These are the definitions:

  • Linux: kernel.shmmax, kernel.shmall
  • MacOS X: kern.sysv.shmmax, kern.sysv.shmall

The sysctl command can be used to change the value temporarily. To permanently set the value, add an entry into /etc/sysctl.conf. The details are given below.

Remember: to make the change permanent add these values in /etc/sysctl.conf 

Huge Pages

Linux, by default, uses 4K memory pages, BSD has Super Pages, whereas Windows has Large Pages. A page is a chunk of RAM that is allocated to a process. A process may own more than one page depending on its memory requirements. The more memory a process needs the more pages that are allocated to it. The OS maintains a table of page allocation to processes. The smaller the page size, the bigger the table, the more time required to look up a page in that page table. Therefore, huge pages make it possible to use a large amount of memory with reduced overheads; fewer page lookups, fewer page faults, faster read/write operations through larger buffers. This results in improved performance.

PostgreSQL has support for bigger pages on Linux only. By default, Linux uses 4K of memory pages, so in cases where there are too many memory operations, there is a need to set bigger pages. Performance gains have been observed by using huge pages with sizes 2 MB and up to 1 GB. The size of Huge Page can be set boot time. You can easily check the huge page settings and utilization on your Linux box using cat /proc/meminfo | grep -i huge command.

In this example, although huge page size is set at 2,048 (2 MB), the total number of huge pages has a value of 0. which signifies that huge pages are disabled.

Script to quantify Huge Pages

This is a simple script which returns the number of Huge Pages required. Execute the script on your Linux box while your PostgreSQL is running. Ensure that $PGDATA environment variable is set to PostgreSQL’s data directory.

The output of the script looks like this:

The recommended huge pages are 88, therefore you should set the value to 88.

Check the huge pages now, you will see no huge page is in use (HugePages_Free = HugePages_Total).

Now set the parameter huge_pages “on” in $PGDATA/postgresql.conf and restart the server.

Now you can see that a very few of the huge pages are used. Let’s now try to add some data into the database.

Let’s see if we are now using more huge pages than before.

Now you can see that most of the huge pages are in use.

Note: The sample value for HugePages used here is very low, which is not a normal value for a big production machine. Please assess the required number of pages for your system and set those accordingly depending on your system’s workload and resources.

vm.swappiness

vm.swappiness is another kernel parameter that can affect the performance of the database. This parameter is used to control the swappiness (swapping pages to and from swap memory into RAM) behavior on a Linux system. The value ranges from 0 to 100. It controls how much memory will be swapped or paged out. Zero means disable swap and 100 means aggressive swapping.

You may get good performance by setting lower values.

Setting a value of 0 in newer kernels may cause the OOM Killer (out of memory killer process in Linux) to kill the process. Therefore, you can be on the safe side and set the value to 1 if you want to minimize swapping. The default value on a Linux system is 60. A higher value causes the MMU (memory management unit) to utilize more swap space than RAM, whereas a lower value preserves more data/code in memory.

A smaller value is a good bet to improve performance in PostgreSQL.

vm.overcommit_memory / vm.overcommit_ratio

Applications acquire memory and free that memory when it is no longer needed. But in some cases, an application acquires too much memory and does not release it.  This can invoke the OOM killer. Here are the possible values for vm.overcommit_memory parameter with a description for each:

    1. Heuristic overcommit, Do it intelligently (default); based kernel heuristics
    2. Allow overcommit anyway
    3. Don’t over commit beyond the overcommit ratio.

Reference: https://www.kernel.org/doc/Documentation/vm/overcommit-accounting

vm.overcommit_ratio is the percentage of RAM that is available for overcommitment. A value of 50% on a system with 2 GB of RAM may commit up to 3 GB of RAM.

A value of 2 for vm.overcommit_memory yields better performance for PostgreSQL. This value maximizes RAM utilization by the server process without any significant risk of getting killed by the OOM killer process. An application will be able to overcommit, but only within the overcommit ratio, thus reducing the risk of having OOM killer kill the process. Hence a value to 2 gives better performance than the default 0 value. However, reliability can be improved by ensuring that memory beyond an allowable range is not overcommitted. It avoids the risk of the process being killed by OOM-killer.

On systems without swap, one may experience a problem when vm.overcommit_memory is 2.

https://www.postgresql.org/docs/current/static/kernel-resources.html#LINUX-MEMORY-OVERCOMMIT

vm.dirty_background_ratio / vm.dirty_background_bytes

The vm.dirty_background_ratio is the percentage of memory filled with dirty pages that need to be flushed to disk. Flushing is done in the background. The value of this parameter ranges from 0 to 100; however, a value lower than 5 may not be effective and some kernels do not internally support it. The default value is 10 on most Linux systems. You can gain performance for write-intensive operations with a lower ratio, which means that Linux flushes dirty pages in the background.

You need to set a value of vm.dirty_background_bytes depending on your disk speed.

There are no “good” values for these two parameters since both depend on the hardware. However, setting vm.dirty_background_ratio to 5 and vm.dirty_background_bytes to 25% of your disk speed improves performance by up to ~25% in most cases.

vm.dirty_ratio / dirty_bytes

This is the same as vm.dirty_background_ratio / dirty_background_bytes except that the flushing is done in the foreground, blocking the application. So vm.dirty_ratio should be higher than vm.dirty_background_ratio. This will ensure that background processes kick in before the foreground processes to avoid blocking the application, as much as possible. You can tune the difference between the two ratios depending on your disk IO load.

Summing up

You can tune other parameters for performance, but the improvement gains are likely to be minimal. We must keep in mind that not all parameters are relevant to all applications types. Some applications perform better by tuning some parameters and some applications don’t. You need to find a good balance between these parameter configurations for the expected application workload and type, and OS behavior must also be kept in mind when making adjustments. Tuning kernel parameters are not as easy as tuning database parameters: it’s harder to be prescriptive.

In my next post, I’ll take a look at tuning PostgreSQL’s database parameters.

You May Also Like

Did you know sysbench-tpcc works with PostgreSQL now? Read our blog to learn how you can set up PostgreSQL to perform optimally for sysbench-tpcc.

Reviewing raw MySQL query logs can be more useful than working with tools that only have summary data. Percona CEO Peter Zaitsev details why this is the case and the benefits of examining this kind of information in his blog, Why Analyze Raw MySQL Query Logs?

Learn how to avoid the top 10 deadly PostgreSQL mistakes in our free webinar, “How to Avoid the 10 Deadly PostgreSQL Mistakes“.

Watch the On-Demand Webinar 

9 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Nils

Through sysfs, you can use both 2MiB and 1 GiB pages (on amd64, other architectures may support more / different sizes), assuming AMD64 architecture:

/sys/kernel/mm/hugepages/hugepages-1048576kB/
/sys/kernel/mm/hugepages/hugepages-2048kB/

Usually the TLB will support a combination of different huge page sizes, so it may make sense to set both for optimum performance (the thing to optimize for is reducing TLB misses). When looking for information on this topic please keep in mind that it’s different from TRANSPARENT huge pages.

Nils

Forgot to add, to be able to use huge pages the process user must be a member of the group set in /proc/sys/vm/hugetlb_shm_group, I believe this is also missing from the article. With MySQL at least, InnoDB will allocate regular memory when HugeTLB allocation fails, which usually results in running out of memory since the hugepage memory is reserved. A bonus: (Explicit) Huge pages can’t be swapped out.

Douglas Hunley

For vm.dirty_background_ratio (and vm.dirty_ratio) you can’t set both the ratio *and* the bytes. You set one or the other.

Hamid Akhtar

I don’t know much about huge pages on AMD64 (or even AMD64 for that matter), but AFAIK, PostgreSQL doesn’t honour multiple huge page sizes. Even if you have groups of multiple huge pages with different sizes, PostgreSQL will pick up the first line of “/proc/meminfo” containing “Hugepagesize”.

It’ll then sscanf the line to pickup huge page size in kb and ignore whatever comes after that. So, I doubt that in case of PostgreSQL, you’ll see any performance gain.

Nils

That’s very valuable information Hamid, I don’t actually know how hugepage allocation works within glibc or whatever memory allocator is being used. I think it’s worth looking into, but it’s a somewhat exotic topic, this thing has increased in impact after the infamous Meltdown bug since depending on Linux version it’ll require a TLB flush.

Can we do a benchmark Ibrar?

marcio

Hi ! Very good tech informations.
Please let me know how I may compute good parameters for a server with 7 instances of Postgres, considering this study ?!