Калі ў Linux сервер базы дадзеных непрадбачана завяршае працу, трэба знайсці чыннік. Прычын можа быць некалькі. Напрыклад, СІГСЭГВ - збой з-за бага ў бэкенд-серверы. Але гэта рэдкасць. Часцей за ўсё проста заканчваецца прастора на дыску ці памяць. Калі скончылася прастора на дыску, выйсце адно - вызваліць месца і перазапусціць базу дадзеных.
Out-Of-Memory Killer
Калі ў сервера або працэсу заканчваецца памяць, Linux прапануе 2 шляхі рашэння: абрынуць усю сістэму або завяршыць працэс (дадатак), які з'ядае памяць. Лепш, вядома, завяршыць працэс і выратаваць АС ад аварыйнага завяршэння. У двух словах, Out-Of-Memory Killer - гэта працэс, які завяршае дадатак, каб выратаваць ядро ад збою. Ён ахвяруе дадаткам, каб захаваць працу АС. Давайце спачатку абмяркуем, як працуе OOM і як яго кантраляваць, а потым паглядзім, як OOM Killer вырашае, якое прыкладанне завяршыць.
Адна з галоўных задач Linux - вылучаць памяць працэсам, калі яны яе просяць. Звычайна працэс або дадатак запытваюць у АС памяць, а самі выкарыстоўваюць яе не цалкам. Калі АС будзе выдаваць памяць усім, хто яе просіць, але не плануе выкарыстоўваць, вельмі хутка памяць скончыцца і сістэма адмовіць. Каб гэтага пазбегнуць, АС рэзервуе памяць за працэсам, але фактычна не выдае яе. Памяць выдзяляецца, толькі калі працэс сапраўды збіраецца яе выкарыстоўваць. Здараецца, што ў АС няма вольнай памяці, але яна замацоўвае памяць за працэсам, і калі працэсу яна патрэбна, АС вылучае яе, калі можа. Мінус у тым, што часам АС рэзервуе памяць, але ў патрэбны момант вольнай памяці няма, і адбываецца збой сістэмы. OOM гуляе важную ролю ў гэтым сцэнары і завяршае працэсы, каб зберагчы ядро ад панікі. Калі прымусова завяршаецца працэс PostgreSQL, у логу з'яўляецца паведамленне:
Out of Memory: Killed process 12345 (postgres).
Калі ў сістэме мала памяці і вызваліць яе немагчыма, выклікаецца функцыя out_of_memory
. На гэтым этапе ёй застаецца толькі адно - завяршыць адзін або некалькі працэсаў. OOM-killer павінен завяршаць працэс адразу ці можна пачакаць? Відавочна, што, калі выклікаецца out_of_memory, гэта звязана з чаканнем аперацыі ўводу-вываду або падпампоўкай старонкі на дыск. Таму OOM-killer павінен спачатку выканаць праверкі і на іх аснове вырашыць, што трэба завяршыць працэс. Калі ўсе прыведзеныя ніжэй праверкі дадуць станоўчы вынік, OOM завершыць працэс.
Выбар працэсу
Калі заканчваецца памяць, выклікаецца функцыя out_of_memory()
. У ёй ёсць функцыя select_bad_process()
, якая атрымлівае ацэнку ад функцыі badness()
. Пад раздачу патрапіць самы "дрэнны" працэс. Функцыя badness()
выбірае працэс па пэўных правілах.
- Ядру патрэбен нейкі мінімум памяці для сябе.
- Трэба вызваліць шмат памяці.
- Не трэба завяршаць працэсы, якія выкарыстоўваюць мала памяці.
- Трэба завяршыць мінімум працэсаў.
- Складаныя алгарытмы, якія падвышаюць шанцы на завяршэнне для тых працэсаў, якія карыстач сам жадае завяршыць.
Выканаўшы ўсе гэтыя праверкі, OOM вывучае адзнаку (oom_score
). OOM прызначае oom_score
кожнаму працэсу, а потым памнажае гэтае значэнне на аб'ём памяці. У працэсаў з вялікімі значэннямі больш шанцаў стаць ахвярамі OOM Killer. Працэсы, звязаныя з прывілеяваным карыстальнікам, маюць больш нізкую адзнаку і менш шанцаў на прымусовае завяршэнне.
postgres=# SELECT pg_backend_pid();
pg_backend_pid
----------------
3813
(1 row)
Ідэнтыфікатар працэсу Postgres – 3813, таму ў іншай абалонцы можна атрымаць адзнаку, выкарыстаючы гэты параметр ядра oom_score
:
vagrant@vagrant:~$ sudo cat /proc/3813/oom_score
2
Калі вы зусім не хочаце, каб OOM-Killer завяршыў працэс, ёсць яшчэ адзін параметр ядра: oom_score_adj
. Дадайце вялікае адмоўнае значэнне, каб знізіць шанцы на завяршэнне дарагога вам працэсу.
sudo echo -100 > /proc/3813/oom_score_adj
Каб задаць значэнне oom_score_adj
, усталюйце OOMScoreAdjust ў блоку сэрвісу:
[Service]
OOMScoreAdjust=-1000
Або выкарыстоўвайце oomprotect
у камандзе rcctl
.
rcctl set <i>servicename</i> oomprotect -1000
Прымусовае завяршэнне працэсу
Калі адзін ці некалькі працэсаў ужо абраныя, OOM-Killer выклікае функцыю oom_kill_task()
. Гэтая функцыя адпраўляе працэсу сігнал завяршэння. У выпадку недахопу памяці oom_kill()
выклікае гэтую функцыю, каб адправіць працэсу сігнал SIGKILL. У лог ядра запісваецца паведамленне.
Out of Memory: Killed process [pid] [name].
Як кантраляваць OOM-Killer
У Linux можна ўключаць і адключаць OOM-Killer (хоць апошняе не рэкамендуецца). Для ўключэння і адключэнні выкарыстоўвайце параметр vm.oom-kill
. Каб уключыць OOM-Killer у асяроддзі выканання, выканайце каманду sysctl
.
sudo -s sysctl -w vm.oom-kill = 1
Каб адключыць OOM-Killer, укажыце значэнне 0 у гэтай жа камандзе:
sudo -s sysctl -w vm.oom-kill = 0
Вынік гэтай каманды захаваецца не назаўжды, а толькі да першай перазагрузкі. Калі трэба больш сталасці, дадайце гэты радок у файл /etc/sysctl.conf
:
echo vm.oom-kill = 1 >>/etc/sysctl.conf
Яшчэ адзін спосаб уключэння і адключэнні - напісаць зменную panic_on_oom
. Значэнне заўсёды можна праверыць у /proc
.
$ cat /proc/sys/vm/panic_on_oom
0
Калі ўсталяваць значэнне 0, то калі скончыцца памяць, kernel panic не будзе.
$ echo 0 > /proc/sys/vm/panic_on_oom
Калі ўсталяваць значэнне 1, то калі скончыцца памяць, здарыцца kernel panic.
echo 1 > /proc/sys/vm/panic_on_oom
OOM-Killer можна не толькі ўключаць і выключаць. Мы ўжо казалі, што Linux можа зарэзерваваць для працэсаў больш памяці, чым ёсць, але не вылучаць яе па факце, і гэтымі паводзінамі кіруе параметр ядра Linux. За гэта адказвае зменная vm.overcommit_memory
.
Для яе можна ўказваць наступныя значэнні:
0: ядро само вырашае, ці варта рэзерваваць занадта шмат памяці. Гэта значэнне па змаўчанні ў большасці версій Linux.
1: ядро заўсёды будзе рэзерваваць лішнюю памяць. Гэта рызыкоўна, бо памяць можа скончыцца, таму што, хутчэй за ўсё, аднойчы працэсы запатрабуюць належнае.
2: ядро не будзе рэзерваваць больш памяці, чым паказана ў параметры overcommit_ratio
.
У гэтым параметры вы паказваеце працэнт памяці, для якога дапушчальна залішняе рэзерваванне. Калі для яго няма месца, памяць не выдзяляецца, у рэзерваванні будзе адмоўлена. Гэта самы бяспечны варыянт, рэкамендаваны для PostgreSQL. На OOM-Killer уплывае яшчэ адзін элемент - магчымасць падпампоўкі, якой кіруе пераменная. cat /proc/sys/vm/swappiness
. Гэтыя значэнні паказваюць ядру, як апрацоўваць падпампоўку старонак. Чым больш значэнне, тым менш верагоднасці, што OOM завершыць працэс, але з-за аперацый уводу-вываду гэта негатыўна адбіваецца на базе дадзеных. І наадварот - чым менш значэнне, тым вышэй верагоднасць умяшання OOM-Killer, але і прадукцыйнасць базы дадзеных таксама вышэй. Значэнне па змаўчанні 60, але калі ўся база дадзеных змяшчаецца ў памяць, лепш усталяваць значэнне 1.
Вынікі
Хай вас не палохае "кілер" у OOM-Killer. У дадзеным выпадку кілер будзе выратавальнікам вашай сістэмы. Ён "забівае" самыя нядобрыя працэсы і ратуе сістэму ад аварыйнага завяршэння. Каб не даводзілася выкарыстоўваць OOM-Killer для завяршэння PostgreSQL, усталюеце для vm.overcommit_memory
значэнне 2. Гэта не гарантуе, што OOM-Killer не давядзецца ўмешвацца, але знізіць верагоднасць прымусовага завяршэння працэсу PostgreSQL.
Крыніца: habr.com