множество улучшений

This commit is contained in:
Alexey Avramov 2018-06-11 04:52:39 +09:00
parent 2aa4f5c7b5
commit 27d22d41e4
4 changed files with 384 additions and 220 deletions

View File

@ -47,24 +47,21 @@ https://2ch.hk/s/res/2310304.html#2311483, https://archive.li/idixk
- по умолчанию высокий приоритет процесса `nice -20`, может регулироваться через конфиг - по умолчанию высокий приоритет процесса `nice -20`, может регулироваться через конфиг
- предотвращение самоубийства с помощью `self_oom_score_adj = -1000` - предотвращение самоубийства с помощью `self_oom_score_adj = -1000`
- возможность задания `oom_score_min` для предотвращения убийства невиновных - возможность задания `oom_score_min` для предотвращения убийства невиновных
- опциональность печати результатов проверки памяти
- `min_delay_after_sigkill` для предотвращения массовых убийств - `min_delay_after_sigkill` для предотвращения массовых убийств
- наличие `man` страницы - наличие `man` страницы
- наличие установщика для пользователей `systemd` - наличие установщика для пользователей `systemd`
- протестировано на `Debian 9 x86_64`, `Debian 8 i386`, `Fedora 28 x86_64` - протестировано на `Debian 9 x86_64`, `Debian 8 i386`, `Fedora 28 x86_64`
- пример вывода с отчетом об успешной отпраке сигнала: - пример вывода с отчетом об успешной отпраке сигнала:
``` ```
MemAvail: 0M 0.0%, SwapFree: 985M 8.4%, MemUsedZram: 625M 10.6% MemAvail: 0M 0.0%, SwapFree: 706M 6.0%, MemUsedZram: 357M 6.1%
MemAvail: 0M 0.0%, SwapFree: 962M 8.2%, MemUsedZram: 626M 10.6% MemAvail: 0M 0.0%, SwapFree: 411M 3.5%, MemUsedZram: 362M 6.2%
MemAvail: 9M 0.1%, SwapFree: 939M 8.0%, MemUsedZram: 626M 10.7% + MemAvail (0M, 0.0%) < mem_min_sigterm (235M, 4.0%)
MemAvailable 9M < 353M and SwapFree 939M < 940M SwapFree (411M, 3.5%) < swap_min_sigterm (470M, 4.0%)
Try to send signal 15 to process python3, Pid 3392, oom_score 818 Try to send signal 15 to python3, Pid 3930, oom_score 903
Success Success
MemAvail: 29M 0.5%, SwapFree: 2866M 24.4%, MemUsedZram: 582M 9.9% MemAvail: 107M 1.8%, SwapFree: 3461M 29.5%, MemUsedZram: 311M 5.3%
MemAvail: 77M 1.3%, SwapFree: 5037M 42.9%, MemUsedZram: 532M 9.1% MemAvail: 5159M 87.8%, SwapFree: 11311M 96.3%, MemUsedZram: 186M 3.2%
MemAvail: 168M 2.9%, SwapFree: 8956M 76.2%, MemUsedZram: 441M 7.5%
MemAvail: 5006M 85.2%, SwapFree: 10632M 90.5%, MemUsedZram: 356M 6.1%
MemAvail: 5000M 85.1%, SwapFree: 10633M 90.5%, MemUsedZram: 356M 6.1%
``` ```
### Установка и удаление для пользователей systemd ### Установка и удаление для пользователей systemd
@ -91,8 +88,7 @@ sudo ./uninstall.sh
``` ```
/etc/nohang/nohang.conf /etc/nohang/nohang.conf
``` ```
К опциям прилагается описание. Отредактируйте значения параметров в соответствии с вашими предпочтениями. К опциям прилагается описание. Отредактируйте значения параметров в соответствии с вашими предпочтениями и перезапустите сервис командой `sudo systemctl restart nohang`.
### Известные баги ### Известные баги
Известных нет, если найдете - пишите в [Issues](https://github.com/hakavlad/nohang/issues). В рабочем алгоритме известных нет, если найдете - пишите в [Issues](https://github.com/hakavlad/nohang/issues).

483
nohang
View File

@ -8,40 +8,297 @@ from operator import itemgetter
from time import sleep from time import sleep
from argparse import ArgumentParser from argparse import ArgumentParser
# найден экспериментально, требует уточнения с разными ядрами и архитектурами
zram_disksize_factor = 0.0042
# где искать конфиг, если не указан через --config
default_configs = ('./nohang.conf', '/etc/nohang/nohang.conf')
err_mess = '\nSet up path to the valid config file with -c/--config CONFIG option!\nexit'
# парсинг аргументов командной строки
parser = ArgumentParser() parser = ArgumentParser()
parser.add_argument( parser.add_argument(
'-c', '-c',
'--config', '--config',
help='path to config file, default values: ./nohang.conf, /etc/nohang/nohang.conf', help='path to the config file, default values: ./nohang.conf, /etc/nohang/nohang.conf',
default=None, default=None,
type=str type=str
) )
arg_config = parser.parse_args().config arg_config = parser.parse_args().config
# ветвление требует переработки и лучшей обработки исключений
if arg_config != None: if arg_config is None:
if os.path.exists:
config = arg_config # print('конфиг не задан через опцию -с/--config, берем его из дефолтных путей')
else: del arg_config
print('Указанный конфиг файл {} не существует!'.format(arg_config))
exit() config = None
elif os.path.exists('./nohang.conf'): for i in default_configs:
config = './nohang.conf' if os.path.exists(i):
elif os.path.exists('/etc/nohang/nohang.conf'): config = i
config = '/etc/nohang/nohang.conf' break
else: if config is None:
print('Пожалуйста, укажите путь к конфигу опцией -c или --config') print('По дефолтным путям конфиг не найден', err_mess)
exit() exit()
# найден экспериментально, требует уточнения с разными ядрами и архитектурами else:
zram_disksize_factor = 0.0042
# print('через опцию задан путь к конфигу {}'.format(arg_config))
if os.path.exists(arg_config):
config = arg_config
else:
print('нет файла по указанному пути: {}'.format(arg_config), err_mess)
exit()
print('path to config:', config)
try:
with open(config) as f:
config_dict = dict()
for line in f:
a = line.startswith('#')
b = line.startswith('\n')
c = line.startswith('\t')
d = line.startswith(' ')
if not a and not b and not c and not d:
a = line.split('=')
config_dict[a[0].strip()] = a[1].strip()
except PermissionError:
print('PermissionError', err_mess)
exit()
except UnicodeDecodeError:
print('UnicodeDecodeError', err_mess)
exit()
except IsADirectoryError:
print('IsADirectoryError', err_mess)
exit()
except IndexError:
print('IndexError', err_mess)
exit()
if 'print_mem_check_results' in config_dict:
print_mem_check_results = config_dict['print_mem_check_results']
if print_mem_check_results == 'True':
print_mem_check_results = True
elif print_mem_check_results == 'False':
print_mem_check_results = False
else:
print(
'invalid mlockall value {} (should be True or False), exit!'.format(
print_mem_check_results
)
)
exit()
print('print_mem_check_results: {}'.format(print_mem_check_results))
else:
print('print_mem_check_results not in config, exit!')
exit()
if 'mlockall' in config_dict:
mlockall = config_dict['mlockall']
if mlockall == 'True':
mlockall = True
elif mlockall == 'False':
mlockall = False
else:
print(
'invalid mlockall value {} (should be True or False), exit!'.format(
mlockall
)
)
exit()
print('mlockall: {}'.format(mlockall))
else:
print('mlockall not in config, exit!')
exit()
if 'self_nice' in config_dict:
self_nice = int(config_dict['self_nice'])
print('self_nice: {}'.format(self_nice))
else:
print('self_nice not in config, exit!')
exit()
if 'self_oom_score_adj' in config_dict:
self_oom_score_adj = int(config_dict['self_oom_score_adj'])
print('self_oom_score_adj: {}'.format(self_oom_score_adj))
else:
print('self_oom_score_adj not in config, exit!')
exit()
if 'rate_mem' in config_dict:
rate_mem = float(config_dict['rate_mem'])
if rate_mem <= 0:
print('rate_mem должен быть положительным')
exit()
print('rate_mem: {}'.format(rate_mem))
else:
print('rate_mem not in config, exit!')
exit()
if 'rate_swap' in config_dict:
rate_swap = float(config_dict['rate_swap'])
if rate_swap <= 0:
print('rate_swap должен быть положительным')
exit()
print('rate_swap: {}'.format(rate_swap))
else:
print('rate_swap not in config, exit!')
exit()
if 'rate_zram' in config_dict:
rate_zram = float(config_dict['rate_zram'])
if rate_zram <= 0:
print('rate_zram должен быть положительным')
exit()
print('rate_zram: {}'.format(rate_zram))
else:
print('rate_zram not in config, exit!')
exit()
if 'mem_min_sigterm' in config_dict:
mem_min_sigterm = config_dict['mem_min_sigterm']
print('mem_min_sigterm: {}'.format(mem_min_sigterm))
else:
print('mem_min_sigterm not in config, exit!')
exit()
if 'mem_min_sigkill' in config_dict:
mem_min_sigkill = config_dict['mem_min_sigkill']
print('mem_min_sigkill: {}'.format(mem_min_sigkill))
else:
print('mem_min_sigkill not in config, exit!')
exit()
if 'swap_min_sigterm' in config_dict:
swap_min_sigterm = config_dict['swap_min_sigterm']
print('swap_min_sigterm: {}'.format(swap_min_sigterm))
else:
print('swap_min_sigterm not in config, exit!')
exit()
if 'swap_min_sigkill' in config_dict:
swap_min_sigkill = config_dict['swap_min_sigkill']
print('swap_min_sigkill: {}'.format(swap_min_sigkill))
else:
print('swap_min_sigkill not in config, exit!')
exit()
if 'zram_max_sigterm' in config_dict:
zram_max_sigterm = config_dict['zram_max_sigterm']
print('zram_max_sigterm: {}'.format(zram_max_sigterm))
else:
print('zram_max_sigterm not in config, exit!')
exit()
if 'zram_max_sigkill' in config_dict:
zram_max_sigkill = config_dict['zram_max_sigkill']
print('zram_max_sigkill: {}'.format(zram_max_sigkill))
else:
print('zram_max_sigkill not in config, exit!')
exit()
if 'min_delay_after_sigterm' in config_dict:
min_delay_after_sigterm = float(config_dict['min_delay_after_sigterm'])
print('min_delay_after_sigterm: {}'.format(min_delay_after_sigterm))
else:
print('min_delay_after_sigterm not in config, exit!')
exit()
if 'min_delay_after_sigkill' in config_dict:
min_delay_after_sigkill = float(config_dict['min_delay_after_sigkill'])
print('min_delay_after_sigkill: {}'.format(min_delay_after_sigkill))
else:
print('min_delay_after_sigkill not in config, exit!')
exit()
if 'oom_score_min' in config_dict:
oom_score_min = int(config_dict['oom_score_min'])
print('oom_score_min: {}'.format(oom_score_min))
else:
print('oom_score_min not in config, exit!')
exit()
if 'decrease_oom_score_adj_enable' in config_dict:
decrease_oom_score_adj_enable = config_dict['decrease_oom_score_adj_enable']
if decrease_oom_score_adj_enable == 'True':
decrease_oom_score_adj_enable = True
elif decrease_oom_score_adj_enable == 'False':
decrease_oom_score_adj_enable = False
else:
print(
'invalid mlockall value {} (should be True or False), exit!'.format(
decrease_oom_score_adj_enable
)
)
exit()
print('decrease_oom_score_adj_enable: {}'.format(decrease_oom_score_adj_enable))
else:
print('decrease_oom_score_adj_enable not in config, exit!')
exit()
if 'oom_score_adj_before' in config_dict:
oom_score_adj_before = int(config_dict['oom_score_adj_before'])
print('oom_score_adj_before: {}'.format(oom_score_adj_before))
else:
print('oom_score_adj_before not in config, exit!')
exit()
if 'oom_score_adj_after' in config_dict:
oom_score_adj_after = config_dict['oom_score_adj_after']
print('oom_score_adj_after: {}'.format(oom_score_adj_after))
else:
print('oom_score_adj_after not in config, exit!')
exit()
########################################################################################### ###########################################################################################
def decrease_oom_score_adj(oom_score_adj_before, oom_score_adj_after): def decrease_oom_score_adj(oom_score_adj_before, oom_score_adj_after):
#print('Decrease oom_score_adj...') #print('Decrease oom_score_adj...')
# цикл для наполнения oom_list # цикл для наполнения oom_list
@ -72,30 +329,14 @@ def rline1(path):
def write(path, string): def write(path, string):
with open(path, 'w') as f: with open(path, 'w') as f:
f.write(string) f.write(string)
# дикриз не от рута
# возвращает словарь с параметрами из конфига def percent(n):
def config_parser(config): return round(n * 100, 1)
if os.path.exists(config):
try:
with open(config) as f:
name_value_dict = dict()
for line in f:
a = line.startswith('#')
b = line.startswith('\n')
c = line.startswith('\t')
d = line.startswith(' ')
if not a and not b and not c and not d:
a = line.split('=')
name_value_dict[a[0].strip()] = a[1].strip()
return name_value_dict
except PermissionError:
return 2
else:
return 1
def to_percent(num): def just_percent(num):
return str(round(num * 100, 1)).rjust(5, ' ') return str(round(num * 100, 1)).rjust(5, ' ')
@ -163,7 +404,7 @@ def find_victim_and_send_signal(signal):
name = pid_to_name(pid) name = pid_to_name(pid)
print( print(
'Try to send signal {} to process {}, Pid {}, oom_score {}'.format( ' Try to send signal {} to {}, Pid {}, oom_score {}'.format(
signal, name, pid, oom_score signal, name, pid, oom_score
) )
) )
@ -206,105 +447,21 @@ mem_total = int(mem_list[0].split(':')[1].split(' ')[-2])
config_dict = config_parser(config)
if config_dict is 1:
print('config {} does not exists'.format(config))
elif config_dict is 2:
print('cannot read config {}, permission error'.format(config))
else:
print('config: {}\n'.format(config))
if 'mlockall' in config_dict:
mlockall = config_dict['mlockall']
if mlockall == 'True':
mlockall = True
print('mlockall: {}'.format(mlockall))
if 'self_nice' in config_dict:
self_nice = int(config_dict['self_nice'])
print('self_nice: {}'.format(self_nice))
if 'self_oom_score_adj' in config_dict:
self_oom_score_adj = int(config_dict['self_oom_score_adj'])
print('self_oom_score_adj: {}'.format(self_oom_score_adj))
if 'rate_mem' in config_dict:
rate_mem = float(config_dict['rate_mem'])
print('rate_mem: {}'.format(rate_mem))
if 'rate_swap' in config_dict:
rate_swap = float(config_dict['rate_swap'])
print('rate_swap: {}'.format(rate_swap))
if 'rate_zram' in config_dict:
rate_zram = float(config_dict['rate_zram'])
print('rate_zram: {}'.format(rate_zram))
if 'mem_min_sigterm' in config_dict:
mem_min_sigterm = config_dict['mem_min_sigterm']
print('mem_min_sigterm: {}'.format(mem_min_sigterm))
if 'mem_min_sigkill' in config_dict:
mem_min_sigkill = config_dict['mem_min_sigkill']
print('mem_min_sigkill: {}'.format(mem_min_sigkill))
if 'swap_min_sigterm' in config_dict:
swap_min_sigterm = config_dict['swap_min_sigterm']
print('swap_min_sigterm: {}'.format(swap_min_sigterm))
if 'swap_min_sigkill' in config_dict:
swap_min_sigkill = config_dict['swap_min_sigkill']
print('swap_min_sigkill: {}'.format(swap_min_sigkill))
if 'zram_max_sigterm' in config_dict:
zram_max_sigterm = config_dict['zram_max_sigterm']
print('zram_max_sigterm: {}'.format(zram_max_sigterm))
if 'zram_max_sigkill' in config_dict:
zram_max_sigkill = config_dict['zram_max_sigkill']
print('zram_max_sigkill: {}'.format(zram_max_sigkill))
if 'min_delay_after_sigterm' in config_dict:
min_delay_after_sigterm = float(config_dict['min_delay_after_sigterm'])
print('min_delay_after_sigterm: {}'.format(min_delay_after_sigterm))
if 'min_delay_after_sigkill' in config_dict:
min_delay_after_sigkill = float(config_dict['min_delay_after_sigkill'])
print('min_delay_after_sigkill: {}'.format(min_delay_after_sigkill))
if 'oom_score_min' in config_dict:
oom_score_min = int(config_dict['oom_score_min'])
print('oom_score_min: {}'.format(oom_score_min))
if 'decrease_oom_score_adj_enable' in config_dict:
decrease_oom_score_adj_enable = config_dict['decrease_oom_score_adj_enable']
if decrease_oom_score_adj_enable == 'True':
decrease_oom_score_adj_enable = True
print('decrease_oom_score_adj_enable: {}'.format(decrease_oom_score_adj_enable))
if 'oom_score_adj_before' in config_dict:
oom_score_adj_before = int(config_dict['oom_score_adj_before'])
print('oom_score_adj_before: {}'.format(oom_score_adj_before))
if 'oom_score_adj_after' in config_dict:
oom_score_adj_after = config_dict['oom_score_adj_after']
print('oom_score_adj_after: {}'.format(oom_score_adj_after))
def sig_level_to_kb(string): def sig_level_to_kb(string):
if string.endswith('%'): if string.endswith('%'):
return float(string[:-1].strip()) / 100 * mem_total return float(string[:-1].strip()) / 100 * mem_total
if string.endswith('K'): elif string.endswith('K'):
return float(string[:-1].strip()) return float(string[:-1].strip())
if string.endswith('M'): elif string.endswith('M'):
return float(string[:-1].strip()) * 1024 return float(string[:-1].strip()) * 1024
if string.endswith('G'): elif string.endswith('G'):
return float(string[:-1].strip()) * 1048576 return float(string[:-1].strip()) * 1048576
else:
print('Конфиг инвалид, где-то неверно указаны единицы измерения')
exit()
mem_min_sigterm_kb = sig_level_to_kb(mem_min_sigterm) mem_min_sigterm_kb = sig_level_to_kb(mem_min_sigterm)
mem_min_sigkill_kb = sig_level_to_kb(mem_min_sigkill) mem_min_sigkill_kb = sig_level_to_kb(mem_min_sigkill)
@ -313,7 +470,6 @@ zram_max_sigkill_kb = sig_level_to_kb(zram_max_sigkill)
# возвращает число килобайт при задании в конфиге абсолютного значения, # возвращает число килобайт при задании в конфиге абсолютного значения,
# или кортеж с числом процентов # или кортеж с числом процентов
def sig_level_to_kb_swap(string): def sig_level_to_kb_swap(string):
@ -321,12 +477,16 @@ def sig_level_to_kb_swap(string):
if string.endswith('%'): if string.endswith('%'):
return float(string[:-1].strip()), True return float(string[:-1].strip()), True
if string.endswith('K'): elif string.endswith('K'):
return float(string[:-1].strip()) return float(string[:-1].strip())
if string.endswith('M'): elif string.endswith('M'):
return float(string[:-1].strip()) * 1024 return float(string[:-1].strip()) * 1024
if string.endswith('G'): elif string.endswith('G'):
return float(string[:-1].strip()) * 1048576 return float(string[:-1].strip()) * 1048576
else:
print('Конфиг инвалид, где-то неверно указаны единицы измерения')
exit()
# получаем число килобайт или кортеж с процентами # получаем число килобайт или кортеж с процентами
swap_min_sigterm_swap = sig_level_to_kb_swap(swap_min_sigterm) swap_min_sigterm_swap = sig_level_to_kb_swap(swap_min_sigterm)
@ -400,7 +560,10 @@ def kib_to_mib(num):
########################################################################################### ###########################################################################################
print()
print('Start monitoring...')
# рабочий цикл # рабочий цикл
while True: while True:
@ -457,27 +620,44 @@ while True:
t = t_mem_zram t = t_mem_zram
# печать состояния памяти if print_mem_check_results:
print( print(
'MemAvail: {}M {}%, SwapFree: {}M {}%, MemUsedZram: {}M {}%'.format( 'MemAvail: {}M {}%, SwapFree: {}M {}%, MemUsedZram: {}M {}%'.format(
human(mem_available), human(mem_available),
to_percent(mem_available / mem_total), just_percent(mem_available / mem_total),
human(swap_free), human(swap_free),
to_percent(swap_free / (swap_total + 0.0001)), just_percent(swap_free / (swap_total + 0.0001)),
human(mem_used_zram), human(mem_used_zram),
to_percent(mem_used_zram / mem_total) just_percent(mem_used_zram / mem_total)
) )
) )
if swap_total > swap_min_sigkill_kb:
swap_sigkill_pc = percent(swap_min_sigkill_kb / (swap_total + 1))
else:
swap_sigkill_pc = '-'
if swap_total > swap_min_sigterm_kb:
swap_sigterm_pc = percent(swap_min_sigterm_kb / (swap_total + 1))
else:
swap_sigterm_pc = '-'
# MEM SWAP KILL # MEM SWAP KILL
if mem_available <= mem_min_sigkill_kb and swap_free <= swap_min_sigkill_kb: if mem_available <= mem_min_sigkill_kb and swap_free <= swap_min_sigkill_kb:
print( print(
'MemAvailable {}M < {}M and SwapFree {}M < {}M'.format( '+ MemAvail ({}M, {}%) < mem_min_sigkill ({}M, {}%)\n SwapFree' \
' ({}M, {}%) < swap_min_sigkill ({}M, {}%)'.format(
kib_to_mib(mem_available), kib_to_mib(mem_available),
percent(mem_available / mem_total),
kib_to_mib(mem_min_sigkill_kb), kib_to_mib(mem_min_sigkill_kb),
percent(mem_min_sigkill_kb / mem_total),
kib_to_mib(swap_free), kib_to_mib(swap_free),
kib_to_mib(swap_min_sigkill_kb) percent(swap_free / (swap_total + 0.0001)),
kib_to_mib(swap_min_sigkill_kb),
swap_sigkill_pc
) )
) )
find_victim_and_send_signal(9) find_victim_and_send_signal(9)
@ -487,9 +667,11 @@ while True:
# MEM ZRAM KILL # MEM ZRAM KILL
if mem_used_zram >= zram_max_sigkill_kb: if mem_used_zram >= zram_max_sigkill_kb:
print( print(
'MemUsedZram {}M > {}M'.format( '+ MemUsedZram ({}M, {}%) > zram_max_sigkill ({}M, {}%)'.format(
kib_to_mib(mem_used_zram), kib_to_mib(mem_used_zram),
kib_to_mib(zram_max_sigkill_kb) percent(mem_used_zram / mem_total),
kib_to_mib(zram_max_sigkill_kb),
percent(zram_max_sigkill_kb / mem_total)
) )
) )
find_victim_and_send_signal(9) find_victim_and_send_signal(9)
@ -499,11 +681,16 @@ while True:
# MEM SWAP TERM # MEM SWAP TERM
if mem_available <= mem_min_sigterm_kb and swap_free <= swap_min_sigterm_kb: if mem_available <= mem_min_sigterm_kb and swap_free <= swap_min_sigterm_kb:
print( print(
'MemAvailable {}M < {}M and SwapFree {}M < {}M'.format( '+ MemAvail ({}M, {}%) < mem_min_sigterm ({}M, {}%)\n SwapFree' \
' ({}M, {}%) < swap_min_sigterm ({}M, {}%)'.format(
kib_to_mib(mem_available), kib_to_mib(mem_available),
percent(mem_available / mem_total),
kib_to_mib(mem_min_sigterm_kb), kib_to_mib(mem_min_sigterm_kb),
percent(mem_min_sigterm_kb / mem_total),
kib_to_mib(swap_free), kib_to_mib(swap_free),
kib_to_mib(swap_min_sigterm_kb) percent(swap_free / (swap_total + 0.0001)),
kib_to_mib(swap_min_sigterm_kb),
swap_sigterm_pc
) )
) )
find_victim_and_send_signal(15) find_victim_and_send_signal(15)
@ -512,9 +699,11 @@ while True:
# MEM ZRAM TERM # MEM ZRAM TERM
if mem_used_zram >= zram_max_sigterm_kb: if mem_used_zram >= zram_max_sigterm_kb:
print( print(
'MemUsedZram {}M > {}M'.format( '+ MemUsedZram ({}M, {}%) > zram_max_sigterm ({}M, {}%)'.format(
kib_to_mib(mem_used_zram), kib_to_mib(mem_used_zram),
kib_to_mib(zram_max_sigterm_kb) percent(mem_used_zram / mem_total),
kib_to_mib(zram_max_sigterm_kb),
percent(zram_max_sigterm_kb / mem_total)
) )
) )
find_victim_and_send_signal(15) find_victim_and_send_signal(15)

View File

@ -13,7 +13,7 @@ Nohang - аналог earlyoom с поддержкой zram и SIGTERM. При
.TP .TP
.BI \-c " CONFIG", .BI \-c " CONFIG",
.BI \-\-config " CONFIG" .BI \-\-config " CONFIG"
path to config file, default values: path to the config file, default values:
.I ./nohang.conf, .I ./nohang.conf,
.I /etc/nohang/nohang.conf .I /etc/nohang/nohang.conf
.TP .TP

View File

@ -7,12 +7,18 @@
и табуляций. Инлайновые комментарии запрещены. Пробелы допустиы и табуляций. Инлайновые комментарии запрещены. Пробелы допустиы
внутри строк в любом количестве. внутри строк в любом количестве.
В конце конфига перечислены значения по умолчанию. #####################################################################
Печатать ли результаты измерения доступной памяти.
Допустимые значения: True и False
print_mem_check_results = True
##################################################################### #####################################################################
True - заблокировать процесс в памяти для запрета его своппинга. True - заблокировать процесс в памяти для запрета его своппинга.
False - не блокировать. Значения чувствительны к регистру! False - не блокировать. Значения чувствительны к регистру!
Требует рут прав.
mlockall = True mlockall = True
@ -20,6 +26,7 @@ mlockall = True
Повысить приоритет процесса, установив niceness -20 Повысить приоритет процесса, установив niceness -20
Допустимые значения - целые числа из диапазона [-20; 19] Допустимые значения - целые числа из диапазона [-20; 19]
Требует рут прав.
self_nice = -20 self_nice = -20
@ -28,6 +35,7 @@ self_nice = -20
Задать oom_score_adj для процесса. Задать oom_score_adj для процесса.
Задание значения -1000 запретит самоубийство. Задание значения -1000 запретит самоубийство.
Допустимые значения - целые числа из диапазона [-1000; 1000] Допустимые значения - целые числа из диапазона [-1000; 1000]
Требует рут прав.
self_oom_score_adj = -1000 self_oom_score_adj = -1000
@ -38,8 +46,8 @@ self_oom_score_adj = -1000
Уменьшение коэффициентов способно снизить нагрузку на Уменьшение коэффициентов способно снизить нагрузку на
прцессор и увеличить периоды между проверками памяти. прцессор и увеличить периоды между проверками памяти.
Почему три коэффициента, а не один? - Потому что Почему три коэффициента, а не один? - Потому что скорость
скорость наполнения свопа обычно ниже скорости наполнения RAM. наполнения свопа обычно ниже скорости наполнения RAM.
Можно для свопа задать более низкую интенсивность Можно для свопа задать более низкую интенсивность
мониторинга без ущерба для предотвращения нехватки памяти мониторинга без ущерба для предотвращения нехватки памяти
и тем самым снизить нагрузку на процессор. и тем самым снизить нагрузку на процессор.
@ -49,7 +57,7 @@ self_oom_score_adj = -1000
памяти. памяти.
rate_mem = 6 rate_mem = 6
rate_swap = 2 rate_swap = 0.2
rate_zram = 1 rate_zram = 1
##################################################################### #####################################################################
@ -67,10 +75,11 @@ rate_zram = 1
mem_min_sigterm = 0.5 G mem_min_sigterm = 0.5 G
swap_min_sigkill = 200 M swap_min_sigkill = 200 M
mem_min_sigterm = 6 % mem_min_sigterm = 4%
mem_min_sigkill = 3 % mem_min_sigkill = 2%
swap_min_sigterm = 8 %
swap_min_sigkill = 4 % swap_min_sigterm = 4%
swap_min_sigkill = 2%
Задание общей доли zram в памяти, при превышении которой Задание общей доли zram в памяти, при превышении которой
происходит отправка соответствующих сигналов. происходит отправка соответствующих сигналов.
@ -91,7 +100,7 @@ zram_max_sigkill = 65 %
пойдет не так. пойдет не так.
Значение должно быть целым числом из диапазона [0; 1000] Значение должно быть целым числом из диапазона [0; 1000]
oom_score_min = 10 oom_score_min = 15
##################################################################### #####################################################################
@ -115,40 +124,10 @@ min_delay_after_sigkill = 3
False - не изменять oom_score_adj процессов перед поиском False - не изменять oom_score_adj процессов перед поиском
жертвы. Значения чувствительны к регистру! жертвы. Значения чувствительны к регистру!
decrease_oom_score_adj_enable = False Требует рут прав.
decrease_oom_score_adj_enable = True
oom_score_adj_before = 50 oom_score_adj_before = 50
oom_score_adj_after = 10 oom_score_adj_after = 10
#####################################################################
#####################################################################
#####################################################################
#####################################################################
#####################################################################
Значения по умолчанию
mlockall = True
self_nice = -20
self_oom_score_adj = -1000
rate_mem = 6
rate_swap = 2
rate_zram = 1
mem_min_sigterm = 6 %
mem_min_sigkill = 3 %
swap_min_sigterm = 8 %
swap_min_sigkill = 4 %
zram_max_sigterm = 60 %
zram_max_sigkill = 65 %
oom_score_min = 10
min_delay_after_sigterm = 0.1
min_delay_after_sigkill = 3
decrease_oom_score_adj_enable = False
oom_score_adj_before = 50
oom_score_adj_after = 10