Thread: Memory usage and configuration settings

Memory usage and configuration settings

From
Mike C
Date:
Hi,

I have been using table 17-2, Postgres Shared Memory Usage
(http://www.postgresql.org/docs/9.1/interactive/kernel-resources.html)
to calculate approximately how much memory the server will use. I'm
using Postgres 9.1 on a Linux 2.6 (RHEL 6) 64bit system, with 8GB RAM.
Database is approximately 5GB, and is a mixture of read/write.
Postgres is occasionally being killed by the linux oom-killer. I am
trying to understand how much memory postgres could use, and how to
change the configuration to bring it down to a level that won't get it
killed.

Key configuration values are:

max_connections = 350
shared_buffers = 4GB
temp_buffers = 24MB
max_prepared_transactions = 211
work_mem = 16MB
maintenance_work_mem = 131MB
wal_buffers = -1
wal_keep_segments = 128
checkpoint_segments = 64
effective_cache_size = 4GB
autovacuum_max_workers = 4

which I have interpreted to be:

max_locks_per_transaction = 64
max_connections = 350
autovacuum_max_workers =4
max_prepared_transactions = 211 (I've since realised this can be 0; I
use prepared statements, not 2PC)
shared_buffers = 4294967296
wal_block_size = 8192
wal_buffers = 16777216 (actually, -1, but following the documentation
of max(16MB, shared_buffers/32) it should be 16MB).
and wal segment size = 16777216, block_size = 8192

And using the equations on the kernel resources page, I get:

Connections = 6,678,000
                     = (1800 + 270 * max_locks_per_transaction) *
max_connections
                     = (1800 + 270 * 64) * 350
Autovacuum Workers = 76,320
                                    = (1800 + 270 *
max_locks_per_transaction) * autovacuum_max_workers
                                    = (1800 + 270 * 64) * 4
Prepared Transactions = 3,808,550
                                      = (770 + 270 *
max_locks_per_transaction) * max_prepared_transactions
                                      = (770 + 270 * 64) * 211
Shared Disk Buffers     = 36,077,725,286,400
                                 = (block_size + 208) * shared_buffers
                                 = (8192 + 208) * 4294967296
                                 = ~33TB
WAL Buffers = 137,573,171,200
                     = (wal_block_size + 8) * wal_buffers
                     = (8192 + 8) * 16777216
                     = ~128GB
Fixed Space Requirements = 788,480
Overall = 36,215,309,808,950 bytes (~33.2 TB!)

33.2TB doesn't seem right, and while I know the equations are just
approximations, this seems too much. What have I done wrong? I read a
prior thread about this on the pgsql lists which seemed to indicate
the equations for shared disk and wall buffers should be divided by
the block_size 8192, and looking at it closer, wonder if the equation
for both should just be overhead + buffer?

Also what is the relationship between memory and work_mem (set to 16M
in my case). I understand work_mem is per sort, and in most cases our
queries only have a single sort. Does this mean an additional 16M per
sorting client (350 * 16M = 5.6GB), or presumably it only uses the
work memory as it needs it (i.e. does it preallocate all 16M for each
sort, or on an as-needed basis depending on the size of sorted data?)

Are there any other ways to calculate the worst case memory usage of a
given postgres configuration?

My gut feeling is to reduce shared_buffer to 1GB or less and reduce
connections to ~150-200 (to reduce worst case work_mem impact).

Kind Regards,

Mike

Re: Memory usage and configuration settings

From
Tom Lane
Date:
Mike C <smith.not.western@gmail.com> writes:
> I have been using table 17-2, Postgres Shared Memory Usage
> (http://www.postgresql.org/docs/9.1/interactive/kernel-resources.html)
> to calculate approximately how much memory the server will use. I'm
> using Postgres 9.1 on a Linux 2.6 (RHEL 6) 64bit system, with 8GB RAM.
> Database is approximately 5GB, and is a mixture of read/write.
> Postgres is occasionally being killed by the linux oom-killer. I am
> trying to understand how much memory postgres could use, and how to
> change the configuration to bring it down to a level that won't get it
> killed.

Basically, you can't fix it that way, at least not if you want to have a
sane configuration.  The problem is misdesign of the OOM killer: it will
count the shared memory block against the postmaster *once for each
child process*.  The only realistic solution is to turn off OOM kill for
the postmaster (and maybe its children too, or maybe you'd rather have
them immune as well).  The former is pretty easy to do if you're
launching the postmaster from a root-privileged initscript.  I think
most prepackaged versions of PG are set up to be able to do this
already.  If you want the children OOM-killable it requires a
source-code tweak as well, since that property is normally inherited.

But anyway, your calculations are totally off:

> Shared Disk Buffers     = 36,077,725,286,400
>                                  = (block_size + 208) * shared_buffers
>                                  = (8192 + 208) * 4294967296
>                                  = ~33TB

I think you've multiplied by the block size one time too many.  Ditto
for WAL buffers.

            regards, tom lane

Re: Memory usage and configuration settings

From
Mike C
Date:
On Mon, Mar 5, 2012 at 4:04 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
> Mike C <smith.not.western@gmail.com> writes:
>> I have been using table 17-2, Postgres Shared Memory Usage
>> (http://www.postgresql.org/docs/9.1/interactive/kernel-resources.html)
>> to calculate approximately how much memory the server will use. I'm
>> using Postgres 9.1 on a Linux 2.6 (RHEL 6) 64bit system, with 8GB RAM.
>> Database is approximately 5GB, and is a mixture of read/write.
>> Postgres is occasionally being killed by the linux oom-killer. I am
>> trying to understand how much memory postgres could use, and how to
>> change the configuration to bring it down to a level that won't get it
>> killed.
>
> Basically, you can't fix it that way, at least not if you want to have a
> sane configuration.  The problem is misdesign of the OOM killer: it will
> count the shared memory block against the postmaster *once for each
> child process*.  The only realistic solution is to turn off OOM kill for
> the postmaster (and maybe its children too, or maybe you'd rather have
> them immune as well).  The former is pretty easy to do if you're
> launching the postmaster from a root-privileged initscript.  I think
> most prepackaged versions of PG are set up to be able to do this
> already.  If you want the children OOM-killable it requires a
> source-code tweak as well, since that property is normally inherited.

Ok, that makes sense. With regards to work_mem, am I right in thinking
the child processes only allocate enough memory to meet the task at
hand, rather than the full 16M specified in the config file?

> But anyway, your calculations are totally off:
>
>> Shared Disk Buffers    = 36,077,725,286,400
>>                                  = (block_size + 208) * shared_buffers
>>                                  = (8192 + 208) * 4294967296
>>                                  = ~33TB
>
> I think you've multiplied by the block size one time too many.  Ditto
> for WAL buffers.

Yes spot on, removed the block_size and it is now the more sane ~4.1GB.

Thanks for your help,

Mike

Re: Memory usage and configuration settings

From
Tom Lane
Date:
Mike C <smith.not.western@gmail.com> writes:
> Ok, that makes sense. With regards to work_mem, am I right in thinking
> the child processes only allocate enough memory to meet the task at
> hand, rather than the full 16M specified in the config file?

They only allocate what's needed ... but you have to keep in mind that
work_mem is *per operation*, eg per sort or hash.  A complex query could
require several such steps and thus eat several times work_mem.

            regards, tom lane

Re: Memory usage and configuration settings

From
Merlin Moncure
Date:
On Mon, Mar 5, 2012 at 6:37 AM, Mike C <smith.not.western@gmail.com> wrote:
> Hi,
>
> I have been using table 17-2, Postgres Shared Memory Usage
> (http://www.postgresql.org/docs/9.1/interactive/kernel-resources.html)
> to calculate approximately how much memory the server will use. I'm
> using Postgres 9.1 on a Linux 2.6 (RHEL 6) 64bit system, with 8GB RAM.
> Database is approximately 5GB, and is a mixture of read/write.
> Postgres is occasionally being killed by the linux oom-killer. I am
> trying to understand how much memory postgres could use, and how to
> change the configuration to bring it down to a level that won't get it
> killed.
>
> Key configuration values are:
>
> max_connections = 350
> shared_buffers = 4GB
> temp_buffers = 24MB
> max_prepared_transactions = 211
> work_mem = 16MB
> maintenance_work_mem = 131MB
> wal_buffers = -1
> wal_keep_segments = 128
> checkpoint_segments = 64
> effective_cache_size = 4GB
> autovacuum_max_workers = 4
>
> which I have interpreted to be:
>
> max_locks_per_transaction = 64
> max_connections = 350
> autovacuum_max_workers =4
> max_prepared_transactions = 211 (I've since realised this can be 0; I
> use prepared statements, not 2PC)
> shared_buffers = 4294967296
> wal_block_size = 8192
> wal_buffers = 16777216 (actually, -1, but following the documentation
> of max(16MB, shared_buffers/32) it should be 16MB).
> and wal segment size = 16777216, block_size = 8192
>
> And using the equations on the kernel resources page, I get:
>
> Connections = 6,678,000
>                     = (1800 + 270 * max_locks_per_transaction) *
> max_connections
>                     = (1800 + 270 * 64) * 350
> Autovacuum Workers = 76,320
>                                    = (1800 + 270 *
> max_locks_per_transaction) * autovacuum_max_workers
>                                    = (1800 + 270 * 64) * 4
> Prepared Transactions = 3,808,550
>                                      = (770 + 270 *
> max_locks_per_transaction) * max_prepared_transactions
>                                      = (770 + 270 * 64) * 211
> Shared Disk Buffers      = 36,077,725,286,400
>                                 = (block_size + 208) * shared_buffers
>                                 = (8192 + 208) * 4294967296
>                                 = ~33TB
> WAL Buffers = 137,573,171,200
>                     = (wal_block_size + 8) * wal_buffers
>                     = (8192 + 8) * 16777216
>                     = ~128GB
> Fixed Space Requirements = 788,480
> Overall = 36,215,309,808,950 bytes (~33.2 TB!)
>
> 33.2TB doesn't seem right, and while I know the equations are just
> approximations, this seems too much. What have I done wrong? I read a
> prior thread about this on the pgsql lists which seemed to indicate
> the equations for shared disk and wall buffers should be divided by
> the block_size 8192, and looking at it closer, wonder if the equation
> for both should just be overhead + buffer?
>
> Also what is the relationship between memory and work_mem (set to 16M
> in my case). I understand work_mem is per sort, and in most cases our
> queries only have a single sort. Does this mean an additional 16M per
> sorting client (350 * 16M = 5.6GB), or presumably it only uses the
> work memory as it needs it (i.e. does it preallocate all 16M for each
> sort, or on an as-needed basis depending on the size of sorted data?)
>
> Are there any other ways to calculate the worst case memory usage of a
> given postgres configuration?
>
> My gut feeling is to reduce shared_buffer to 1GB or less and reduce
> connections to ~150-200 (to reduce worst case work_mem impact).

One easy thing to neglect when doing memory counting is backend
private memory.  Each postgres process typically eats around 1mb and
this will grow if your processes are long-lived as the backend starts
to cache various structures.  As a rule of thumb I tend to use 4mb per
backend (you can confirm this yourself by subtracting SHR from RES).
In absolutely pathological cases (like heavy plpgsql backends with a
lot of tables and views) it can be worse.  4mb * 350 = 1.4gb...so
you're cutting things fairly close.

Looking at your postgresql.conf, your memory settings for
shared_buffers are a more aggressive than the often suggested 25% rule
but I bet it's the backend memory that's pushing you over the edge.

Rather than reducing backend count, I'd consider (carefully) using
pgbouncer to reduce overall connection count.  Or you can reduce
shared buffers, but in your case I'd probably cut it to 1GB if it was
me.

merlin