Ефекти налаштування vm.overcommit_memory


41

Мій веб-сервер VPS, що працює на CentOS 5.4 (ядро Linux 2.6.16.33-xenU) нерегулярно (як-то раз на місяць дають або забирають кілька тижнів), стає невідповідним через натискання вбивці, що вбиває роботу. Моніторинг сервера показує, що він не як правило, не вистачає пам’яті, просто кожен так часто.

Я прочитав пару блогів, які вказують на цю сторінку, в якій обговорюється настройка ядра для кращого керування надкомісією за допомогою наступних параметрів sysctl:

vm.overcommit_memory = 2
vm.overcommit_ratio = 80

Моє розуміння цього (що може бути помилковим, але я не можу знайти канонічне визначення для уточнення) полягає в тому, що це запобігає перерозподілу ядра ядра поза свопом + 80% фізичної пам'яті.

Однак я також читав деякі інші джерела, які припускають, що ці параметри не є гарною ідеєю - хоча, здається, критики цього підходу говорять: "не робіть справи, щоб зламати вашу систему, а не намагатися цього хитрувати", припускаючи, що причинно-наслідковий зв’язок завжди відомий.

Отже, моє запитання полягає в тому, які плюси і мінуси такого підходу в контексті веб-сервера Apache2, який розміщує близько 10 сайтів з низьким трафіком? У моєму конкретному випадку веб-сервер має 512 Мб оперативної пам’яті, з обміном місцями 1024 Мб. Це здається адекватним для переважної більшості часу.

Відповіді:


32

Установка overcommit_ratioна 80, швидше за все, не є правильним дією. Встановлення значення на рівні менше 100 майже завжди невірно.

Причиною цього є те, що програми для Linux виділяють більше, ніж дійсно потрібно. Скажіть, вони виділяють 8 кбіт для зберігання пари символьних рядків тексту. Ну ось кілька КБ, які там не використовуються. Програми роблять це дуже багато, і саме для цього призначений overcommit.

Таким чином, ядро ​​не дозволить програмам виділяти більше пам'яті, ніж у вас (swap + ram). Якщо встановити його менше ніж 100, означає, що ви ніколи не будете використовувати всю свою пам'ять. Якщо ви збираєтеся встановити цей параметр, вам слід встановити його вище 100 через вищезазначений сценарій, що є досить поширеним явищем.

Тепер, що стосується вашої проблеми із запуском вбивці OOM, вручну встановити перевиконання цього рішення, ймовірно, це не виправить. Налаштування за замовчуванням (евристичне визначення) є досить розумним.

Якщо ви хочете дізнатися, чи справді це причина проблеми, подивіться, /proc/meminfoколи вбивця OOM працює. Якщо ви бачите, що Committed_ASце близько CommitLimit, але freeвсе ще відображається вільна пам'ять, то так, ви можете вручну налаштувати надмірну комісію для свого сценарію. Якщо встановити це значення занадто низько, це призведе до того, що вбивця OOM почне вбивати додатки, коли у вас ще багато вільної пам'яті. Якщо встановити його занадто високо, це може призвести до вмирання випадкових програм, коли вони намагаються використовувати пам'ять, яку їм було виділено, але насправді вона доступна (коли вся пам'ять насправді звикає).


1
Дякую - я намагаюсь зробити речі із значенням overcommit_ratio на 100, щоб побачити, що відбувається. Основна проблема, яку я маю, полягає в тому, що коли запускається oom-killer, він незмінно вбиває sshd, не даючи мені отримати доступ до сервера і побачити, що відбувається. Я здогадуюсь, що мені насправді потрібно - це не допустити запуску вбивці, а також зафіксувати певні засоби запису того, що станеться, коли він би запустився, щоб я міг знайти причину проблеми.
dunxd

4
@dunxd ви можете використовувати /proc/<PID>/oom_score_adjдля цього. Наприклад, якщо встановити oom_score_adj на -1000 для sshd, вбивця oom ніколи не націлить на sshd, коли хоче щось вбити. Зупинка oom killer повністю не є хорошою ідеєю, тому що тоді ваші програми не зможуть поганяти пам'ять, і вони все одно помруть.
Патрік

4
@dunxd передав її у спадок. попросіть ваш скрипт init встановити його на себе, і все, що розпочалося скриптом init, це успадковує його.
Патрік

4
Ваш приклад 4 Кб неправильний. Віртуальна пам'ять використовується на сторінках, а (найменший) розмір сторінки під Linux - 4 Кб. Це означає, що для зберігання пари символів потрібно десь відобразити 4 Кб незалежно від налаштувань перевиконання. Правильним прикладом пам’яті над прихильністю є, наприклад, ви виділяєте 10 Кб і використовуєте лише перші 4100 байт. Це означає, що для зберігання даних потрібно дві 4 Кб сторінки, а одна додаткова сторінка не використовується. У системах, що не мають дозволу, завжди буде готова до зберігання третьої сторінки в разі надходження попиту, оскільки комісійні системи цього не будуть виконувати.
jlliagre

2
/ proc / self вказує на поточний процес, тому / proc / self / oom_score_adj можна використовувати для зміни oom_score_adj поточного процесу.
r_2

23

Розділ 9.6 "Overcommit and OOM" в документі, який згадує @dunxd, особливо графічно свідчить про небезпеку дозволення перевиконання комісії. Однак 80виглядав і мені цікаво, тому я провів кілька тестів.

Що я з’ясував, це те, що overcommit_ratioвпливає на загальну оперативну пам’ять, доступну для ВСІХ процесів. Корінні процеси, схоже, не трактуються інакше, ніж звичайні користувацькі процеси.

Встановлення відношення до 100або менше повинно забезпечувати класичну семантику, у якій значення, що повертаються, malloc/sbrkє надійними. Встановлення співвідношення нижче, ніж це 100може бути способом зарезервувати більше оперативної пам’яті для непроцесорних дій, таких як кешування тощо.

Так, на моєму комп’ютері з 24 Гб оперативної пам’яті, з вимкненням свопи, 9 гігабайт у користуванні, з topпоказом

Mem:  24683652k total,  9207532k used, 15476120k free,    19668k buffers
Swap:        0k total,        0k used,        0k free,   241804k cached

Ось кілька overcommit_ratioналаштувань і скільки оперативної пам’яті міг би захопити мій програму-споживач (торкаючись кожної сторінки) - у кожному випадку програма вийшла чисто після виходу з mallocладу.

 50    ~680 MiB
 60   ~2900 MiB
 70   ~5200 MiB
100  ~12000 MiB

Запуск декількох одразу, навіть якщо хтось як користувач root, не змінив загальну кількість, яку вони споживали разом. Цікаво, що не вдалося спожити останніх 3+ GiB або близько того; freeне опускалася значно нижче того , що показано тут:

Mem:  24683652k total, 20968212k used,  3715440k free,    20828k buffers

Експерименти були безладними - все, що використовує malloc на даний момент, коли вся оперативна пам'ять використовується, має тенденцію до краху, оскільки багато програмістів страшно перевіряти на предмет відмов malloc в C, деякі популярні бібліотеки колекцій цілком ігнорують його, а C ++ та різні інші мови навіть гірше.

Більшість ранніх впроваджень уявної оперативної пам’яті, яку я бачив, мали справу з дуже конкретним випадком, коли потрібен один великий процес - скажімо 51% + наявної пам’яті - для fork()того, щоб exec()якась програма підтримки, як правило, значно, набагато менша. ОС з семантикою копіювання при записі дозволяла б fork(), але за умови, що якщо роздвоєний процес насправді намагається змінити занадто багато сторінок пам’яті (кожна з яких потім повинна бути створена як нова сторінка, незалежна від початкового величезного процесу) це врешті-решт буде вбито. Батьківський процес загрожував лише тим, що виділивши більше пам’яті, і він міг би впоратися із закінченням, у деяких випадках просто зачекавши трохи, коли якийсь інший процес загине, а потім продовжиться. Дочірній процес зазвичай просто замінюється програмою (як правило, меншою) черезexec() і тоді він був звільнений від застереження.

Концепція overcommit Linux є надзвичайним підходом до того, щоб дозволити як fork()відбуватися, так і дозволяти одиночним процесам масово перерозподіляти. Смерть, спричинені вбивцею OOM, трапляються асинхронно, навіть із програмами, які працюють з розподілом пам'яті відповідально. Я особисто ненавиджу загальносистемну подолання загалом і особливо убивцю, - зокрема, це сприяє диявольському підходу до управління пам’яттю, яка заражає бібліотеки, і через них кожен додаток, який їх використовує.

Я б запропонував встановити співвідношення до 100, а також мати розділ swap, який, як правило, лише звикне до величезних процесів - які часто використовують лише крихітну частину самої себе частини, яка набивається в своп, і таким чином захистити переважну більшість процесів від невдач вбивств OOM. Це повинно захищати ваш веб-сервер від випадкової смерті, і якщо це було написано, щоб поводитися mallocвідповідально, навіть захистити себе від вбивства (але не ставте ставку на останнє).

Це означає, що я використовую це в /etc/sysctl.d/10-no-overcommit.conf

vm.overcommit_memory = 2
vm.overcommit_ratio = 100

І чи рекомендуєте ви зберегти vm.overcommit_memory до 2?
Ut xD

1
Гарна примітка - це справді те, що я використовую; Я думаю, що я пропустив це у своїй відповіді, оскільки це вже в питанні
Алекс Норт-Кейс
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.