Postgres尽管拥有足够的可用内存,但仍会发生内存不足错误

问题描述:

我有一台运行Postgres 9.1.15的服务器。该服务器有2GB的RAM并且没有交换。间歇性Postgres将开始在某些SELECT上出现“内存不足”错误,并且将继续这样做,直到我重新启动Postgres 某些连接到它的客户端。奇怪的是,当发生这种情况时,free仍然报告超过500MB的可用内存。Postgres尽管拥有足够的可用内存,但仍会发生内存不足错误

select version();

PostgreSQL 9.1.15 on x86_64-unknown-linux-gnu, compiled by gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3, 64-bit 

uname -a

Linux db 3.2.0-23-virtual #36-Ubuntu SMP Tue Apr 10 22:29:03 UTC 2012 x86_64 x86_64 x86_64 GNU/Linux 

postgresql.conf里(一切被注释掉/默认):

max_connections = 100 
shared_buffers = 500MB 
work_mem = 2000kB 
maintenance_work_mem = 128MB 
wal_buffers = 16MB 
checkpoint_segments = 32 
checkpoint_completion_target = 0.9 
random_page_cost = 2.0 
effective_cache_size = 1000MB 
default_statistics_target = 100 
log_temp_files = 0 

我从pgtune得到这些值(我选择了“混合类型的应用程序”),并一直在摆弄wi基于我读过的内容,而没有取得太大的进展。目前有68个连接,这是一个典型的数字(我没有使用pgbouncer或任何其他连接存储器)。

/etc/sysctl.conf

kernel.shmmax=1050451968 
kernel.shmall=256458 

vm.overcommit_ratio=100 
vm.overcommit_memory=2 

我首先改变overcommit_memory至2大约两周前的OOM杀手杀死了Postgres的服务器后。在此之前,服务器运行良好很长时间。我现在得到的错误不那么灾难性,但更烦人,因为它们更频繁。

我没有太多的运气,查明导致postgres运行“内存不足”的第一个事件 - 它似乎每次都不一样。坠毁最近时间,前三行记录的是:

2015-04-07 05:32:39 UTC ERROR: out of memory 
2015-04-07 05:32:39 UTC DETAIL: Failed on request of size 125. 
2015-04-07 05:32:39 UTC CONTEXT: automatic analyze of table "xxx.public.delayed_jobs" 
TopMemoryContext: 68688 total in 10 blocks; 4560 free (4 chunks); 64128 used 
[... snipped heaps of lines which I can provide if they are useful ...] 

--- 

2015-04-07 05:33:58 UTC ERROR: out of memory 
2015-04-07 05:33:58 UTC DETAIL: Failed on request of size 16. 
2015-04-07 05:33:58 UTC STATEMENT: SELECT oid, typname, typelem, typdelim, typinput FROM pg_type 
2015-04-07 05:33:59 UTC LOG: could not fork new process for connection: Cannot allocate memory 
2015-04-07 05:33:59 UTC LOG: could not fork new process for connection: Cannot allocate memory 
2015-04-07 05:33:59 UTC LOG: could not fork new process for connection: Cannot allocate memory 
TopMemoryContext: 396368 total in 50 blocks; 10160 free (28 chunks); 386208 used 
[... snipped heaps of lines which I can provide if they are useful ...] 

--- 

2015-04-07 05:33:59 UTC ERROR: out of memory 
2015-04-07 05:33:59 UTC DETAIL: Failed on request of size 1840. 
2015-04-07 05:33:59 UTC STATEMENT: SELECT... [nested select with 4 joins, 19 ands, and 2 order bys] 
TopMemoryContext: 388176 total in 49 blocks; 17264 free (55 chunks); 370912 used 

在此之前的崩溃,几个小时前,刚刚度过这最后的查询的三个实例作为第一个三线崩溃。该查询经常运行非常,所以我不确定问题是,因为此查询的,或者它只是出现在错误日志中,因为它是一个相当复杂的SELECT始终运行。这就是说,这里是一个EXPLAIN分析吧:http://explain.depesz.com/s/r00

这是ulimit -a为postgres用户的样子:

core file size   (blocks, -c) 0 
data seg size   (kbytes, -d) unlimited 
scheduling priority    (-e) 0 
file size    (blocks, -f) unlimited 
pending signals     (-i) 15956 
max locked memory  (kbytes, -l) 64 
max memory size   (kbytes, -m) unlimited 
open files      (-n) 1024 
pipe size   (512 bytes, -p) 8 
POSIX message queues  (bytes, -q) 819200 
real-time priority    (-r) 0 
stack size    (kbytes, -s) 8192 
cpu time    (seconds, -t) unlimited 
max user processes    (-u) 15956 
virtual memory   (kbytes, -v) unlimited 
file locks      (-x) unlimited 

我会试着从free下一次有一个碰撞获得确切的数字,在此期间,这是我拥有的所有信息的问题。

任何想法去哪里从这里?

+0

AFAIK的内核,如果它分配给承诺的内存来处理,即使他们永远不会使用它。这包括从postmaster编写的写入时复制内存区'fork()'。所以即使内存是空闲的,但目前还没有被映射到进程的地址空间中,但它已经被提交。我认为。我可能会在这里完全挥手。内核对共享内存进行统计的一些怪异问题也有可能存在。 –

+1

'maintenance_work_mem = 128MB'因为你的内存限制似乎相当大。自动分析启动时发生问题的事实也表明此参数太大。 –

+0

@a_horse_with_no_name我试着将它设置为'16MB'。将报告结果。在此期间还有什么要注意的? –

当错误发生时,您可以检查是否有可用的交换内存?

我已经完全删除了我的Linux桌面上的交换内存(仅用于测试其他东西......),并且我得到了完全相同的错误!我很确定这也是你们的情况。

+0

我收到了这条消息,我也交换了。可能是这个错误的原因... – alfonx

我刚刚遇到了同样的问题,我试图恢复一个〜2.5 GB的纯文本SQL文件。我将数字海洋服务器扩展到64 GB RAM,创建了10 GB交换文件,然后再次尝试。我收到了50 GB的内存不足错误,并且没有使用交换。

我将服务器缩小到我使用的小1 GB实例(需要重新启动),并且认为除了我感到沮丧之外,我没有其他理由再给它一次。我开始导入并意识到我忘了再次创建我的临时交换文件。

我在导入过程中创建了它。 psql在碰撞之前进一步将其编号为lot。它通过了5个额外的表格。

我认为psql中必须有一个分配内存的bug。

您报告与shared_buffers大小相同的空闲内存大小有点可疑。你确定你正在寻找正确的价值?

在崩溃时

输出free命令将是有益的,以及内容的/ proc/meminfo中

若设置overcommit_memory 2,如果你看到overcommit_ratio〜100将不那么有效基本上将内存分配限制为大小交换(在本例中为0)+物理RAM的100%,这不考虑共享内存和磁盘高速缓存的空间。

你或许应该设置overcommit_ratio至50

+0

我认为这只是我写这个问题的巧合。这是超过500MB免费(如在“成堆的记忆!”),而不是一个硬性价值。也就是说,我认为这是'overcommit_ratio'上的一个好点 - 会对此进行修补。 –