PostgreSQL尽管有大量可用内存,仍会出现内存不足的错误。

14

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

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获得了这些值(我选择了“混合类型的应用程序”),并根据我的阅读进行了一些调整,但没有取得很多实际进展。目前有68个连接,这是一个典型的数字(我还没有使用pgbouncer或任何其他连接池器)。

/etc/sysctl.conf

kernel.shmmax=1050451968
kernel.shmall=256458

vm.overcommit_ratio=100
vm.overcommit_memory=2

两周前,由于OOM killer杀死了Postgres服务器,我首先将overcommit_memory更改为2。在那之前,该服务器长时间运行良好。现在出现的错误虽然不那么严重,但非常烦人,因为它们更加频繁。

我还没有找到导致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 ANALYZE: http://explain.depesz.com/s/r00 这是postgres用户的ulimit -a的样子:
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获取精确的数字,同时这里是我所拥有的所有信息的脑力倾泻。

你有任何想法可以继续探讨吗?


1
考虑到您的内存限制,“maintenance_work_mem = 128MB”似乎相当大。问题发生时自动分析启动,这也表明此参数过大。 - user330315
1
2GB 的内存没有交换空间并不算很多。如果没有交换空间,操作系统在内存短暂耗尽时就无法做任何事情。而且,内核要进行内存碎片整理也更加困难。你可能有足够的空闲内存,但它可能全部都是碎片化的。考虑增加一些交换空间,至少 4GB。 - Schwern
1
除非你真的需要它们,否则请降低max_connections。降低shared_buffers(:-信任于OS-cache)也是一个选项(在Linux中,共享内存被锁定在核心中且无法交换,如果我没记错的话)。还有:添加一些交换空间。 - joop
运行过多的连接是一个真正的停机器(死锁的概率呈指数级增长...另外:work_mem在每个连接上都会花费(可能还包括其中的每个子查询))。连接池可能是个好主意。但是:内存很便宜。交换空间更便宜。如果您的OOM killer一天只启动一次,添加交换空间至少可以让作业完成。 - joop
增加1GB的交换空间并减少maintenance_work_mem已经有了很大的改进。然而,由free报告的内存使用仍会随着时间的推移逐渐增加(只是慢得多)。我还需要注意或者知道其他什么吗? - Alex Ghiculescu
显示剩余3条评论
3个回答

3
我遇到了同样的问题,我试图恢复一个约2.5 GB的纯文本SQL文件。我将我的Digital Ocean服务器升级到64 GB RAM,创建了一个10 GB的交换文件,并再次尝试。即使有50 GB的可用内存和没有使用的swap,我仍然遇到了内存不足的错误。
我将服务器缩小到原来使用的小型1 GB实例(需要重新启动),并决定再试一次,原因只是我感到沮丧。我开始导入并意识到我忘记再次创建我的临时交换文件。
在导入过程中我创建了它。psql收集更多数据后才崩溃,它成功地导入了另外5个表。
我认为在psql中分配内存存在错误。

2

当错误出现时,你能否检查是否有可用的交换内存?

我已经完全删除了我的Linux桌面上的交换内存(只是为了测试其他东西...),而且我也收到了完全相同的错误!我非常确定这也是你所遇到的问题。


我收到了这个消息,而且我也有交换空间...可能是这个错误的原因... - alfonx

1

你报告的可用内存大小与 shared_buffers 大小相同,有点可疑。你确定你查看了正确的值吗?

在崩溃时输出 free 命令的结果和 /proc/meminfo 文件内容会很有用。

请注意,如果将 overcommit_memory 设置为 2,而 overcommit_ratio 为 100,那么效果可能不太好。它基本上将内存分配限制为交换空间的大小(在这种情况下为 0)+ 物理 RAM 的 100%,这并没有考虑任何用于共享内存和磁盘缓存的空间。

你应该把 overcommit_ratio 设置为 50。


我认为这只是我写问题时的巧合。它超过了500MB的空闲内存(也就是说,“有很多内存!”),而不是一个硬值。话虽如此,我认为overcommit_ratio是一个很好的点子 - 我会试着调整一下。 - Alex Ghiculescu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接