Наладжваем Out-Of-Memory Killer у Linux для PostgreSQL

Наладжваем Out-Of-Memory Killer у Linux для PostgreSQL

Калі ў 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() выбірае працэс па пэўных правілах.

  1. Ядру патрэбен нейкі мінімум памяці для сябе.
  2. Трэба вызваліць шмат памяці.
  3. Не трэба завяршаць працэсы, якія выкарыстоўваюць мала памяці.
  4. Трэба завяршыць мінімум працэсаў.
  5. Складаныя алгарытмы, якія падвышаюць шанцы на завяршэнне для тых працэсаў, якія карыстач сам жадае завяршыць.

Выканаўшы ўсе гэтыя праверкі, 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

Дадаць каментар