В системе под управлением OpenVZ контейнеры, могут ограничиваться по следующим параметрам:
К дисковым квотам первого уровня относятся:
Пример установки данных параметров:
# vzctl set 200 --save --diskspace 50G:50G # vzctl set 200 --save --diskinodes 200000:200000
В результате получим:
# vzctl exec 200 df -h / Filesystem Size Used Avail Use% Mounted on simfs 50G 1.4G 49G 3% / # vzctl exec 200 df -i / Filesystem Inodes IUsed IFree IUse% Mounted on simfs 200000 21677 178323 11% /
Квоты второго уровня в OpenVZ - это квоты unix-пользователей внутри контейнера. Каждому контейнеру выделяется заданное количество записей в таблице, хранящей квоты. Это значение определяется в параметре QUOTAUGIDLIMIT. По умолчанию, все квоты второго уровня отключены и данный параметр для всех контейнеров выставлен в ноль. Чтобы разрешить квоты второго уровня в контейнере, необходимо установить значение QUOTAUGIDLIMIT в ненулевое значение:
# vzctl set 200 --save --quotaugidlimit 200
UBC можно посмотреть для каждой VPS через интерфейс /proc:
# vzctl exec 200 cat /proc/user_beancounters
Version: 2.5
uid resource held maxheld barrier limit failcnt
200: kmemsize 2575706 6701344 11055923 11377049 0
lockedpages 0 0 256 256 0
privvmpages 36928 69684 65536 69632 652909
shmpages 26 1322 21504 21504 0
dummy 0 0 0 0 0
numproc 34 95 240 240 0
physpages 15296 48207 0 2147483647 0
vmguarpages 0 0 33792 2147483647 0
oomguarpages 15444 48351 26112 2147483647 0
numtcpsock 5 64 360 360 0
numflock 4 11 188 206 0
numpty 0 4 16 16 0
numsiginfo 0 13 256 256 0
tcpsndbuf 44800 1349952 1720320 2703360 0
tcprcvbuf 81920 1727424 1720320 2703360 4
othersockbuf 6720 155904 1126080 2097152 0
dgramrcvbuf 0 9600 262144 262144 0
numothersock 5 23 360 360 0
dcachesize 126492 184404 3409920 3624960 0
numfile 770 1596 9312 9312 0
dummy 0 0 0 0 0
dummy 0 0 0 0 0
dummy 0 0 0 0 0
numiptent 21 22 128 128 0
Смысл столбцов:
К первичным параметрам относятся:
Данный параметр определяет максимальное количество процессов и потоков, которые разрешено создать в контейнере.
Единица измерения - 1 процесс (поток). Значения barrier и limit необходимо устанавливать равными.
Очень важно понимать, что процесс в Linux - это достаточно тяжеловесная структура, поэтому необходимо следить за балансом количества процессов в системе. В ядре Linux количество процессов ограничено следующим параметром:
# /proc/sys/kernel/threads-max 32726
Несмотря на то, что величина порядка 30k кажется достаточно большой, на практике такого суммарного количества процессов в системе достичь вряд ли удастся. Поэтому можно не думать о том, что сумма numproc по всем контейнерам должна быть меньше значения threads-max, этот лимит всё равно вряд ли будет достигнут. Считается, что для среднестатистической системы нужно ориентироваться на суммарное количество процессов порядка 8000.
Параметр numproc - это барьер, который защищает систему от лавинообразного создания процессов внутри какого-либо из контейнеров. Например, в случае fork bomb, или же в случае DDoS-атаки на сетевой сервер, создающий процессы на каждое сетевое соединение. В случае, когда количество процессов внутри контейнера достигнет значения numproc, ядро перестанет создавать новые процессы внутри данного контейнера.
Параметр numtcpsock определяет максимальное количество TCP-сокетов (то есть количество обслуживаемых TCP-соединений).
Единица измерения - 1 сокет. Значения barrier и limit необходимо устанавливать равными.
Органичиваем количество сокетов мы по двум причинам:
Ограничивает максимальное количество не-TCP-сокетов.
Единица измерения - 1 сокет. Значения barrier и limit необходимо устанавливать равными.
Под данный параметр попадают все остальные сокеты (не являющиеся TCP) - UDP-сокеты, локальные сокеты (как, например, /tmp/mysql.sock) и иные.
Гарантированная контейнеру память (перед тем, как принять термин «гарантированная память» рекомендую ознакомиться с информацией о выделении памяти контейнерам)
Единица измерения - 1 страница памяти (4 Кб на архитектурах x86 и x86_64)
С помощью данного параметра можно установить объем памяти, который гарантирован контейнеру для выделения из кучи с помощью функции malloc(3) или ей подобных. Для установки данного лимита используется barrier-значение. Например, при установке его в значение 262144 контейнеру будет обещано памяти 262144 * 4Кб = 1 Гб.
Значение limit при этом фактически не используется, его необходимо установить в значение MAX_ULONG
Еще одна интересная особенность данного лимита заключается в том, что он не имеет своего собственного счетчика. Количество страниц памяти, которое в данный момент выделено контейнеру учитывается в счетчике параметра privvmpages
К вторичным параметрам относятся:
Этот важный параметр определяет количество доступной ядерной памяти.
Единица измерения - 1 байт. Между значениями barrier и limit рекомендуется оставлять интервал величиной в 10%
Данный параметр лимитирует тот объем памяти, которое ядро использует для своих внутренних нужд при обслуживании контейнера (например, для хранения дескрипторов процессов, кеширования объектов файловой системы и т.д.). Буферы сокетов в данный лимит не входят, они реализованы отдельно как tcpsndbuf, tcprcvbuf, othersockbuf и dgramrcvbuf
Характерная особенность ядерной памяти в том, что она не выгружается в swap. Поэтому соответствующие структуры данных, выделяемые ядром для своих нужд всегда находятся в RAM. Более того, они находятся не просто в оперативной памяти, а в нижней памяти (low memory). (Рекомендую на этом остановиться подробнее и изучить информацию о нижней памяти проследовав по ссылке).
Общий размер буферов отправки TCP-сокетов
Единица измерения - 1 байт
Эти буферы находятся в нижней памяти . Данный параметр связан с лимитом на количество сокетов numtcpsock, необходимо обеспечить выполнение соотношения ниже, чтобы всем сокетам хватало памяти:
limit(tcpsndbuf) - barrier(tcpsndbuf) >= 2,5 Кб * numtcpsock
Если данное соотношение не выполняется, то некоторые соединения могут без сообщения об ошибке застопориться и позже - быть закрытыми по таймауту. Отправка TCP-пакетов через эти сокеты будет невозможна. Увеличение данного параметра может повысить быстродействие сетевых соединений, однако это вовсе не обязательно, этого ускорения может и не быть.
Общий размер буферов приёма TCP-сокетов
Единица измерения - 1 байт
Эти буферы находятся в нижней памяти . Данный параметр связан с лимитом на количество сокетов numtcpsock, необходимо обеспечить выполнение соотношения ниже, чтобы всем сокетам хватало памяти:
limit(tcprcvbuf) - barrier(tcprcvbuf) >= 2,5 Кб * numtcpsock
Если данное соотношение не выполняется, то некоторые соединения могут без сообщения об ошибке застопориться и позже - быть закрытыми по таймауту. Увеличение данного параметра может повысить быстродействие сетевых соединений, однако это вовсе не обязательно, этого ускорения может и не быть.
Общий размер буферов отправки UDP (и иных протоколов, использующих датаграммы) и буферов локальных сокетов
Единица измерения - 1 байт
Эти буферы находятся в нижней памяти . Данный параметр связан с лимитом на количество прочих сокетов numothersock, необходимо обеспечить выполнение соотношения ниже, чтобы всем сокетам хватало памяти:
limit(othersockbuf) - barrier(othersockbuf) >= 2,5 Кб * numothersock
В достаточной мере большие буферы необходимы для высокой производительности UNIX-сокетов. Однако следует учитывать, что поскольку память для буферов выделяется из нижней памяти - стоит разумно подходить к увеличению значений данного параметра.
Общий размер буферов для временного хранения входящих UDP-пакетов и пакетов других протоколов, использующих датаграммы.
Единица измерения - 1 байт. Значения barrier и limit необходимо устанавливать равными
Данный параметр зависит от количества не TCP-сокетов (numothersock). В большинстве случаев данный параметр не нужно устанавливать в большие значения, только если контейнер должен отправлять и принимать большие датаграммы есть смысл повысить значения barrier для параметров othersockbuf и dgramrcvbuf
В случае, если данный лимит сработал, некоторые входящие датаграммы могут быть не приняты контейнером. Однако, учитывая то, что UDP не является протоколом с гарантированной доставкой, все приложения контейнера, ожидающие приема датаграмм должны быть готовы к тому, что некоторая их часть будет утеряна в процессе доставки.
Не нужно устанавливать значение данного параметра в слишком большие величины - так как память для буферов выделяется из нижней памяти .
Размер гарантированной контейнеру памяти для случаев возникновения на ноде ситуации out-of-memory (OOM)
Единица измерения - 1 страница памяти (4 Кб на архитектурах x86 и x86_64)
Данный параметр очень похож на vmguarpages, но существенно отличается от него ситуацией в которой он применим. Параметр vmguarpages определяет количество гарантированной контейнеру для его приложений памяти, однако, гарантированной лишь в том случае, когда на сервере-ноде нет ситуации OOM.
Так вот, когда мы говорим о параметре oomguarpages, мы говорим о гарантированной контейнеру памяти на случай отсутствия на сервере ситуации OOM. Величина данного лимита определяется по значению barrier. Как и в случае с vmguarpages в качестве limit надо прописать значение MAX_ULONG для текущей архитектуры
Если текущее значение oomguarpages (которое показывает потребление виртуальной памяти процессами внутри контейнера) + текущее потребление ядерной памяти kmemsize + суммарное потребление памяти по всем буферам сокетов tcpsndbuf, tcprcvbuf, othersockbuf и dgramrcvbuf НЕ превышает размеров памяти определенной в barrier параметра oomguarpages, тогда ядро НЕ уничтожит процессы данного контейнера в случае наступления ситуации OOM
Рассмотрим на конкретном примере - возьмем UBC реального контейнера:
# vzctl exec 4463 cat /proc/user_beancounters
Version: 2.5
uid resource held maxheld barrier limit failcnt
4463: kmemsize 2628798 6491433 33554432 33554432 0
oomguarpages 3218 9443 65536 2147483647 0
tcpsndbuf 297480 1935840 8388608 12582912 0
tcprcvbuf 311296 1322044 8388608 12582912 0
othersockbuf 17760 36964 8388608 12582912 0
dgramrcvbuf 0 16728 1048576 1048576 0
... все прочие параметры опущены
16436262 явно меньше 268435456, поэтому процессы данного контейнера будут в безопасности при наступлении ситуации OOM.
Если же есть несколько контейнеров, которые потребляют памяти сверх гарантированного параметром oomguarpages, то в случае наступления ситуации OOM в первую очередь будут уничтожаться процессы на том контейнере, где превышение максимально. Когда ядро будет уничтожать процесс на таком контейнере, оно увеличит failcnt параметра oomguarpages.
Если для какого-то контейнера подобную ситуацию необходимо исключить, единственный вариант - это не давать разрешать ему потреблять памяти более, чем гарантировано по oomguarpages. Для этого надо приравнять к этому гарантированному значению величину параметра privvmpages, что исключит оверселлинг по памяти (и строго говоря, приведет к неэффективному использованию ресурсов)
ВАЖНО! Для того чтобы гарантированная память, действительно была гарантированной - необходимо, чтобы сумма памяти обещанной всем контейнерам по параметрам oomguarpages, kmemsize и буферам tcpsndbuf, tcprcvbuf, othersockbuf и dgramrcvbuf не превышала установленного в сервере объема виртуальной памяти (RAM + swap). В противном случае, в случае наступления ситуации OOM ядро может уничтожать процессы даже на тех контейнерах, где условие гарантированности соблюдается
Верхний лимит памяти, выделяемой контейнеру
Единица измерения - 1 страница памяти (4 Кб на архитектурах x86 и x86_64)
Данный параметр определяет тот максимум виртуальной памяти, которая может быть выделена контейнеру. Данный объем памяти - не гарантирован (конечно, за исключением того случая, когда этот лимит равен oomguarpages).
Счетчик (held) у данного параметра показывает количество памяти, которое выделено приложениям данного контейнера, но, часть этой памяти возможно, еще реально не использована. Таким образом, счетчик privvmpages обычно показывает значение большее, нежели у счетчика oomguarpages, который отражает реальное потребление памяти контейнером
Необходимо обеспечить некоторый интервал между значениями barrier и limit параметра privvmpages. В случае срабатывания barrier, приложение все еще может выделить память до значения limit, но только для случая высокоприоритетных выделений, например, для расширения стека процесса. Для запросов на выделение памяти с нормальным приоритетом процесс получит отказ от ядра OpenVZ.
К дополнительным параметрам относятся:
Страницы памяти процессов, которые не могут быть выгружены в swap (страницы, заблокированные с помощью системного вызова mlock)
Единица измерения - 1 страница памяти (4 Кб на архитектурах x86 и x86_64)
ВАЖНО! Размер этой памяти также учитывается в счетчике kmemsize
Значения barrier и limit можно устанавливать равными друг другу, а можно и оставить интервал между ними - в зависимости от природы приложений, использующих возможности блокировки страниц памяти. Обычные серверные приложения - такого типа как HTTP-, FTP-, почтовые серверы не используют возможности блокировки страниц памяти.
Общий размер разделяемой памяти
Единица измерения - 1 страница памяти (4 Кб на архитектурах x86 и x86_64). Значения barrier и limit необходимо устанавливать равными
Эти страницы также учитываются в счетчике параметра privvmpages
Общее количество страниц оперативной памяти (RAM), используемое процессами данного контейнера
Единица измерения - 1 страница памяти (4 Кб на архитектурах x86 и x86_64). Значения barrier и limit необходимо устанавливать равными
В данный момент данный параметр используется только как счетчик. В будущих релизах OpenVZ данный параметр позволит устанавливать гарантированное количество памяти для приложений, которая выделяется из RAM и не выгружается в swap. А пока что контейнеру можно гарантировать только виртуальную память (RAM+swap), но не оперативную (RAM).
Для совместимости с будущими версиями необходимо значение barrier данного параметра установить в 0, а значение limit - в MAX_ULONG
Максимальное количество одновременно открытых файлов
Единица измерения - 1 файл. Значения barrier и limit необходимо устанавливать равными
Максимальное количество файловых блокировок
Единица измерения - 1 блокировка.
Между значениями barrier и limit необходимо оставить интервал.
Количество псевдотерминалов
Единица измерения - 1 псевдотерминал. Значения barrier и limit необходимо устанавливать равными
Ограничивает количество одновременных shell-сессий. Максимальное количество псевдотерминалов для одного контейнера ограничено значением 256.
Количество структур siginfo
Единица измерения - 1 структура. Значения barrier и limit необходимо устанавливать равными
Объем памяти, занимаемый структурами siginfo в памяти также учитывается в счетчике параметра kmemsize. Обычно в Linux-системах по умолчанию данный лимит установлен в значение 1024 структуры на всю систему, OpenVZ позволяет устанавливать данный лимит для каждого контейнера в отдельности, но при этом очень нежелательно, чтобы у какого-либо из контейнеров данное значение превышало значение по умолчанию (1024). Слишком большие значения лимитов могут уменьшить время отклика системы.
Общий размер структур dentry и inode, удерживаемых в памяти.
Иными словами, данный параметр определяет размер кеша для хранения объектов файловой системы. Размер текущего потребления памяти по данному параметру также учитывается в счетчике параметра kmemsize. Между значениями barrier и limit необходимо предусмотреть интервал. Задача dcachesize как отдельного от kmemsize параметра - ограничить размер кеша для хранения объектов файловой системы с той целью, чтобы при работе со слишком большим количеством таких объектов (например, если открыто слишком много файлов и директорий), сработал лимит dcachesize и возникла ошибка файловых операций, но память по лимиту kmemsize при этом исчерпана бы не была
Максимальное количество правил фаервола NETFILTER
Единица измерения - 1 правило. Значения barrier и limit необходимо устанавливать равными
Не рекомендуется устанавливать данный лимит в слишком большие значения по следующим причинам:
Ядро для собственных нужд выделяет память двумя способами:
Однако, не следует думать, что память выделяемая ядром с помощью vmalloc и память, которая выделяется пользовательскими приложениями - это одно и то же. Они находятся в виртуальной памяти, но, тем не менее, для vmalloc используется собственная область ограниченного размера:
# cat /proc/meminfo | grep Vmalloc VmallocTotal: 118776 kB VmallocUsed: 15996 kB VmallocChunk: 102256 kB
Из-за этим ограничением и обусловлено порожденное ограничение на общее количество правил NETFILTER, которое можно создать. Величина, на которую следует ориентироваться ~250000 правил
Видимый размер swap.
Единица измерения - 1 страница памяти (4 Кб на архитектурах x86 и x86_64)
Параметр, который, определяет - какого размера будет определяться swap внутри контейнера. Фактически не влияет на выделение памяти контейнеру никоим образом, а служит только для отображения нужной величины.
Если swappages установить в MAX_ULONG, то внутри контейнера значения SwapTotal, SwapUsed будут видны как 0
Значение выставляется по величине limit, при этом barrier полностью игнорируется.
Необходимо обеспечить достаточное количество ядерной памяти для ожидаемого количества процессов:
barrier(kmemsize) >= 40 Кб * avnumproc + limit(dcachesize)
Гарантированной памяти не может быть больше лимита:
barrier(privvmpages) >= barrier(oomguarpages)
Размера буферов отправки должно быть достаточно для всех сокетов:
limit(tcpsndbuf) - barrier(tcpsndbuf) >= 2,5 Кб * numtcpsock limit(othersockbuf) - barrier(othersockbuf) >= 2,5 Кб * numothersock
Другие буферы TCP также должны быть достаточных размеров:
limit(tcprcvbuf) - barrier(tcprcvbuf) >= 2,5 Кб * numtcpsock barrier(tcprcvbuf) >= 64 Кб barrier(tcpsndbuf) >= 64 Кб
Буферы UDP должны быть достаточно большими, если это позволяет память:
barrier(dgramrcvbuf) >= 129 Кб barrier(othersockbuf) >= 129 Кб
Количество файлов должно быть адекватно ожидаемому количеству процессов:
numfile >= avnumproc * 32
Размер кеша dcachesize должен быть адекватен количеству файлов
barrier(dcachesize) >= numfile * 384 байт
Для любого параметра limit всегда не меньше barrier:
barrier <= limit