Введение в мультиарендность для виртуальных машин Java

Новая функция для облачных систем в бета-релизе IBM Java 8

Функция IBM Multitenant JVM стала доступной в рамках недавнего релиза IBM Java™ 8 beta. Исполнение нескольких приложений внутри одной мультиарендной виртуальной машины JVM позволяет облачной системе ускорить запуск приложений и уменьшить занимаемое ими пространство памяти. В предлагаемой статье представляется технология, лежащая в основе облачной мультиарендной JVM, а также рассматриваются основные издержки и выгоды при ее использовании.

Грэм Джонсон, менеджер по разработке J9 Virtual Machine, IBM

 x 

Photo of Graeme JohnsonГрэм Джонсон (Graeme Johnson) является менеджером по разработке и техническим руководителем группы IBM J9 Virtual Machine (J9 JVM). Он занимается созданием виртуальных машин и отладчиков с момента своего прихода в IBM в 1994 году из компании Object Technology International. Он имеет опыт работы с такими средами исполнения, как VisualAge for Java и IBM/OTI Smalltalk. В последнее время Джонсон сосредоточил свои усилия на проекте Apache Harmony и на поддержке среды исполнения Java/PHP для проекта IBM Project Zero. Джонсон регулярно выступает на конференциях по различным темам, в том числе по проекту Apache Harmony (конференция JavaOne 2006), по многоплатформенной разработке на C (конференция EclipseCon 2007) и по исследованию среды исполнения PHP (конференция International PHP 2006).



Майкл Доусон, разработчик программного обеспечения, IBM

 x 

Photo of Michael DawsonМайкл Доусон (Michael Dawson) на протяжении последних девяти лет работает в группе J9 JVM, где занимался реализацией базовых компонентов JVM. За это время он внес существенный вклад в развитие IBM Java, включая WebSphere Real Time, а также релизы Java 6 и Java 7 для различных платформ. В последние несколько лет он занимается облачными и виртуализационными решениями IBM для технологии Java. В прошлом он занимал руководящие должности в группах по созданию приложений электронной коммерции и по представлению этих приложений в качестве сервисов (коммуникационные сервисы электронного обмена данными (EDI), процессинг кредитных карт, онлайновые аукционы, электронное выставление счетов и т. д.).



03.02.2014

Поставщикам облачных сервисов необходимо сопоставлять затраты на инфраструктуру, которая требуется для функционирования системы и предоставления этих сервисов, с получаемыми в результате выгодами. Необходимость сопоставления затрат и выгод побуждает поставщиков рассматривать различные архитектуры. Возможные варианты охватывают спектр от архитектур без совместного использования до совместно используемых архитектур с несколькими арендаторами. В варианте без совместного использования поставщик предлагает аппаратные средства, программное обеспечение и приложения, полностью выделенные отдельным клиентам. В варианте мультиаренды с совместным использованием приложения нескольких клиентов поддерживаются средствами единственного приложения, а все обеспечивающие аппаратные и программные средства используются совместно.

Основной компромисс в вышеупомянутом архитектурном спектре — это компромисс между изоляцией и плотностью. Плотность определяется количеством систем и сервисов, которые могут быть предоставлены с помощью определенного набора аппаратных и программных средств. Чем больше ресурсов используется совместно, тем выше плотность. Повышение плотности снижает затраты поставщика. Одновременно с этим увеличение масштабов совместного использования уменьшает уровень изоляции между арендаторами — отдельными системами или сервисами, которые предоставляются клиентам. Изоляция характеризует степень, в которой один из арендаторов способен влиять на действия и данные других арендаторов.

Для Java-арендаторов в архитектурном спектре имеется две позиции –JVM-машины с совместным использованием или JVM-машины без совместного использования. В любой архитектуре, в которой приложение верхнего уровня используется совместно, JVM-машина должна быть совместно используемой. Совместное использование JVM экономит ресурсы памяти и процессорные ресурсы. Однако в случае традиционной технологии JVM совместное использование JVM-машины в общем случае устраняет на уровне инфраструктуры любую остававшуюся на нем изоляцию, в результате чего эту изоляцию должно обеспечивать само приложение верхнего уровня. В данной статье описывается функциональность мультиарендности, представленная для пробного использования в последнем релизе Java 8 beta от IBM (см. раздел Ресурсы). Эта опция позволяет при развертывании воспользоваться преимуществами совместного использования JVM-машины, но при этом поддерживает более высокий уровень изоляции, чем можно достигнуть при совместном использовании традиционной JVM-машины.

Издержки и выгоды мультиарендной JVM

Основное преимущество мультиарендной JVM состоит в отсутствии потребления памяти, которое обычно имеет место при развертывании с использованием нескольких стандартных JVM. Эти накладные расходы в виде потребления памяти обусловлены несколькими причинами.

  • Куча Java потребляет сотни мегабайт памяти. Объекты кучи не могут совместно использоваться несколькими JVM-машинами, даже если эти объекты идентичны. Более того, JVM-машины имеют тенденцию использовать всю выделенную им кучу, даже если пиковый объем памяти требуется им лишь на протяжении короткого промежутка времени.
  • JIT-компилятор (Just-in-time) потребляет десятки мегабайт памяти, поскольку генерируемый им код является приватным и потребляет память. Кроме того, генерация этого кода требует существенных процессорных ресурсов, которые отбираются у приложений.
  • Внутренние артефакты для классов (многие из которых, такие как String и Hashtable, существуют для всех приложений) потребляют память. Для каждой JVM-машины существует по одному экземпляру каждого из этих артефактов.
  • По умолчанию каждая JVM имеет по одному потоку хелпера-сборщика мусора на каждое ядро, а также несколько потоков компиляции. Действия в сфере компиляции или сборки мусора могут происходить одновременно в одной или в нескольких JVM, что приводит к снижению оптимальности, поскольку JVM-машины конкурируют за ограниченное процессорное время.

Помимо снижения затрат на память и на обработку мультиарендная JVM-машина обеспечивает более высокий уровень изоляции, чем исполнение нескольких приложений в одной традиционной JVM-машине.

Другое преимущество состоит в том, что после запуска первого арендатора в совместно используемой JVM-машине на запуск последующих приложений требуется меньше времени, поскольку JVM-машина уже работает. Ускорение запуска особенно полезно для приложений с малой продолжительностью работы, которые часто используются для исполнения скриптов.

Основные издержки при использовании мультиарендной JVM обусловлены меньшей степенью изоляции арендаторов, чем при исполнении нескольких приложений в отдельных JVM. Например, катастрофический отказ в мультиарендной JVM-машине затронет всех ее арендаторов.

Кроме того, имеет место некоторая потеря производительности вследствие того, что JVM-машина должна выполнять определенную работу по поддержке мультиарендных расширений. Однако это снижение производительности уменьшается по мере увеличения количества арендаторов — поскольку мы избегаем издержек на процессоры и на память в результате исполнения нескольких JVM-машин в одной системе.


Использование мультиарендной JVM

Чтобы использовать вариант с совместным использованием среды исполнения вместе с другими арендаторами, пользователь приложения при его запуске добавляет к командной строке один аргумент -Xmt. Пример:

java -Xmt -jar one.jar

В результате приложение будет вести себя точно так же (с учетом ограничений, которые мы опишем ниже), как при исполнении на выделенной JVM-машине. Однако в действительности оно исполняется вместе с другими приложениями. Расширения в мультиарендной JVM делают возможным такой способ исполнения и обеспечивают изоляцию между арендаторами, которые совместно используют одну и ту же JVM-машину.

После запуска арендатора модуль запуска JVM-машины (JVM launcher) определяет местоположение демона совместно используемой JVM-машины (javad) или запускает его в случае необходимости (см. рис. 1).

Рисунок 1. Модуль запуска JVM автоматически находит (и в случае необходимости, запускает) демон совместно используемой JVM-машины
Screen capture and diagram represents the JVM launcher locating and starting the shared JVM daemon (javad)

При запуске второго арендатора этот арендатор находит демон существующей совместно используемой JVM-машины и исполняется в этой JVM-машине (см. рис. 2).

Рисунок 2. JVM launcher находит демона существующей JVM-машины и подключается к нему
Screen capture and diagram represents the JVM launcher locating and connecting to the existing JVM daemon (javad)

Результат состоит в том, что в процессе javad "живет" одна копия кода начальной загрузки (bootstrap), которая является общей для обоих арендаторов. Такая организация позволяет арендаторам совместно использовать большую часть структур среды исполнения.

Запуск существующих приложений с использованием мультиарендной JVM осуществляется весьма просто – требуются лишь некоторые изменения в командной строке.


Реализация изоляции

В нормальных условиях два или несколько приложений, работающие в одной и той же (обычной) JVM-машине, не изолированы друг от друга. Деятельность каждого такого приложения будет оказывать влияние на возможности другого приложения. Кроме того, данные, доступные для совместного использования через статические поля, будут доступны всем приложениям. В режиме мультиарендной JVM эти проблемы решаются следующими двумя способами: изоляция статических полей и ограничение ресурсов.

Изоляция статических полей

В мультиарендной JVM арендаторы совместно используют инвариантные части классов. К числу этих частей относятся: скомпилированный код для методов, структуры данных, которые использует JVM-машина, а также другие подобные артефакты. Такое совместное использование обеспечивает экономию памяти, поскольку отпадает необходимость в отдельных копиях этих частей, которые существовали бы в случае использования нескольких JVM. В то же время мультиарендная JVM предоставляет каждому арендатору собственную копию статических полей. Вследствие изоляции статических полей — а также того факта, что каждый арендатор в общем случае может получить доступ лишь к тем экземплярам объектов, которые он сам создал, — каждый арендатор имеет возможность обращаться только к тем данным, которые ассоциированы именно с ним. Результатом является изоляция данных между арендаторами.

Ограничение ресурсов: противодействие плохому поведению

В совершенном мире арендаторы сотрудничают друг с другом и используют общие ресурсы надлежащим образом. Однако в реальном несовершенном мире могут иметь место ошибки и злонамеренные действия. Опция мультиарендной JVM предоставляет параметры управления, которые можно сконфигурировать на ограничение возможностей арендатора по неправильному поведению и по использованию ресурсов в режимах, затрагивающих других арендаторов. В частности, предоставляется контроль над значениями следующих параметров:

  • Процессорное время
  • Размер кучи
  • Количество потоков
  • Ввод/вывод файлов: пропускная способность по чтению, пропускная способность по записи
  • Ввод/вывод сокета: пропускная способность по чтению, пропускная способность по записи

Эти параметры управления можно задать в командной строке с аргументом -Xmt. Примеры.

  • -Xlimit:cpu=10-30 (процессорное время: 10% минимум, 30% максимум)
  • -Xlimit:cpu=30 (процессорное время: 30% максимум)
  • -Xlimit:netIO=20M (пропускная способность: 20 Мбит/с максимум)
  • -Xms8m-Xmx64m • (куча: 8 МБ исходные размеры, 64 МБ максимум)

Документация по Java 8 содержит информацию по всем доступным параметрам (см. раздел Ресурсы).


Производительность и потребление ресурсов

В качестве теста для сравнения производительности приложений и потребления памяти в случае JVM-машин без совместного использования и при мультиарендной JVM-машине мы добавляем приложения в каждую конфигурацию JVM вплоть до момента, когда система начинает осуществлять подкачку (когда это происходит, мы считаем, что система "заполнена"). В варианте без совместного использования мы исполняем каждое приложение в отдельной JVM-машине и запускаем новую JVM-машину для каждого дополнительного приложения. В случае мультиарендной JVM мы исполняем каждое приложение в качестве отдельного арендатора в одной мультиарендной JVM.

В таблице 1 и таблице 2 показаны результаты, полученные при использовании машины с 1 ГБ памяти и с 64-разрядной JVM (JVM-машина со сжатыми ссылками, со сбалансированной политикой сборки мусора во всех экземплярах). Столбец Ручная настройка в обеих таблицах демонстрирует результаты использования обычной JVM-машины после того, как мы в ручном режиме настроили параметры командной строки на достижение максимально возможной плотности (таблица 1) или максимально возможной скорости запуска (таблица 2). В столбце По умолчанию показаны результаты для обычной JVM-машины с опциями по умолчанию.

У мультиарендной JVM-машины плотность в 1,2 – 4,9 раза выше, чему у JVM без совместного использования в зависимости от конкретного приложения (таблица 1).

Максимальное количество одновременно исполняемых приложений
ПриложениеОписаниеМультиаренднаяРучная настройкаПо умолчаниюУлучшение в случае мультиарендной JVM
Hello World Печатает слова HelloWorld, а затем засыпает3097363В 4,2 – 4,9 раз
JettyЗапускает Jetty и ждет запросов34-18В 1,9 раза
TomcatЗапускает Tomcat и ждет запросов28-13В 2,1 раза
JRubyЗапускает JRuby и ждет запросов322615В 1,2 – 2,1 раз

Увеличение плотности является результатом совместного использования ключевых артефактов:

  • Классы и связанные артефакты, загружаемые при начальной загрузке и при загрузке классов расширения; объект кучи Class для каждого класса, загружаемого соответствующим загрузчиком; объекты кучи, которые арендаторы могут безопасно использовать в совместном режиме (например, интернированные объекты String).
  • Скомпилированный JIT-компилятором код и метаданные для скомпилированных JIT-компилятором классов.
  • Куча: один арендатор может использовать все пространство, доступное в куче, если оно не требуется другим арендаторам.

В таблице 2 показано, что в случае мультиарендной JVM мы в 1,2 – 6 раз сократили среднюю продолжительность запуска.

Таблица 2. Продолжительность запуска (первый запуск/в среднем)
ПриложениеОписаниеМультиаренднаяРучная настройкаПо умолчаниюУлучшение в случае мультиарендной JVM
Hello WorldПечатает слова HelloWorld, а затем засыпает5709/138 мс514/400 мс3361/460 мсВ 3,3 раза
JettyЗапускает Jetty и ждет запросов7478/2116 мс-6296/12624 мсВ 6 раз
TomcatЗапускает Tomcat и ждет запросов9333/6005 мс-7802/7432 мсВ 1,2 раза
JRubyЗапускает JRuby и ждет запросов12391/3277 мс14847/4101 мс7849/6058 мсВ 1,25 – 1,8 раза

Как показано в таблице 2, продолжительность запуска первого экземпляра приложения на мультиарендной JVM в общем случае больше, чем на стандартной JVM. Этот результат является вполне ожидаемым, поскольку при запуске первого экземпляра имеется определенная дополнительная задержка вследствие удлинения процедуры, связанной с мультиарендными расширениями. Продолжительность запуска у всех последующих экземпляров в мультиарендной JVM оказалась меньше.

Эти первые результаты получены с использованием JVM-машин, находящихся в стадии разработки; поэтому со временем они будут дополнительно улучшены. Более того, эти примеры не распространяются на совместное использование в тех случаях, когда приложения нуждаются в ресурсах в разные моменты времени. В типичной JVM-среде занимаемое пространство памяти для каждой JVM-машины имеет тенденцию к росту вплоть до максимального значения, который требуется ей на протяжении жизненного цикла. В стандартной JVM большая часть этого пространства не используется совместно. В случае мультиарендной JVM – при условии, что потребности в ресурсах не перекрываются – совместное использование памяти для кучи и для собственных артефактов существенно упрощается.


Ограничения

Одна из целей разработки мультиарендной JVM — предоставить возможность запуска всех Java-приложений без их модификации. На данный момент это невозможно вследствие ограничений, налагаемых спецификациями Java, и ограничений в нашей текущей реализации. Важнейшие известные ограничения:

  • Интерфейс JNI (Java Native Interface) и нативные артефакты. Опция multitenant JVM не обеспечивает изоляцию для т.н. нативных артефактов при использовании интерфейса JNI. Приложения с предоставленными пользователем JNI-вызовами не могут безопасно исполняться на мультиарендной JVM-машине. Такие приложения способны влиять на функционирование всей JVM и на доступ к данным со стороны других арендаторов. В случае, когда к нативным артефактам имеется достаточная степень доверия (например, речь идет об известном программном продукте связующего уровня), этот риск может оказаться приемлемым. Кроме того, операционная система позволяет процессу совместно используемой JVM-машины загружать только одну копию совместно используемой библиотеки, в которой расположены нативные артефакты. В результате несколько арендаторов не смогут загружать одни и те же нативные артефакты, если те находятся в одной совместно используемой библиотеке.
  • Интерфейс JVMTI (Java Virtual Machine Tool Interface). Поскольку деятельность по отладке и профилированию влияет на всех арендаторов, совместно использующих соответствующий JVM-сервер, эти функции в настоящий момент не поддерживаются в мультиарендном JDK. Мы планируем продолжить работу в этом направлении.
  • Программы для поддержки графических интерфейсов пользователя. Библиотеки, такие как SWT, поддерживают глобальное состояние на нативном уровне и, соответственно, не могут быть задействованы в мультиарендном JDK.

Заключение

В данной статье была представлена мультиарендная JVM-машина (multitenant JVM), описан порядок ее использования и рассмотрены сопряженные с таким использованием издержки и выгоды. Мы надеемся, что вас заинтересует эта тематика и что вы испытаете бета-релиз IBM Java 8 и сообщите нам свое мнение. Мы уверены в том, что мультиарендная JVM-машина может дать существенные преимущества при использовании в соответствующих средах.

Ресурсы

Научиться

Получить продукты и технологии

Обсудить

  • Присоединяйтесь к сообществу developerWorks . Связывайтесь с другими пользователями developerWorks и знакомьтесь с ориентированными на разработчиков форумами, блогами, группами и вики-ресурсами.

Комментарии

developerWorks: Войти

Обязательные поля отмечены звездочкой (*).


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Профиль создается, когда вы первый раз заходите в developerWorks. Информация в вашем профиле (имя, страна / регион, название компании) отображается для всех пользователей и будет сопровождать любой опубликованный вами контент пока вы специально не укажите скрыть название вашей компании. Вы можете обновить ваш IBM аккаунт в любое время.

Вся введенная информация защищена.

Выберите имя, которое будет отображаться на экране



При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Обязательные поля отмечены звездочкой (*).

(Отображаемое имя должно иметь длину от 3 символов до 31 символа.)

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Вся введенная информация защищена.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Технология Java, Облачные вычисления
ArticleID=964555
ArticleTitle=Введение в мультиарендность для виртуальных машин Java
publish-date=02032014