drop-out logging, blacklist and whitelist support, add realtime_ionice support
This commit is contained in:
parent
a96eeb8ad2
commit
b910bf1b28
32
README.md
32
README.md
@ -15,12 +15,12 @@ OOM killer doesn't prevent OOM conditions.
|
|||||||
|
|
||||||
### Some features
|
### Some features
|
||||||
|
|
||||||
- convenient configuration with a well commented config file (there are 38 parameters in the config)
|
- convenient configuration with a well commented config file (there are 35 parameters in the config)
|
||||||
- `SIGKILL` and `SIGTERM` as signals that can be sent to the victim
|
- `SIGKILL` and `SIGTERM` as signals that can be sent to the victim
|
||||||
- `zram` support (`mem_used_total` as a trigger)
|
- `zram` support (`mem_used_total` as a trigger)
|
||||||
- customizable intensity of monitoring
|
- customizable intensity of monitoring
|
||||||
- desktop notifications: results of preventings OOM and low memory warnings
|
- desktop notifications: results of preventings OOM and low memory warnings
|
||||||
- black, white, prefer, avoid lists via regex
|
- prefer and avoid lists via regex matching
|
||||||
- possibility of restarting processes via command like `systemctl restart something` if the process is selected as a victim
|
- possibility of restarting processes via command like `systemctl restart something` if the process is selected as a victim
|
||||||
- look at the [config](https://github.com/hakavlad/nohang/blob/master/nohang.conf) to find more
|
- look at the [config](https://github.com/hakavlad/nohang/blob/master/nohang.conf) to find more
|
||||||
|
|
||||||
@ -32,34 +32,11 @@ OOM killer doesn't prevent OOM conditions.
|
|||||||
### An example of output
|
### An example of output
|
||||||
|
|
||||||
```
|
```
|
||||||
MemAvail: 2976 M, 50.6 % | SwapFree: 10758 M, 100.0 %
|
|
||||||
MemAvail: 0 M, 0.0 % | SwapFree: 10281 M, 95.6 %
|
|
||||||
MemAvail: 0 M, 0.0 % | SwapFree: 9918 M, 92.2 %
|
|
||||||
MemAvail: 0 M, 0.0 % | SwapFree: 8659 M, 80.5 %
|
|
||||||
MemAvail: 0 M, 0.0 % | SwapFree: 7235 M, 67.3 %
|
|
||||||
MemAvail: 19 M, 0.3 % | SwapFree: 6851 M, 63.7 %
|
|
||||||
MemAvail: 0 M, 0.0 % | SwapFree: 5780 M, 53.7 %
|
|
||||||
MemAvail: 0 M, 0.0 % | SwapFree: 5008 M, 46.6 %
|
|
||||||
MemAvail: 0 M, 0.0 % | SwapFree: 4199 M, 39.0 %
|
|
||||||
MemAvail: 0 M, 0.0 % | SwapFree: 3502 M, 32.6 %
|
|
||||||
MemAvail: 0 M, 0.0 % | SwapFree: 2929 M, 27.2 %
|
|
||||||
MemAvail: 0 M, 0.0 % | SwapFree: 2446 M, 22.7 %
|
|
||||||
MemAvail: 0 M, 0.0 % | SwapFree: 2093 M, 19.5 %
|
|
||||||
MemAvail: 0 M, 0.0 % | SwapFree: 1573 M, 14.6 %
|
|
||||||
MemAvail: 0 M, 0.0 % | SwapFree: 1320 M, 12.3 %
|
|
||||||
MemAvail: 0 M, 0.0 % | SwapFree: 1117 M, 10.4 %
|
|
||||||
MemAvail: 0 M, 0.0 % | SwapFree: 943 M, 8.8 %
|
|
||||||
|
|
||||||
2018-07-06 Fri 03:04:37
|
|
||||||
MemAvailable (0 MiB, 0.0 %) < mem_min_sigterm (588 MiB, 10.0 %)
|
MemAvailable (0 MiB, 0.0 %) < mem_min_sigterm (588 MiB, 10.0 %)
|
||||||
SwapFree (943 MiB, 8.8 %) < swap_min_sigterm (1076 MiB, 10.0 %)
|
SwapFree (943 MiB, 8.8 %) < swap_min_sigterm (1076 MiB, 10.0 %)
|
||||||
Preventing OOM: trying to send the SIGTERM signal to tail,
|
Preventing OOM: trying to send the SIGTERM signal to tail,
|
||||||
Pid: 14636, Badness: 777, VmRSS: 4446 MiB, VmSwap: 8510 MiB
|
Pid: 14636, Badness: 777, VmRSS: 4446 MiB, VmSwap: 8510 MiB
|
||||||
Success
|
Success
|
||||||
MemAvail: 173 M, 2.9 % | SwapFree: 3363 M, 31.3 %
|
|
||||||
MemAvail: 4700 M, 80.0 % | SwapFree: 8986 M, 83.5 %
|
|
||||||
MemAvail: 4668 M, 79.4 % | SwapFree: 8997 M, 83.6 %
|
|
||||||
MemAvail: 4610 M, 78.5 % | SwapFree: 9024 M, 83.9 %
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Requirements
|
### Requirements
|
||||||
@ -117,11 +94,10 @@ The program can be configured by editing the [config file](https://github.com/ha
|
|||||||
- PREVENTION OF KILLING INNOCENT VICTIMS
|
- PREVENTION OF KILLING INNOCENT VICTIMS
|
||||||
- AVOID AND PREFER VICTIM NAMES VIA REGEX
|
- AVOID AND PREFER VICTIM NAMES VIA REGEX
|
||||||
- EXECUTE THE COMMAND INSTEAD OF SENDING THE SIGTERM SIGNAL
|
- EXECUTE THE COMMAND INSTEAD OF SENDING THE SIGTERM SIGNAL
|
||||||
- DESKTOP NOTIFICATIONS
|
- GUI NOTIFICATIONS
|
||||||
- LOW MEMORY WARNINGS
|
- LOW MEMORY WARNINGS
|
||||||
- SELF-DEFENSE
|
- SELF-DEFENSE AND PREVENTING SLOWING DOWN THE PROGRAM
|
||||||
- OUTPUT VERBOSITY
|
- OUTPUT VERBOSITY
|
||||||
- LOGGING TO SEPARATE FILE
|
|
||||||
|
|
||||||
Just read the description of the parameters and edit the values. Run the command `sudo systemctl restart nohang` to apply changes. Default path to the config arter installing via `./install.sh` is `/etc/nohang/nohang.conf`.
|
Just read the description of the parameters and edit the values. Run the command `sudo systemctl restart nohang` to apply changes. Default path to the config arter installing via `./install.sh` is `/etc/nohang/nohang.conf`.
|
||||||
|
|
||||||
|
@ -15,12 +15,6 @@ cp nohang.1.gz /usr/local/share/man/man1/
|
|||||||
chmod 644 /usr/local/share/man/man1/nohang.1.gz
|
chmod 644 /usr/local/share/man/man1/nohang.1.gz
|
||||||
rm nohang.1.gz
|
rm nohang.1.gz
|
||||||
|
|
||||||
mkdir /var/log/nohang
|
|
||||||
chmod 750 /var/log/nohang
|
|
||||||
|
|
||||||
cp nohang.logrotate /etc/logrotate.d/nohang
|
|
||||||
chmod 644 /etc/logrotate.d/nohang
|
|
||||||
|
|
||||||
cp nohang.service /etc/systemd/system/
|
cp nohang.service /etc/systemd/system/
|
||||||
chmod 644 /etc/systemd/system/nohang.service
|
chmod 644 /etc/systemd/system/nohang.service
|
||||||
systemctl daemon-reload
|
systemctl daemon-reload
|
||||||
|
156
nohang
156
nohang
@ -5,8 +5,8 @@
|
|||||||
import os
|
import os
|
||||||
from operator import itemgetter
|
from operator import itemgetter
|
||||||
from time import sleep, time
|
from time import sleep, time
|
||||||
import datetime
|
|
||||||
from argparse import ArgumentParser
|
from argparse import ArgumentParser
|
||||||
|
from subprocess import Popen
|
||||||
|
|
||||||
sig_dict = {9: 'SIGKILL', 15: 'SIGTERM'}
|
sig_dict = {9: 'SIGKILL', 15: 'SIGTERM'}
|
||||||
|
|
||||||
@ -110,20 +110,6 @@ def write(path, string):
|
|||||||
f.write(string)
|
f.write(string)
|
||||||
|
|
||||||
|
|
||||||
def append_log(string):
|
|
||||||
try:
|
|
||||||
with open(logfile, 'a') as f:
|
|
||||||
f.write(string + '\n')
|
|
||||||
except PermissionError:
|
|
||||||
print(
|
|
||||||
' Cannot append log {}: PermissionError'.format(
|
|
||||||
logfile))
|
|
||||||
except IsADirectoryError:
|
|
||||||
print(
|
|
||||||
' Cannot append log {}: IsADirectoryError'.format(
|
|
||||||
logfile))
|
|
||||||
|
|
||||||
|
|
||||||
def kib_to_mib(num):
|
def kib_to_mib(num):
|
||||||
return round(num / 1024.0)
|
return round(num / 1024.0)
|
||||||
|
|
||||||
@ -228,25 +214,6 @@ def send_notify(signal, name, pid, oom_score, vm_rss, vm_swap):
|
|||||||
os.system(user_notify_command + info)
|
os.system(user_notify_command + info)
|
||||||
|
|
||||||
|
|
||||||
def send_notify_black(signal, name, pid):
|
|
||||||
# текст отправляемого уведомления
|
|
||||||
info = '"<u>Nohang</u> sent <u>{}</u>\nto blacklisted proce' \
|
|
||||||
'ss <b>{}</b>, <i>Pid</i> <b>{}</b>" &'.format(
|
|
||||||
sig_dict[signal], name, pid)
|
|
||||||
if root:
|
|
||||||
# отправляем уведомление всем залогиненным пользователям
|
|
||||||
for uid in os.listdir('/run/user'):
|
|
||||||
root_notify_command = 'sudo -u {} DISPLAY={} notify-send {} "Pr' \
|
|
||||||
'eventing OOM" '.format(
|
|
||||||
users_dict[uid], root_display, notify_options)
|
|
||||||
os.system(root_notify_command + info)
|
|
||||||
else:
|
|
||||||
# отправляем уведомление пользователю, который запустил nohang
|
|
||||||
user_notify_command = 'notify-send {} "Preventing OOM" '.format(
|
|
||||||
notify_options)
|
|
||||||
os.system(user_notify_command + info)
|
|
||||||
|
|
||||||
|
|
||||||
def sleep_after_send_signal(signal):
|
def sleep_after_send_signal(signal):
|
||||||
if signal is 9:
|
if signal is 9:
|
||||||
if print_sleep_periods:
|
if print_sleep_periods:
|
||||||
@ -260,6 +227,9 @@ def sleep_after_send_signal(signal):
|
|||||||
|
|
||||||
def find_victim_and_send_signal(signal):
|
def find_victim_and_send_signal(signal):
|
||||||
|
|
||||||
|
print('****')
|
||||||
|
print(mem_info)
|
||||||
|
|
||||||
# выставляем потолок для oom_score_adj всех процессов
|
# выставляем потолок для oom_score_adj всех процессов
|
||||||
if decrease_oom_score_adj and root:
|
if decrease_oom_score_adj and root:
|
||||||
func_decrease_oom_score_adj(oom_score_adj_max)
|
func_decrease_oom_score_adj(oom_score_adj_max)
|
||||||
@ -269,9 +239,6 @@ def find_victim_and_send_signal(signal):
|
|||||||
|
|
||||||
if use_regex_lists:
|
if use_regex_lists:
|
||||||
|
|
||||||
# pid list, rename var! blacklisted_pids
|
|
||||||
oom_blacklist_regex = []
|
|
||||||
|
|
||||||
for pid in os.listdir('/proc'):
|
for pid in os.listdir('/proc'):
|
||||||
if pid.isdigit() is not True:
|
if pid.isdigit() is not True:
|
||||||
continue
|
continue
|
||||||
@ -280,20 +247,6 @@ def find_victim_and_send_signal(signal):
|
|||||||
oom_score = int(rline1('/proc/' + pid + '/oom_score'))
|
oom_score = int(rline1('/proc/' + pid + '/oom_score'))
|
||||||
name = pid_to_name(pid)
|
name = pid_to_name(pid)
|
||||||
|
|
||||||
# если имя в белом списке,то пропускаем
|
|
||||||
res = fullmatch(whitelist_regex, name)
|
|
||||||
if res is not None:
|
|
||||||
print(' {} (Pid: {}) matches with whitelist_regex'.format(name, pid)),
|
|
||||||
continue
|
|
||||||
|
|
||||||
# если имя в черном списке - добавляем Pid в список для убийства
|
|
||||||
# ДОБАВЛЯТЬ И ИМЯ СРАЗУ
|
|
||||||
# ВАРИАНТ - СРАЗУ УБИВАТЬ
|
|
||||||
res = fullmatch(blacklist_regex, name)
|
|
||||||
if res is not None:
|
|
||||||
oom_blacklist_regex.append(pid)
|
|
||||||
print(' {} (Pid: {}) matches with blacklist_regex'.format(name, pid)),
|
|
||||||
|
|
||||||
res = fullmatch(avoidlist_regex, name)
|
res = fullmatch(avoidlist_regex, name)
|
||||||
if res is not None:
|
if res is not None:
|
||||||
# тут уже получаем badness
|
# тут уже получаем badness
|
||||||
@ -311,35 +264,6 @@ def find_victim_and_send_signal(signal):
|
|||||||
oom_score = 0
|
oom_score = 0
|
||||||
oom_list.append((pid, oom_score))
|
oom_list.append((pid, oom_score))
|
||||||
|
|
||||||
|
|
||||||
# если найден хоть один в черном списке - нет смысла сравнивать с остальными
|
|
||||||
|
|
||||||
if oom_blacklist_regex != []:
|
|
||||||
|
|
||||||
for pid in oom_blacklist_regex:
|
|
||||||
|
|
||||||
name = pid_to_name(pid)
|
|
||||||
print(' Preventing OOM: trying to send the {} signal to blacklisted process {}, Pid: {}'.format(
|
|
||||||
sig_dict[signal], name, pid))
|
|
||||||
|
|
||||||
try:
|
|
||||||
os.kill(int(pid), signal)
|
|
||||||
print(' Success')
|
|
||||||
|
|
||||||
if desktop_notifications:
|
|
||||||
send_notify_black(signal, name, pid)
|
|
||||||
|
|
||||||
except FileNotFoundError:
|
|
||||||
print(' No such process')
|
|
||||||
except ProcessLookupError:
|
|
||||||
print(' No such process')
|
|
||||||
except PermissionError:
|
|
||||||
print(' Operation not permitted')
|
|
||||||
|
|
||||||
# после отправки сигнала процессам из черного списка поспать и выйти из функции
|
|
||||||
sleep_after_send_signal(signal)
|
|
||||||
return 0
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
|
||||||
# not use regex
|
# not use regex
|
||||||
@ -354,14 +278,12 @@ def find_victim_and_send_signal(signal):
|
|||||||
oom_score = 0
|
oom_score = 0
|
||||||
oom_list.append((i, oom_score))
|
oom_list.append((i, oom_score))
|
||||||
|
|
||||||
|
|
||||||
# получаем отсортированный по oom_score (по badness!) список пар (pid, oom_score)
|
# получаем отсортированный по oom_score (по badness!) список пар (pid, oom_score)
|
||||||
pid_tuple_list = sorted(oom_list, key=itemgetter(1), reverse=True)[0]
|
pid_tuple_list = sorted(oom_list, key=itemgetter(1), reverse=True)[0]
|
||||||
|
|
||||||
# получаем максимальный oom_score
|
# получаем максимальный oom_score
|
||||||
oom_score = pid_tuple_list[1]
|
oom_score = pid_tuple_list[1]
|
||||||
|
|
||||||
|
|
||||||
if oom_score >= oom_score_min:
|
if oom_score >= oom_score_min:
|
||||||
|
|
||||||
# пытаемся отправить сигнал найденной жертве
|
# пытаемся отправить сигнал найденной жертве
|
||||||
@ -392,13 +314,12 @@ def find_victim_and_send_signal(signal):
|
|||||||
vm_rss = 0
|
vm_rss = 0
|
||||||
vm_swap = 0
|
vm_swap = 0
|
||||||
|
|
||||||
|
|
||||||
if name in etc_dict and signal is 15:
|
if name in etc_dict and signal is 15:
|
||||||
command = etc_dict[name]
|
command = etc_dict[name]
|
||||||
etc_info = ' Process {} is a victim,\n Pid: {}, Badness: {}, VmRSS: {} MiB, VmSwap: {} MiB\n Execute command: {}'.format(name, pid, oom_score, vm_rss, vm_swap, command)
|
etc_info = ' Process {} is a victim,\n Pid: {}, Badness: {}, VmRSS: {} MiB, VmSwap: {} MiB\n Execute command: {}'.format(name, pid, oom_score, vm_rss, vm_swap, command)
|
||||||
|
os.system(etc_dict[name]) # все норм, это произвольная команда задана юзером
|
||||||
print(etc_info)
|
print(etc_info)
|
||||||
os.system(etc_dict[name])
|
# еще ГУИ уведомление запустить
|
||||||
append_log(etc_info)
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
|
||||||
@ -414,25 +335,11 @@ def find_victim_and_send_signal(signal):
|
|||||||
except ProcessLookupError:
|
except ProcessLookupError:
|
||||||
send_result = ' No such process'
|
send_result = ' No such process'
|
||||||
|
|
||||||
|
|
||||||
time_now_and_mem_info = datetime.datetime.today().strftime(
|
|
||||||
'\n%Y-%m-%d %a %H:%M:%S\n{}'.format(mem_info))
|
|
||||||
|
|
||||||
print(time_now_and_mem_info)
|
|
||||||
|
|
||||||
if logging:
|
|
||||||
append_log(time_now_and_mem_info)
|
|
||||||
|
|
||||||
try_to_send = ' Preventing OOM: trying to send the {} signal to {},\n Pid: {}, Badness: {}, VmRSS: {} MiB, VmSwap: {} MiB'.format(sig_dict[signal], name, pid, oom_score, vm_rss, vm_swap)
|
try_to_send = ' Preventing OOM: trying to send the {} signal to {},\n Pid: {}, Badness: {}, VmRSS: {} MiB, VmSwap: {} MiB'.format(sig_dict[signal], name, pid, oom_score, vm_rss, vm_swap)
|
||||||
|
|
||||||
print(try_to_send)
|
print(try_to_send)
|
||||||
|
|
||||||
|
|
||||||
print(send_result)
|
print(send_result)
|
||||||
|
|
||||||
if logging:
|
|
||||||
append_log(try_to_send + '\n' + send_result)
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
|
||||||
badness_is_too_small = ' oom_score {} < oom_score_min {}'.format(
|
badness_is_too_small = ' oom_score {} < oom_score_min {}'.format(
|
||||||
@ -440,9 +347,6 @@ def find_victim_and_send_signal(signal):
|
|||||||
|
|
||||||
print(badness_is_too_small)
|
print(badness_is_too_small)
|
||||||
|
|
||||||
if logging:
|
|
||||||
append_log(badness_is_too_small)
|
|
||||||
|
|
||||||
sleep_after_send_signal(signal)
|
sleep_after_send_signal(signal)
|
||||||
|
|
||||||
|
|
||||||
@ -611,6 +515,23 @@ print_mem_check_results = conf_parse_bool('print_mem_check_results')
|
|||||||
print_sleep_periods = conf_parse_bool('print_sleep_periods')
|
print_sleep_periods = conf_parse_bool('print_sleep_periods')
|
||||||
|
|
||||||
|
|
||||||
|
realtime_ionice = conf_parse_bool('realtime_ionice')
|
||||||
|
|
||||||
|
|
||||||
|
if 'realtime_ionice_classdata' in config_dict:
|
||||||
|
realtime_ionice_classdata = string_to_int_convert_test(
|
||||||
|
config_dict['realtime_ionice_classdata'])
|
||||||
|
if realtime_ionice_classdata is None:
|
||||||
|
print('Invalid realtime_ionice_classdata value, not integer\nExit')
|
||||||
|
exit()
|
||||||
|
if realtime_ionice_classdata < 0 or realtime_ionice_classdata > 7:
|
||||||
|
print('Invalid realtime_ionice_classdata value\nExit')
|
||||||
|
exit()
|
||||||
|
else:
|
||||||
|
print('realtime_ionice_classdata not in config\nExit')
|
||||||
|
exit()
|
||||||
|
|
||||||
|
|
||||||
mlockall = conf_parse_bool('mlockall')
|
mlockall = conf_parse_bool('mlockall')
|
||||||
|
|
||||||
|
|
||||||
@ -952,12 +873,6 @@ if use_regex_lists:
|
|||||||
from re import fullmatch
|
from re import fullmatch
|
||||||
|
|
||||||
|
|
||||||
whitelist_regex = conf_parse_string('whitelist_regex')
|
|
||||||
|
|
||||||
|
|
||||||
blacklist_regex = conf_parse_string('blacklist_regex')
|
|
||||||
|
|
||||||
|
|
||||||
preferlist_regex = conf_parse_string('preferlist_regex')
|
preferlist_regex = conf_parse_string('preferlist_regex')
|
||||||
|
|
||||||
|
|
||||||
@ -990,11 +905,8 @@ else:
|
|||||||
exit()
|
exit()
|
||||||
|
|
||||||
|
|
||||||
logging = conf_parse_bool('logging')
|
|
||||||
|
|
||||||
|
|
||||||
logfile = conf_parse_string('logfile')
|
|
||||||
|
|
||||||
|
|
||||||
low_memory_warnings = conf_parse_bool('low_memory_warnings')
|
low_memory_warnings = conf_parse_bool('low_memory_warnings')
|
||||||
|
|
||||||
@ -1190,7 +1102,11 @@ else:
|
|||||||
mla_res = ''
|
mla_res = ''
|
||||||
|
|
||||||
|
|
||||||
if os.geteuid() == 0:
|
self_uid = os.geteuid()
|
||||||
|
self_pid = os.getpid()
|
||||||
|
|
||||||
|
|
||||||
|
if self_uid == 0:
|
||||||
root = True
|
root = True
|
||||||
decrease_res = 'OK'
|
decrease_res = 'OK'
|
||||||
else:
|
else:
|
||||||
@ -1198,6 +1114,15 @@ else:
|
|||||||
decrease_res = 'Impossible'
|
decrease_res = 'Impossible'
|
||||||
|
|
||||||
|
|
||||||
|
if root and realtime_ionice:
|
||||||
|
os.system('ionice -c 1 -n {} -p {}'.format(
|
||||||
|
realtime_ionice_classdata ,self_pid))
|
||||||
|
print('\nionice:'.format())
|
||||||
|
os.system('ionice')
|
||||||
|
print()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
##########################################################################
|
##########################################################################
|
||||||
|
|
||||||
|
|
||||||
@ -1258,18 +1183,11 @@ if print_config:
|
|||||||
print('\nVII. AVOID AND PREFER VICTIM NAMES VIA REGEX')
|
print('\nVII. AVOID AND PREFER VICTIM NAMES VIA REGEX')
|
||||||
print('use_regex_lists: {}'.format(use_regex_lists))
|
print('use_regex_lists: {}'.format(use_regex_lists))
|
||||||
if use_regex_lists:
|
if use_regex_lists:
|
||||||
print('whitelist_regex: {}'.format(whitelist_regex))
|
|
||||||
print('blacklist_regex: {}'.format(blacklist_regex))
|
|
||||||
print('preferlist_regex: {}'.format(preferlist_regex))
|
print('preferlist_regex: {}'.format(preferlist_regex))
|
||||||
print('preferlist_factor: {}'.format(preferlist_factor))
|
print('preferlist_factor: {}'.format(preferlist_factor))
|
||||||
print('avoidlist_regex: {}'.format(avoidlist_regex))
|
print('avoidlist_regex: {}'.format(avoidlist_regex))
|
||||||
print('avoidlist_factor: {}'.format(avoidlist_factor))
|
print('avoidlist_factor: {}'.format(avoidlist_factor))
|
||||||
|
|
||||||
print('\nVIII. LOGGING')
|
|
||||||
print('logging: {}'.format(logging))
|
|
||||||
if logging:
|
|
||||||
print('logfile: {}'.format(logfile))
|
|
||||||
|
|
||||||
print('\nIX. LOW MEMORY WARNINGS')
|
print('\nIX. LOW MEMORY WARNINGS')
|
||||||
print('low_memory_warnings: {}'.format(low_memory_warnings))
|
print('low_memory_warnings: {}'.format(low_memory_warnings))
|
||||||
if low_memory_warnings:
|
if low_memory_warnings:
|
||||||
|
336
nohang.conf
336
nohang.conf
@ -5,98 +5,22 @@
|
|||||||
|
|
||||||
The configuration includes the following sections:
|
The configuration includes the following sections:
|
||||||
|
|
||||||
I. STANDARD OUTPUT VERBOSITY
|
* THRESHOLDS FOR SENDING SIGNALS
|
||||||
II. SELF-DEFENSE
|
* INTENSITY OF MONITORING (AND CPU USAGE)
|
||||||
III. INTENSITY OF MONITORING
|
* PREVENTION OF KILLING INNOCENT VICTIMS
|
||||||
IV. THRESHOLDS FOR SENDING SIGNALS
|
* AVOID AND PREFER VICTIM NAMES VIA REGEX
|
||||||
V. PREVENTION OF KILLING INNOCENT VICTIMS
|
* EXECUTE THE COMMAND INSTEAD OF SENDING THE SIGTERM SIGNAL
|
||||||
VI. DESKTOP NOTIFICATIONS
|
* GUI NOTIFICATIONS
|
||||||
VII. AVOID AND PREFER VICTIM NAMES VIA REGEX
|
* LOW MEMORY WARNINGS
|
||||||
VIII. LOGGING
|
* SELF-DEFENSE AND PREVENTING SLOWING DOWN THE PROGRAM
|
||||||
IX. LOW MEMORY WARNINGS
|
* OUTPUT VERBOSITY
|
||||||
X. EXECUTE THE COMMAND INSTEAD OF SENDING THE SIGTERM SIGNAL
|
|
||||||
|
|
||||||
Just read the description of the parameters and edit the values.
|
Just read the description of the parameters and edit the values.
|
||||||
Please restart the program after editing the config.
|
Please restart the program after editing the config.
|
||||||
|
|
||||||
#####################################################################
|
#####################################################################
|
||||||
|
|
||||||
I. STANDARD OUTPUT VERBOSITY
|
I. THRESHOLDS FOR SENDING SIGNALS
|
||||||
|
|
||||||
Display the configuration when the program starts.
|
|
||||||
Valid values are True and False.
|
|
||||||
Values are case sensitive!
|
|
||||||
|
|
||||||
print_config = True
|
|
||||||
|
|
||||||
Print memory check results or not print.
|
|
||||||
Valid values are True and False.
|
|
||||||
|
|
||||||
print_mem_check_results = True
|
|
||||||
|
|
||||||
Print sleep periods between memory checks or not print.
|
|
||||||
Valid values are True and False.
|
|
||||||
|
|
||||||
print_sleep_periods = False
|
|
||||||
|
|
||||||
#####################################################################
|
|
||||||
|
|
||||||
II. SELF-DEFENSE
|
|
||||||
|
|
||||||
True - заблокировать процесс в памяти для запрета его своппинга.
|
|
||||||
False - не блокировать. Значения чувствительны к регистру!
|
|
||||||
|
|
||||||
В Fedora 28 значение True вызывает увеличение потребления
|
|
||||||
памяти процессом на 200 MiB, в Debian 8 и 9 такой проблемы нет.
|
|
||||||
|
|
||||||
mlockall = False
|
|
||||||
|
|
||||||
Установка отрицательных значений self_nice и self_oom_score_adj
|
|
||||||
требует наличия root прав.
|
|
||||||
|
|
||||||
Установка отрицательного self_nice повышает приоритет процесса.
|
|
||||||
|
|
||||||
Valid values are integers from the range [-20; 19].
|
|
||||||
|
|
||||||
self_nice = -10
|
|
||||||
|
|
||||||
Set oom_score_adj for the process.
|
|
||||||
Valid values are integers from the range [-1000; 1000].
|
|
||||||
Setting the values to -1000 will prohibit suicide.
|
|
||||||
|
|
||||||
self_oom_score_adj = -100
|
|
||||||
|
|
||||||
#####################################################################
|
|
||||||
|
|
||||||
III. INTENSITY OF MONITORING
|
|
||||||
|
|
||||||
Coefficients that affect the intensity of monitoring. Reducing
|
|
||||||
the coefficients can reduce CPU usage and increase the periods
|
|
||||||
between memory checks.
|
|
||||||
|
|
||||||
Почему три коэффициента, а не один? - Потому что скорость
|
|
||||||
наполнения свопа обычно ниже скорости наполнения RAM.
|
|
||||||
Можно для свопа задать более низкую интенсивность
|
|
||||||
мониторинга без ущерба для предотвращения нехватки памяти
|
|
||||||
и тем самым снизить нагрузку на процессор.
|
|
||||||
|
|
||||||
В дефолтных настройках на данной интенсивности демон работает
|
|
||||||
достаточно хорошо, успешно справляясь с резкими скачками потребления
|
|
||||||
памяти.
|
|
||||||
|
|
||||||
Default values are well for desktop.
|
|
||||||
On servers without rapid fluctuations in memory level, the
|
|
||||||
values can be reduced.
|
|
||||||
|
|
||||||
Valid values are positive floating-point numbers.
|
|
||||||
|
|
||||||
rate_mem = 6
|
|
||||||
rate_swap = 3
|
|
||||||
rate_zram = 1
|
|
||||||
|
|
||||||
#####################################################################
|
|
||||||
|
|
||||||
IV. THRESHOLDS FOR SENDING SIGNALS
|
|
||||||
|
|
||||||
Sets the available memory levels below which SIGTERM or SIGKILL
|
Sets the available memory levels below which SIGTERM or SIGKILL
|
||||||
signals are sent. The signal will be sent if MemAvailable and
|
signals are sent. The signal will be sent if MemAvailable and
|
||||||
@ -123,7 +47,35 @@ zram_max_sigkill = 60 %
|
|||||||
|
|
||||||
#####################################################################
|
#####################################################################
|
||||||
|
|
||||||
V. PREVENTION OF KILLING INNOCENT VICTIMS
|
II. INTENSITY OF MONITORING
|
||||||
|
|
||||||
|
Coefficients that affect the intensity of monitoring. Reducing
|
||||||
|
the coefficients can reduce CPU usage and increase the periods
|
||||||
|
between memory checks.
|
||||||
|
|
||||||
|
Почему три коэффициента, а не один? - Потому что скорость
|
||||||
|
наполнения свопа обычно ниже скорости наполнения RAM.
|
||||||
|
Можно для свопа задать более низкую интенсивность
|
||||||
|
мониторинга без ущерба для предотвращения нехватки памяти
|
||||||
|
и тем самым снизить нагрузку на процессор.
|
||||||
|
|
||||||
|
В дефолтных настройках на данной интенсивности демон работает
|
||||||
|
достаточно хорошо, успешно справляясь с резкими скачками потребления
|
||||||
|
памяти.
|
||||||
|
|
||||||
|
Default values are well for desktop.
|
||||||
|
On servers without rapid fluctuations in memory level, the
|
||||||
|
values can be reduced.
|
||||||
|
|
||||||
|
Valid values are positive floating-point numbers.
|
||||||
|
|
||||||
|
rate_mem = 4
|
||||||
|
rate_swap = 2
|
||||||
|
rate_zram = 1
|
||||||
|
|
||||||
|
#####################################################################
|
||||||
|
|
||||||
|
III. PREVENTION OF KILLING INNOCENT VICTIMS
|
||||||
|
|
||||||
Минимальное значение oom_score, которым должен обладать
|
Минимальное значение oom_score, которым должен обладать
|
||||||
процесс для того, чтобы ему был отправлен сигнал.
|
процесс для того, чтобы ему был отправлен сигнал.
|
||||||
@ -162,7 +114,73 @@ oom_score_adj_max = 20
|
|||||||
|
|
||||||
#####################################################################
|
#####################################################################
|
||||||
|
|
||||||
VI. DESKTOP NOTIFICATIONS
|
IV. AVOID AND PREFER VICTIM NAMES VIA REGEX
|
||||||
|
|
||||||
|
Можно задать регулярные выражения (Perl-compatible regular
|
||||||
|
expressions), которые будут использоваться для сопоставления с
|
||||||
|
именами процессов для влияния на их badness.
|
||||||
|
|
||||||
|
Включение этой опции замедляет поиск жертвы, так как
|
||||||
|
имена всех процессов сравниваются с заданными regex-паттернами.
|
||||||
|
|
||||||
|
Valid values are True and False.
|
||||||
|
|
||||||
|
use_regex_lists = False
|
||||||
|
|
||||||
|
Badness процессов, имена которых соответствуют preferlist_regex,
|
||||||
|
будут рассчитываться по формуле
|
||||||
|
badness = (oom_score + 1) * preferlist_factor
|
||||||
|
|
||||||
|
preferlist_regex = tail|python3
|
||||||
|
|
||||||
|
Valid values are floating-point numbers from the range [1; 1000].
|
||||||
|
|
||||||
|
preferlist_factor = 3
|
||||||
|
|
||||||
|
Список нежелательных для убийства процессов.
|
||||||
|
|
||||||
|
Badness процессов, имена которых соответствуют avoidlist_regex,
|
||||||
|
будут рассчитываться по формуле
|
||||||
|
badness = oom_score / avoidlist_factor
|
||||||
|
|
||||||
|
avoidlist_regex = Xorg|sshd
|
||||||
|
|
||||||
|
Valid values are floating-point numbers from the range [1; 1000].
|
||||||
|
|
||||||
|
avoidlist_factor = 4
|
||||||
|
|
||||||
|
#####################################################################
|
||||||
|
|
||||||
|
V. EXECUTE THE COMMAND INSTEAD OF SENDING THE SIGTERM SIGNAL
|
||||||
|
|
||||||
|
Для процессов с определенным именем можно задать команду,
|
||||||
|
которая будет выполняться вместо отправки сигнала SIGTERM
|
||||||
|
процессу с соответствующим именем.
|
||||||
|
|
||||||
|
Например, если процесс запущен как демон, то вместо
|
||||||
|
отправки SIGTERM можно выполнить команду перезапуска.
|
||||||
|
|
||||||
|
Valid values are True and False.
|
||||||
|
|
||||||
|
execute_the_command = False
|
||||||
|
|
||||||
|
Длина имени процесса не должна превышать 15 символов.
|
||||||
|
Синтаксис таков: строки, начинающиеся с **, считаются строками,
|
||||||
|
содержащими имена процессов и соотвестствующие команды для
|
||||||
|
перезапуска этих процессов. После имени процесса через двойное
|
||||||
|
двоеточие (::) следует команда.
|
||||||
|
Амперсанд (&) в конце команды позволит nohang продолжить работу
|
||||||
|
не дожидаясь окончания выполнения команды.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
** mysqld :: systemctl restart mariadb.service &
|
||||||
|
** php-fpm7.0 :: systemctl restart php7.0-fpm.service &
|
||||||
|
|
||||||
|
** processname :: some command
|
||||||
|
|
||||||
|
#####################################################################
|
||||||
|
|
||||||
|
VI. GUI NOTIFICATIONS
|
||||||
|
|
||||||
Включение этой опции требует наличия notify-send в системе.
|
Включение этой опции требует наличия notify-send в системе.
|
||||||
В Debian/Ubuntu это обеспечивается установкой пакета
|
В Debian/Ubuntu это обеспечивается установкой пакета
|
||||||
@ -192,79 +210,11 @@ root_display = :0
|
|||||||
|
|
||||||
#####################################################################
|
#####################################################################
|
||||||
|
|
||||||
VII. AVOID AND PREFER VICTIM NAMES VIA REGEX
|
VII. LOW MEMORY WARNINGS
|
||||||
|
|
||||||
Можно задать регулярные выражения (Perl-compatible regular
|
|
||||||
expressions), которые будут использоваться для сопоставления с
|
|
||||||
именами процессов для влияния на их badness.
|
|
||||||
|
|
||||||
Включение этой опции замедляет поиск жертвы, так как
|
|
||||||
имена всех процессов сравниваются с заданными regex-паттернами.
|
|
||||||
|
|
||||||
Valid values are True and False.
|
|
||||||
|
|
||||||
use_regex_lists = False
|
|
||||||
|
|
||||||
Приоритет списков (если один процесс находится одновременно в
|
|
||||||
нескольких):
|
|
||||||
1. whitelist_regex: сначала пропуск процессов из белого списка;
|
|
||||||
2. blacklist_regex: отправка сигнала всем из черного списка;
|
|
||||||
3. preferlist_regex и avoidlist_regex: умножение или деление
|
|
||||||
oom_score на соответствующие факторы.
|
|
||||||
|
|
||||||
Процессы, имена которых соответствуют выражению
|
|
||||||
whitelist_regex, не получат сигнал.
|
|
||||||
|
|
||||||
Регулярное выражение для формирования белого списка.
|
|
||||||
|
|
||||||
whitelist_regex = sshd
|
|
||||||
|
|
||||||
При нехватке памяти все процессы, имена которых соответствуют
|
|
||||||
blacklist_regex, получат сигнал.
|
|
||||||
|
|
||||||
blacklist_regex =
|
|
||||||
|
|
||||||
Badness процессов, имена которых соответствуют preferlist_regex,
|
|
||||||
будут рассчитываться по формуле
|
|
||||||
badness = (oom_score + 1) * preferlist_factor
|
|
||||||
|
|
||||||
preferlist_regex = tail|python3|someprocessname
|
|
||||||
|
|
||||||
Valid values are floating-point numbers from the range [1; 1000].
|
|
||||||
|
|
||||||
preferlist_factor = 3
|
|
||||||
|
|
||||||
Список нежелательных для убийства процессов.
|
|
||||||
|
|
||||||
Badness процессов, имена которых соответствуют avoidlist_regex,
|
|
||||||
будут рассчитываться по формуле
|
|
||||||
badness = oom_score / avoidlist_factor
|
|
||||||
|
|
||||||
avoidlist_regex = Xorg
|
|
||||||
|
|
||||||
Valid values are floating-point numbers from the range [1; 1000].
|
|
||||||
|
|
||||||
avoidlist_factor = 3
|
|
||||||
|
|
||||||
#####################################################################
|
|
||||||
|
|
||||||
VIII. LOGGING
|
|
||||||
|
|
||||||
OOM prevention progress can be logged.
|
|
||||||
|
|
||||||
Valid values are True and False.
|
|
||||||
|
|
||||||
logging = True
|
|
||||||
|
|
||||||
logfile = /var/log/nohang/nohang.log
|
|
||||||
|
|
||||||
#####################################################################
|
|
||||||
|
|
||||||
IX. LOW MEMORY WARNINGS
|
|
||||||
|
|
||||||
Десктопные уведомления о низком уровне доступной памяти.
|
Десктопные уведомления о низком уровне доступной памяти.
|
||||||
Для работы опции должны быть включены десктопные уведомления.
|
Для работы опции должны быть включены десктопные уведомления.
|
||||||
Возможно стоит этот раздел объединить с DESKTOP NOTIFICATIONS.
|
Возможно стоит этот раздел объединить с GUI NOTIFICATIONS.
|
||||||
|
|
||||||
Valid values are True and False.
|
Valid values are True and False.
|
||||||
|
|
||||||
@ -293,30 +243,62 @@ zram_max_warnings = 40 %
|
|||||||
|
|
||||||
#####################################################################
|
#####################################################################
|
||||||
|
|
||||||
X. EXECUTE THE COMMAND INSTEAD OF SENDING THE SIGTERM SIGNAL
|
VIII. SELF-DEFENSE AND PREVENTING SLOWING DOWN THE PROGRAM
|
||||||
|
|
||||||
Для процессов с определенным именем можно задать команду,
|
True - заблокировать процесс в памяти для запрета его своппинга.
|
||||||
которая будет выполняться вместо отправки сигнала SIGTERM
|
False - не блокировать.
|
||||||
процессу с соответствующим именем.
|
|
||||||
|
|
||||||
Например, если процесс запущен как демон, то вместо
|
В Fedora 28 значение True вызывает увеличение потребления
|
||||||
отправки SIGTERM можно выполнить команду перезапуска.
|
памяти процессом на 200 MiB, в Debian 8 и 9 такой проблемы нет.
|
||||||
|
|
||||||
|
mlockall = False
|
||||||
|
|
||||||
|
Установка отрицательных значений self_nice и self_oom_score_adj
|
||||||
|
требует наличия root прав.
|
||||||
|
|
||||||
|
Установка отрицательного self_nice повышает приоритет процесса.
|
||||||
|
|
||||||
|
Valid values are integers from the range [-20; 19].
|
||||||
|
|
||||||
|
self_nice = -15
|
||||||
|
|
||||||
|
# -> niceness
|
||||||
|
|
||||||
|
Set oom_score_adj for the process.
|
||||||
|
Valid values are integers from the range [-1000; 1000].
|
||||||
|
Setting the values to -1000 will prohibit suicide.
|
||||||
|
|
||||||
|
self_oom_score_adj = -100
|
||||||
|
|
||||||
|
Read `man ionice` to understand the following parameters.
|
||||||
|
Setting the True value requires the root privileges.
|
||||||
|
|
||||||
|
realtime_ionice = True
|
||||||
|
|
||||||
|
'For realtime and best-effort, 0-7 are valid data
|
||||||
|
(priority levels), and 0 represents the highest priority level.'
|
||||||
|
- `man ionice`
|
||||||
|
Valid values are integers from the range [0; 7].
|
||||||
|
|
||||||
|
realtime_ionice_classdata = 5
|
||||||
|
|
||||||
|
#####################################################################
|
||||||
|
|
||||||
|
IX. STANDARD OUTPUT VERBOSITY
|
||||||
|
|
||||||
|
Display the configuration when the program starts.
|
||||||
|
Valid values are True and False.
|
||||||
|
Values are case sensitive!
|
||||||
|
|
||||||
|
print_config = False
|
||||||
|
|
||||||
|
Print memory check results or not print.
|
||||||
Valid values are True and False.
|
Valid values are True and False.
|
||||||
|
|
||||||
execute_the_command = False
|
print_mem_check_results = False
|
||||||
|
|
||||||
Длина имени процесса не должна превышать 15 символов.
|
Print sleep periods between memory checks or not print.
|
||||||
Синтаксис таков: строки, начинающиеся с **, считаются строками,
|
Valid values are True and False.
|
||||||
содержащими имена процессов и соотвестствующие команды для
|
|
||||||
перезапуска этих процессов. После имени процесса через двойное
|
|
||||||
двоеточие (::) следует команда.
|
|
||||||
Амперсанд (&) в конце команды позволит nohang продолжить работу
|
|
||||||
не дожидаясь окончания выполнения команды.
|
|
||||||
|
|
||||||
For example:
|
print_sleep_periods = False
|
||||||
** mysqld :: systemctl restart mariadb.service &
|
|
||||||
** php-fpm7.0 :: systemctl restart php7.0-fpm.service &
|
|
||||||
|
|
||||||
** processname :: some command
|
|
||||||
|
|
||||||
|
@ -1,9 +0,0 @@
|
|||||||
/var/log/nohang/*.log {
|
|
||||||
create 640 root adm
|
|
||||||
missingok
|
|
||||||
notifempty
|
|
||||||
weekly
|
|
||||||
rotate 5
|
|
||||||
compress
|
|
||||||
delaycompress
|
|
||||||
}
|
|
@ -7,7 +7,7 @@ Documentation=man:nohang(1) https://github.com/hakavlad/nohang
|
|||||||
[Service]
|
[Service]
|
||||||
Type=simple
|
Type=simple
|
||||||
Restart=always
|
Restart=always
|
||||||
StandardOutput=null
|
StandardOutput=syslog
|
||||||
StandardError=syslog
|
StandardError=syslog
|
||||||
ExecStart=/usr/local/bin/nohang
|
ExecStart=/usr/local/bin/nohang
|
||||||
|
|
||||||
|
2
purge.sh
2
purge.sh
@ -4,6 +4,4 @@ systemctl disable nohang
|
|||||||
rm /usr/local/bin/nohang
|
rm /usr/local/bin/nohang
|
||||||
rm /usr/local/share/man/man1/nohang.1.gz
|
rm /usr/local/share/man/man1/nohang.1.gz
|
||||||
rm /etc/systemd/system/nohang.service
|
rm /etc/systemd/system/nohang.service
|
||||||
rm /etc/logrotate.d/nohang
|
|
||||||
rm -r /etc/nohang
|
rm -r /etc/nohang
|
||||||
rm -r /var/log/nohang
|
|
||||||
|
Loading…
Reference in New Issue
Block a user