尽管有足够的可用内存,但 Postgres 仍然出现内存不足错误

Postgres gets out of memory errors despite having plenty of free memory

我有一个服务器 运行ning Postgres 9.1.15。服务器有 2GB RAM,没有交换空间。间歇性地,Postgres 将开始在某些 SELECT 上出现 "out of memory" 错误,并且会继续这样做,直到我重新启动 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(其他都注释掉out/default):

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(我选择了"mixed type of applications")那里得到了这些值,并根据我所读的内容一直在摆弄它们,但没有取得太大的实际进展。目前有 68 个连接,这是一个典型的数字(我还没有使用 pgbouncer 或任何其他连接池)。

/etc/sysctl.conf:

kernel.shmmax=1050451968
kernel.shmall=256458

vm.overcommit_ratio=100
vm.overcommit_memory=2

大约两周前,在 OOM 杀手杀死了 Postgres 服务器后,我第一次将 overcommit_memory 更改为 2。在此之前,服务器已经 运行 正常运行了很长时间。我现在得到的错误没有那么严重,但更烦人,因为它们更频繁。

我没有多少运气来确定导致 postgres 运行 "out of memory" 的第一个事件 - 似乎每次都不一样。最近一次崩溃时,记录的前三行是:

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 一直 运行。也就是说,这里有一个解释分析: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 中获取确切的数字,与此同时,这是我所有信息的脑力转储。

关于从这里到哪里去的任何想法?

我只是 运行 遇到了同样的问题,我试图恢复一个 ~2.5 GB 的纯文本 SQL 文件。我将我的 Digital Ocean 服务器扩展到 64 GB RAM,创建了一个 10 GB 的交换文件,然后再次尝试。我遇到了 50 GB 可用内存不足的错误,并且没有使用交换空间。

我将我的服务器缩减到我正在使用的 1 GB 小型实例(需要重新启动)并且我想我会再试一次,除了我感到沮丧之外没有其他原因。我开始导入并意识到我忘记再次创建我的临时交换文件。

我在导入过程中创建了它。 psql 在崩溃之前使它更进一步 lot。它通过了另外 5 个表格。

我认为 psql 中一定存在分配内存的错误。

能不能在出现错误时检查一下是否有可用的交换内存?

我已经完全删除了 Linux 桌面中的交换内存(只是为了测试其他东西...),我得到了完全相同的错误!我很确定你也是这样。

您报告的可用内存大小与 shared_buffers 大小相同,这有点可疑。您确定您正在查找正确的值吗?

崩溃时 free 命令的输出和 /proc/meminfo

的内容一样有用

请注意,如果您看到 overcommit_ratio 为 100,则将 overcommit_memory 设置为 2 并不是那么有效。它基本上会将内存分配限制为大小交换(在本例中为 0)+ 100物理 RAM 的百分比,不考虑共享内存和磁盘缓存的任何 space。

您可能应该将 overcommit_ratio 设置为 50。