LINUX.ORG.RU

Ограничение максимальной доступной памяти процессом

 , ,


0

2

Всем привет.

Девопсы настраивают OOM killer, чтобы процессы в контейнере не потребляли памяти больше заданного порога. Софт в контейнере - некоторая самопальная СУБД, которая все данные хранит в памяти. Если пользователь загружает данных в СУБД больше порога, OOM killer благополучно убивает процесс, и девопсы бегут к разработчикам разбираться, почему сервер в очередной раз упал :-)

В общем, чтобы девопсы отвалили, хочу в сервер добавить параметр максимального потребления ОЗУ, чтобы он знал что нельзя выделять памяти больше, чем стоит в ограничении.

Понимаю, что можно заменить аллокатор в new/delete, и перед выделением данных в динамической памяти проверять этот порог, но может есть готовые решения? хотя бы для линукса, допустим в glibc может какая функция есть, которая в глобальную переменную в malloc порог запишет?

Или может быть в настройках процессов можно искусственно ограничить процесс, чтобы при привышении порога malloc возвращал nullptr?


Понимаю, что можно заменить аллокатор в new/delete

Я иногда заменяю malloc/free, ты не представляешь себе насколько нетривиальна эта задача… ну у тебя есть операционная система, попробуй покапать в сторону setrlimit

https://man7.org/linux/man-pages/man2/setrlimit.2.html

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

Да я представляю, что это не тривиальная задача, уже разбирался с этой темой. Поэтому и хочу для частной проблемы готовое решение, чтобы багов не добавить

sotlef ()

Понимаю, что можно заменить аллокатор в new/delete, и перед выделением данных в динамической памяти проверять этот порог, но может есть готовые решения? хотя бы для линукса, допустим в glibc может какая функция есть, которая в глобальную переменную в malloc порог запишет?

Или может быть в настройках процессов можно искусственно ограничить процесс, чтобы при привышении порога malloc возвращал nullptr?

Ничего из этого не будет работать лучше OOM killer. Вернуть nullptr может любой маллок, в том числе никак не связанный с пользователем, загрузившим много данных, а значит опять же упадёт весь сервер. Ну или процесс связанный совершенно другим пользователем. Только в отличие от OOM который прибивает всё и сразу, тут, в зависимости от того как написан сервер, и насколько корректно он обрабатывает nullptr из ВСЕХ маллоков, в т.ч. во внешних библиотеках, может случиться и что-то похуже падения, например зависание с жором ресурсов или повреждение данных.

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

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

В текущей проблеме все пользователи работают в одном процессе.

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

Если какой-то модуль обрабатывает nullptr некорректно, то тут только исправлять ошибки.

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

Это по-моему какое-то извращение, не?

sotlef ()
Ответ на: комментарий от sotlef

Это по-моему какое-то извращение, не?

Можно вообще без malloc (new) писать, и в ряде случаев это и есть правильный подход.

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

В текущей проблеме все пользователи работают в одном процессе.

Ну значит в любом случае будет падать весь процесс как я и сказал.

Если какой-то модуль обрабатывает nullptr некорректно, то тут только исправлять ошибки.

Да, но исправления ошибок это одно, а сделать так чтобы программа могла продолжиться после нехватки памяти - совсем другое дело. В общем случае это невозможно, но даже в частном возвращением 0 из malloc по порогу не обойтись.

Например, вернёте вы 0 и код у вас правильный, он обработает 0 и начнёт возвращать ошибку пользователю, выделит для этого память, получит опять 0, а дальше или падение или бесконечная рекурсия или падение. Значит как минимум нужен статический буфер для этой ошибки, а его нужно синхронизировать, а это медленно, значит нужно по буферу на пользователя, а их нужно выделять, а при этом может не хватить памяти - понятна идея?

В самом простом случае можно при нехватке памяти сразу бежать освобождать что-то наименее ненужное, гарантируя что в процессе освобождения не потребуется аллокаций (например, уменьшение размера вектора так чтобы освободилась память требует сначала выделить больше памяти). Вы могли бы, например, выкинуть данные самого жирного пользователя, или того кто запросил кусок на который не хватило памяти. Но без аккаунтинга вы не знаете ни того, ни другого.

Это по-моему какое-то извращение, не?

Шутите? Это единственное решение вашей проблемы, вполне очевидное.

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

Это по-моему какое-то извращение, не?

А по-моему это выглядит как самое некостыльное решение.

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

Или может быть в настройках процессов можно искусственно ограничить процесс, чтобы при привышении порога malloc возвращал nullptr?

Ничего из этого не будет работать лучше OOM killer.

4.2

Правильный ответ.

LamerOk ★★★★★ ()

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

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

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

девопсов логи научить читать

Это не их работа. Их работа - запустить софтину с помощью изоленты и такой-то матери. А всё остальное - к разрабам.

LamerOk ★★★★★ ()

Посмотри в сторону tcmalloc/jemalloc, скорее всего там такое можно настроить. Понятное дело, что корректная обработка нехватки памяти в приложении никуда не денется. Просто в этих либах как раз уже и есть работа с ограниченным пулом памяти.

faq2 ()
Ответ на: комментарий от faq2

Посмотри в сторону tcmalloc/jemalloc, скорее всего там такое можно настроить

А самому посмотреть, прежде чем давать советы другим, ты не хочешь?

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

И в чём именно есть отличие от malloc из GNU glibc?

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

There are three user accessible controls that we can use to performance tune TCMalloc:

The logical page size for TCMalloc (4KiB, 8KiB, 32KiB, 256KiB)

The per-thread or per-cpu cache sizes

The rate at which memory is released to the OS

this в общем, хотя и понятно (мне) с какими ограничениями и, что не панацея, да.

faq2 ()
Для того чтобы оставить комментарий войдите или зарегистрируйтесь.