LINUX.ORG.RU

Лимиты на десктопе для предотвращения зависаний

 ,


2

6

Вопрос фанатам лимитов: как вы решите ситуацию, когда, например, на десктопе я пользуюсь прогами app1, app2, app3. И каждый раз они могут выжирать разное кол-во памяти. И могут запускаться сразу все. А могут по одной. При этом я хочу достичь полной утилизации памяти, при этом надежно предотвращать зависания.

praseodim aidaho WitcherGeralt intelfx

Однако меня интересует способ от сторонников лимитов.

@intelfx

Я не являюсь сторонником лимитов. (Я просто умею ими пользоваться.)

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

Ты бы ему ещё ссылку на его собственный https://github.com/hakavlad/nohang отправил.

:)

Понятно, что OOM-хендлеры. ТС — автор одного из них. Тема-то про другое.

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

Фанаты лимитов не решили проблему. О лимитах говорят, но гайдов хороших нет. На сервере проще, где потребление боле-менее предсказуемо. Как ставить лимиты на десктопе?

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

Ну смотри.

Видно два подхода.

Подход первый.

  • выбрать все критические программы (init, системные службы, графический сервер, композитор/WM/DE);
  • оценить сверху их потребление памяти (допустим, X байт);
  • пихнуть их в цгруппу A, задать там ограничение на X байт;
  • все остальные программы пихнуть в цгруппу B и задать на ней ограничение Total-(X+Padding).

Придётся ещё разобраться с page cache, я не помню, как себя ведут цгруппы применительно к нему — страницы в кэше приписываются цгруппе процесса, который вызвал их загрузку, или лежат отдельно. Если первое, то проще, если второе, то сложнее.

Подход второй. В cgroups v2 появилось «ограничение снизу» (MemoryLow= в systemd). Если оно делает то, что я думаю (исключает цгруппу из всяческого тротлинга, пока потребление памяти ниже ограничения снизу), то можно воспользоваться им: задать глобальное ограничение сверху в Total-Padding, а для всех критичных программ задать ограничение снизу.

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

Проблема в том, что ни один подход «как есть» в современном линуксовом десктопе не реализуется, просто потому что юзерские программы сейчас всегда лежат в одной цгруппе с графическим сервером/WM/DE. Максимум, что можно сделать в направлении этой проблемы без яростного применения напильника — это сделать так, чтобы пользовательской сессии нельзя было вытеснить инит с sshd и getty (или чтобы одному пользователю нельзя было вытеснить второго).

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

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

Кстати, ни memory.min, ни тем более memory.low не показали никакогот эффекта в моих опытах (в отличие от mlockall).

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

Фейсбук для своего киллера 64 метра снизу границу ставит. И утверждает, что эффект подобен mlockall:

We prefer to configure oomd with cgroup2's memory.min. It's more flexible and less complicated for the oomd code

Однако в моих опытах от лимитов снизу было ноль эффекта.

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

Установить earlyoom. Это даст 10% запас свободной памяти всегда.

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

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

Я разве с тобой спорю?

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

Установить earlyoom. Это даст 10% запас свободной памяти всегда.

Меня можно не тыкать носом в earlyoom. Мой ответ писался в контексте лимитов. Я отлично знаю и о том, и о другом, и о том, что лимиты в общем-то никак не подходят для юзкейсов, когда потребление памяти заранее не известно (вот сюрприз-то).

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

Я сторонник не лимитов, а здравого смысла. Не хватает оперативы — докинь её, течёт софтина — не юзай её. А твой кейс со здравым смыслом не дружит, для меня он выглядит как-то так. Если по какой-то причине тебе понадобилось вставить себе палку в колесо, надень шлем ручками выставь ulimit. Системно решать несуществующую проблему смысла не вижу, но решение с cgroups достаточно очевидное, следует вычесть из общего объёма оперативы 3-4гб под систему (чтобы с запасом, никакой «полной утилизации»), а всё остальное отдать группе в которой будут находиться запускаемые тобой приложения.

Для меня этой «проблемы» нет в принципе, у меня везде оперативы с большим запасом, а на случай её возникновения есть своп на SSD.

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

лимиты в общем-то никак не подходят для юзкейсов, когда потребление памяти заранее не известно

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

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

твой кейс со здравым смыслом не дружит

Мой кейс - это типичный десктопный кейс. Юзеры запускают разные проги с разным нестабильным потреблением памяти, иногда одновременно все, иногда по одному. Это просто обычный кейс из жизни, я его не за уши притянул. И это как раз то место, где юзерспейс справится наилучшим образом, в отличие от лимитов через сигруппы.

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

Справедливости ради, ограничение снизу (+ юзерспейсный демон с GUI, рисующий грозные окошки а-ля память в цгруппе кончилась, кого прибьём?) здесь вполне зашло бы.

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

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

Мы уже обсуждали, как.

Чтобы не повторяться, то intelfx пересказал суть моего конфига.
Только в cgroups нельзя «минимум» обозначить для группы.
Поэтому на старте системы из шаблона заполняется максимум для группы «всего остального».
Дальше «всё остальное» может там себе сношаться как хочет.

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

В GNOME 3.34 к этому очень существенно приблизились. Но — ещё нет.

intelfx ★★★★★ ()

$ uptime
20:39:56 up 24 days, 1:59, 1 user, load average: 0,26, 0,25, 0,37

с hibernate'ами и suspend'ами.

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

Ядерный ООМ работает если своп отключить, а юзерспейсным доверия нет, могут повалиться, например. Ненадежные.

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

Вполне возможно, что заработала, но он не понял, что она делает.
По итогам предыдущих тредов это было бы более вероятным объяснением.

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

Ну если она не делает то, что от неё ожидается в контексте сабжа — можно сказать, что и не работает.

intelfx ★★★★★ ()

Чёрт, а чего это ulimit по оперативе в линуксе не работает и даже ворнинги никакие не кидает? По диску же прекрасно работает. Что там ещё сломано?

WitcherGeralt ★★ ()

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

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

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

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

Театр абсурда, не иначе.

Как раз для этого случая есть ulatency/ulatencyd. Не «идеальное» решение, но определённый эффект есть (от юзера никаких действий при этом не производится).

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

ulatency/ulatencyd

Не работает с cgroup2, требует серьезной модернизации. Хотя идея хорошая.

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

А у меня работает. Только без свопа всё попадает, поэтому своп не отключаю — не охота данные терять..

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

Какой имено не помог? Оба отлично обрабатывают падение доступной памяти. Например, демо - https://youtu.be/ChTNu9m7uMU - доступая память восстанавливавется даже при быстром исчерпании, даже без свопа. А тут https://youtu.be/UCwZS5uNLu0 система не виснет без свопа при работе нескольких быстрых пожирателей памяти в цикле. Со свопом тем более отлично помогают.

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

Например, демо - https://youtu.be/ChTNu9m7uMU - доступая память восстанавливавется даже при быстром исчерпании, даже без свопа.

У меня система (Gentoo с ядром 5.х) без свопа не виснет, ну, то есть, примерно через минуту-две жручий софт прибивается. Зато проблема была со свопом, когда он заполнялся на 90% система висла намертво, с использованием свопа на SSD это стало терпимее — уже не виснет как раньше и по мере перемещения данных в своп, курсор перестает ползать по-черепашьи.

А тут https://youtu.be/UCwZS5uNLu0 система не виснет без свопа при работе нескольких быстрых пожирателей памяти в цикле. Со свопом тем более отлично помогают.

А что скрипт делает с пожирателями? Прибивает их даже при наличии свопа? А если это программа в которой я работаю и она потребляет всю память потому что надо?

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

Прибивает их даже при наличии свопа?

Если SwapFree будет меньше 10% SwapTotal. Этот порог предлагается по умолчанию и может быть изменен на любой другой, хоть на 0%, хоть на 100%.

А что скрипт делает с пожирателями?

Отправляет SIGTERM процесссу с наибольшим oom_score. При отсутствии реакции на SIGTERM отправляется SIGKILL.

А если это программа в которой я работаю и она потребляет всю память потому что надо?

Можете снизить вероятность ее убийства через конфиг, есть несколько видов модификаторов badness процессов, включая совпадение name, exe realpath, cwd, cmdlime, cgroup процесса с заданными регулярками. Например:

# KEY              badness_adj   separator       regexp

@BADNESS_ADJ_RE_REALPATH  -500     ///           ^/usr/bin/foo$

# или 

@BADNESS_ADJ_RE_NAME     -500       ///           ^foo$

- эквивалент установки oom_score_adj=-500 для всех процессов программы foo.

Помимо реакции на уровень свободного свопа и рамы доступно включение реакции на «memory pressure» PSI (новый ядерный детектор времени ожидания получения ресурсов).

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

Чёрт, а чего это ulimit по оперативе в линуксе не работает и даже ворнинги никакие не кидает? По диску же прекрасно работает.

    rss 
    maximum resident set size (KB) (Ignored in Linux 2.4.30 and higher) 

https://linux.die.net/man/5/limits.conf

ulimit может ограничивать только виртуальную память (с ключом -v, см https://ss64.com/bash/ulimit.html). Ограничение отдельных процессов по RSS не реализовано, можно только ограничить контрольную группу (cgroup) в целом через memory.max.

Что там ещё сломано?

Остальное всё работает.

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

Я то ли на старом ядре это делал однажды, то ли на фре, уже не помню. Был уверен, что работает. Мне только ulimit -f пригождался в последнее время.

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

Благо хоть докер в качестве высокоуровневого интерфейса в cgroups есть, но и то не очень удобно, если нужно будет просто какой-то текучий мусор запустить.

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

Вот что «нинужно», так это докер на десктопе.

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

hakavlad говорит, что эта крутилка у него не заработала…

Давайте об этом поговорим, может я чего не понимаю.

memory.min specifies a minimum amount of memory the cgroup must always retain, i.e., memory that can never be reclaimed by the system. If the cgroup’s memory usage reaches this low limit and can’t be increased, the system OOM killer will be invoked.

- https://facebookmicrosites.github.io/cgroup2/docs/memory-controller.html (фейсбуковцы - эксперты по сигруппам, например)

Смотрим далее:

memory.min

A read-write single value file which exists on non-root cgroups. The default is «0».

Hard memory protection. If the memory usage of a cgroup is within its effective min boundary, the cgroup's memory won't be reclaimed under any conditions. If there is no unprotected reclaimable memory available, OOM killer is invoked.

Effective min boundary is limited by memory.min values of

all ancestor cgroups. If there is memory.min overcommitment (child cgroup or cgroups are requiring more protected memory than parent will allow), then each child cgroup will get the part of parent's protection proportional to its actual memory usage below memory.min.

Putting more memory than generally available under this protection is discouraged and may lead to constant OOMs.

If a memory cgroup is not populated with processes, its memory.min is ignored.

https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html

Как это всё понимать? Я задавал своему демону разные значения memory.min, в том числе под 100% MemTotal, и это ни на что не влияло вообще. Как убедиться в работоспособности этой крутилки? Какие тесты можно запустить?

Я спрашивал в канале oomd - почему вы не применяете mlockall()? На что получил ответ:

We prefer to configure oomd with cgroup2's memory.min. It's more flexible and less complicated for the oomd code

Звучит так, будто выставление memoryy.min работает подобно mlockall. Однако практика показывает, что это не так. Например, без свопа демон ищет жертву 10 ms, а со свопом - 1000 ms. Если сделать mlockall, то со свопом поиск будет занимать практически те же 10 ms - демон заблокируется в оперативе, не уйдет в споп и будет действовать быстро как без свопа.

Однако выставление даже больших значений memory.min не помогает в ускорении поиска, если не запускать mlockall.

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

Это понимать, скорее всего, вот так:

Effective min boundary is limited by memory.min values of all ancestor cgroups

Ты выставлял ненулевое значение memory.min на всех родительских цгруппах?

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

Ты выставлял ненулевое значение memory.min на всех родительских цгруппах?

Нет. Да и фейсбук напрямую этого не требует, хотя просто рекомендует запускать oomd в отдельном слайсе:

oomd must be run in a protected cgroup. In other words, we use a specialized systemd service setup to guarantee oomd resources so that oomd can act in resource starved scenarios.

You typically group host critical services in their own special cgroup. Perhaps named hostcritical.slice. oomd should be grouped in here with other host critical services like sshd.service. hostcritical.slice should be guaranteed a minimum amount of reserved memory via memory.min. This essentially mlockalls oomd except the kernel sets aside the memory ahead of time. A portion of that memory - 64M should be enough - should be given to oomd.

- https://github.com/facebookincubator/oomd/blob/master/docs/production_setup.m...

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

Нафиг он нужен?

mount none /run/cg -t cgroup2
mkdir /run/cg/my
echo +memory >/run/cg/cgroup.subtree_control
echo 1500m   >/run/cg/my/memory.max

#include<cstdio>
#include<fcntl.h>
#include<unistd.h>
int main(){
char b[6];
write(open("/run/cg/my/cgroup.procs",O_WRONLY|O_CLOEXEC),b,
  snprintf(b,sizeof b,"%u",getpid()));
char const*const c[]{"/usr/lib/chromium/chromium",0};
execve(*c,(char*const*)c,environ);}
anonymous ()
Ответ на: комментарий от anonymous

Кстати, да, у меня по мотивам этого доклада пачка таких скриптов на Go и Python есть, но я их ни разу не юзал на практике, только когда экспериментировал.

WitcherGeralt ★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.