Postgres получает из памяти ошибки, несмотря на наличие большого количества свободной памяти

У меня есть сервер с Postgres 9.1.15. Сервер имеет 2 ГБ ОЗУ и без обмена. Периодически Postgres начнет получать ошибки "из памяти" на некоторых SELECT и будет продолжать делать это до тех пор, пока я не перезапущу Postgres или некоторые из клиентов, которые к нему подключены. Что странно, когда это происходит, free все еще сообщает о 500 МБ свободной памяти.

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

Сначала я изменил 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 ANALYZE: 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 в следующий раз, когда произойдет сбой, тем временем это будет braindump всей информации, которую у меня есть.

Любые идеи о том, куда идти отсюда?

Ответ 1

Можете ли вы проверить, есть ли какая-либо память подкачки при возникновении ошибки?

Я полностью удаляю память подкачки на своем рабочем столе Linux (только для тестирования других вещей...), и я получил точно такую ​​же ошибку! Я почти уверен, что это то, что происходит с вами тоже.

Ответ 2

Я просто столкнулся с этой же проблемой с файлом SQL файла размером ~ 2,5 ГБ, который я пытался восстановить. Я масштабировал свой сервер Digital Ocean до 64 ГБ оперативной памяти, создал файл подкачки объемом 10 ГБ и снова попытался. Я получил ошибку из памяти с 50 ГБ бесплатно и без использования swap.

Я уменьшил свой сервер до небольшого экземпляра 1 ГБ, который использовал (требуя перезагрузки), и решил, что я дам ему еще один снимок только по той причине, что я был расстроен. Я начал импорт и понял, что забыл создать мой файл временного свопа.

Я создал его в середине импорта. psql сделал намного больше перед сбоем. Он сделал это через 5 дополнительных таблиц.

Я думаю, что в psql должна быть ошибка, выделяющая память.

Ответ 3

Немного подозрительно, что вы сообщаете о том же свободном объеме памяти, что и ваш размер shared_buffers. Вы уверены, что ищете правильные значения?

Результат команды free во время сбоя будет полезен, а также содержимое /proc/meminfo

Остерегайтесь того, что установка overcommit_memory в 2 не так эффективна, если вы видите от overcommit_ratio до 100. В основном это ограничивает выделение памяти для свопа размера (в этом случае 0) + 100% физической памяти, что не учитывает какое-либо пространство для разделяемой памяти и кэшей дисков.

Вероятно, вы должны установить overcommit_ratio в 50.