LINUX.ORG.RU

Обработка ошибки Out of memory

 ,


1

1

Всем привет,

Подскажите куда смотреть. Имеется софтинка, которая активно использует ОЗУ, причем пользователи могут туда залить много данных и написать правила обработки этих данных так, что если правила написали неудачно, то софтинка может выжрать всю память.

Ожидается, что если доступная память закончилась, (своп отключен, оом киллер тоже отключен) процесс из аллокатора получит ошибку, что память кончилась и процесс закончит обработку запроса пользователя и освободит выделенную память.

Но процесс запущен в виртуалке в контейнере, хостится девопсами. Происходит следующее - когда память кончается, потоки запрашивающие память переходят в состояние D и мы видим в стеке следующее:

[<ffffffffb244e13d>] mem_cgroup_oom_synchronize+0x16d/0x590
[<ffffffffb23cdad4>] pagefault_out_of_memory+0x14/0x90
[<ffffffffb29aaf88>] mm_fault_error+0x6a/0x15b
[<ffffffffb29bfa61>] __do_page_fault+0x4a1/0x510
[<ffffffffb29bfb05>] do_page_fault+0x35/0x90
[<ffffffffb29bb7b8>] page_fault+0x28/0x30
[<ffffffffffffffff>] 0xffffffffffffffff

Процесс зависает, докер образ становится необслуживаемым и лечится только перезагрузкой. Что мы готовим не так?


Ответ на: комментарий от mrjaggers

нет, правила динамические, пользователь может бездумно может написать что угодно. ПО должно как-то адекватно реагировать. Сейчас реакцией является обработка ошибки OOM

sotlef
() автор топика

Перестать страдать херней, и:

  1. Включить OOM-killer
  2. В программе задать разумные ограничения по вложенности и количеству элементов в «правилах».
lovesan ★★★
()
Ответ на: комментарий от sotlef

Тут либо в софтинке предусмотреть предварительную оценку потребления памяти в зависимости от параметров, либо делить её на 2 части – одну помещать в cgroup c лимитом памяти и OOM, другой мониторить статус процессов и завершать запросы как положено.

snizovtsev ★★★★★
()
Последнее исправление: snizovtsev (всего исправлений: 2)

memory overcommit отключи, тогда malloc вернет тебе NULL (или аналогичную ошибку для языка на котором написана твоя программа)

Но это только девопсы смогут сделать и не факт что они станут - потому что без оверкоммита может другое сломаться.

Pinkbyte ★★★★★
()
Последнее исправление: Pinkbyte (всего исправлений: 3)
Ответ на: комментарий от sotlef

Мысли в слух.

Проверять хватит ли памяти не попыткой выделения памяти, а проверкой доступной и если хватит + накладные расходы памяти на других жителей виртуалки то дёргать маллок иначе ничего не дёргать и просить пользователя умерить пыл запросов на рамку. Я так понял для процесса пользователя то память выделяется, а вот другим уже не хватает.

LINUX-ORG-RU ★★★★★
()
Последнее исправление: LINUX-ORG-RU (всего исправлений: 1)
Ответ на: комментарий от Pinkbyte

Заметили, что имеется настройка under_oom=1 в memory.oom_control.

under_oom 0 or 1 (if 1, the memory cgroup is under OOM, tasks may be stopped.)

Тестим, возможно в этом проблема.

А overcommit отключить, это как делается? Речь идет о vm.overcommit_memory ?

sotlef
() автор топика
Последнее исправление: sotlef (всего исправлений: 1)
Ответ на: комментарий от LINUX-ORG-RU

Ну там параллельно несколько запросов работает. Допустим убедился, что памяти хватит, а другой поток в это время ее съел. В чем тогда резон?

sotlef
() автор топика
Последнее исправление: sotlef (всего исправлений: 1)

Мимокрокодил.

Судя по ману (man malloc, раздел notes), можно попробовать выставить overcommit в двойку

https://www.kernel.org/doc/Documentation/vm/overcommit-accounting.rst

2 Don’t overcommit. The total address space commit for the system is not permitted to exceed swap + a configurable amount (default is 50%) of physical RAM. Depending on the amount you use, in most situations this means a process will not be killed while accessing pages but will receive errors on memory allocation as appropriate.

Useful for applications that want to guarantee their memory allocations will be available in the future without having to initialize every page.

Но не уверен что это работает так как хочет ТС, и что для ТС есть вариант менять оверкоммит. (Хотя, почему, сбстно нет? Описываешь девопсам конфиг системы, они делают.. а там не знаю)

AndreyKl ★★★★★
()
Последнее исправление: AndreyKl (всего исправлений: 1)
Ответ на: комментарий от sotlef

Про параллельно первый раз слышу =) Тогда либо синхронизация в моменты проверки/выделения памяти либо включай своп. Если у тебя память выделяется хаотично и это никак не контролируется и пользователь может задать любой запрос последствия которого в отношении памяти никак не контролируются то на этом мои полномочия всё =) Я лишь предложил.

LINUX-ORG-RU ★★★★★
()
Последнее исправление: LINUX-ORG-RU (всего исправлений: 1)

А сколько памяти у вас планируется выделять под саму софтину/юзера? Подход с выделением всей доступной расходится с политикой запуска в докерах ибо количество всей доступной будет сильно разное в разные моменты времени.

ya-betmen ★★★★★
()
Ответ на: комментарий от AndreyKl

Так ему надо сожрать почти всё, но не совсем. А там уже либо крутить лимиты, либо внутри аллокатор шатать, чтобы учитывал сколько уже занято и не вылезал за собственные лимиты.

Dark_SavanT ★★★★★
()

Другой подход, в отличие от ulimit и overcommit.

Сделай свой аллокатор, отожри при старте сколько у тебя позволено, проинициализируй (чтобы реально выделилась) и потом у тебя полный контроль над тем, сколько ее реально еще есть.

blex ★★★
()

Установи ограничение по памяти для процесса через setrlimit(RLIMIT_VMEM) или, если это чужой софт, команду-обёртку над ним - не помню что там в linux, limit или ulimit. При этом настройки системы можно вообще не трогать - ни киллер, ни своп ни оверкоммит.

slovazap ★★★★★
()

Стандартные аллокаторы не имеет доступа к памяти, поэтому они не имеют понятия когда память закончилась, и следственно не могут вернуть ошибку.

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

Рекомендую последовать советам использовать:

  1. ulimit
  2. setrlimit
cvv ★★★★★
()

Обработку пользовательской нагрузки уноси в контейнер в котором память зарезана с помощью cgroups. С основным процессом связывайся по пайпу. В случае ошибки у тебя будет падать приложение в контейнере, это можно ловить и отправлять пользователю сообщение об ошибку.

Reset ★★★★★
()

Господи, как же у меня горит пердак с того факта, что в 2023 ОС до сих пор не умеет обрабатывать OOM:
Когда линь перестанет виснуть при исчерпании памяти? (2022)
НЕ УМЕЕТ, да. Дело в том, что во-первых порядка 10% должны быть всегда зарезервированы под кэш (иначе система встанет колом на постоянном доступе к диску), а во-вторых несколько процентов памяти всегда должны быть зарезервированы на ядро (ряд функций не может забирать память у кэша).

Сам я следуя советам из треда на десктопе пользуюсь earlyoom, которая по крайней мере для моих задач (медленно жиреющий процесс IDE/браузера/VM) компенсирует отсутствие адекватных механизмов обработки OOM.

Да, одному-двум конейтерам можно поставить суммарный лимит 85%, но как это сделать для заранее неизвестного набора задач ­— понятия не имею.

byko3y ★★★★
()
Ответ на: комментарий от blex

Разве либы станут использовать этот аллокатор? Какая-нибудь функция вроде printf() возмёт при старте себе память, не проинициализирует её и будет работать. А потом при обработке большого сообщения захочет свою память, а свободных страниц и нету...

Уж лучше писать патч в ядро, чтобы отключать overcommit для отдельных приложений.

mky ★★★★★
()