Tuesday, January 25, 2011

Особенности выделения памяти под OpenVZ для java-приложений

OpenVZ как система виртуализации хороша тем, что позволяет легко балансировать ресурсы хост-системы между своими контейнерами (что, по сравнению с тем же Xen'ом, является явным преимуществом). Однако, у неё, конечно, есть и недостатки. Одним из них является отсутствие явной поддержки swap'а.

Сам по себе swap на хост-системе вы использовать, естественно, можете. Но вот внутри контейнера процессам он будет недоступен. Другими словами, выделяя память под контейнер (параметр privvmpages), вы должны учитывать, что её объём должен быть не меньше всей потенциально необходимой вашим процессам памяти.

Отдельное внимание в рамках данного вопроса стоит обратить на java-приложения. В случае, если ваша программа вызывает множество внешних процессов (ярким примером такой программы будет Maven), вам стоит быть готовым, что для его работы потребуется гораздо больше памяти, чем кажется на первый взгляд.
Происходит это из-за того, что каждый вызов внешнего приложения в java (Runtime.getRuntime().exec()) сводится к системному вызову fork() linux'a c последующим замещением кода дочернего процесса. При fork'e дочернему процессу выделяется тоже количество памяти, что и родительскому. Не смотря на то, что в современных ядрах системный вызов fork() сводиться к системному вызову clone(), а, следовательно, должен реализовывать механизм Copy-On-Write, для java-приложений это не играет роли в виду особенностей инициализации памяти в JVM. Таким образом, если вы запускаете приложение, которому необходимо 40Мб, и это приложение делает 10 вызовов внешних приложений, то для того, что бы не получить java.io.IOException: error=12, Cannot allocate memory, вам потребуется выделить для openvz-контейнера минимум 40 + 40*10 = 440Мб.

Поэтому, при нехватке памяти под OpenVZ, первым делом следует посмотреть текущее значение параметра privmpages для контейнера с помощью команды cat /proc/user_beancounters, вторым - увеличить его значение в конфиге контейнера до нужного объёма.

P.S.
Кстати, в ходе своих изысканий наткнулся на один довольно интересный параметр ядра Linux - overcommit_memory (cat /proc/sys/vm/overcommit_memory), с помощью которого можно регулировать политику выделения памяти в системе. По-умолчанию ядро может выделить процессу большее количество памяти, чем реально у него есть (с учётом swap'a). Но это уже совсем другая история.

1 comment:

  1. Добрый день.
    Спасибо за статью, она оказалась очень полезной для меня. Такой эффект наблюдаю на своем VPS с OS Debian 5. Может быть вы знаете как можно настроить систему чтобы дочернему процессу не выделялось памяти столько же как основному? А то запускаю например Tomcat, выделяю ему 64 мб, а использует он как минимум 256 :(. Можно чтото с этим сделать, или лучше вобще сменить тип виртуализации если нужно запускать Java приложения?

    ReplyDelete