Перевод. Оригинал статьи http://in.relation.to/Bloggers/WhyIsJBossAS7SoFast. Статье скоро год, но вопрос все еще актуален.
Если кратко, то ответ следующий: потому что вся проектировка JBoss AS 7 строится на основе закона Эмдейла (эффективная параллелизация задач) в противоположность закону Мура (ждать железа с большей частотой процессора). Почти каждый процессор на вооружении настольных компьютеров, ноутбуков и серверов сегодня имеет не менее двух ядер, при чем тенденция быстро растет. Дни гонок за частотой процессора уже в прошлом. Так что, программам приходится адаптироваться, чтобы выжать все из того железа, что есть сейчас и будет завтра.
Чтобы добиться такой переломной эволюции, JBoss AS подвергся агрессивной трансформации. В AS 7 мы начали с чистого листа и с нуля построили совершенно новую, высокопроизводительную и хорошо управляемую архитектуру ядра. С помощью поистине удивительных инженерных работ мы смогли прийти от крохотного прототипа на Гитхабе к полномасштабной реализации Веб-профиля контейнера Java EE за какой-то год с лишним (не говоря уже о том, что в течение этого времени мы также выпусили AS 6, который предоставил пользователям JBoss ранний доступ к технологиям EE6).
Прежде чем объяснить, позвольте сделать небольшой отступ. Основная задача сервера приложений — это управление службами. Почти все компоненты современных приложений имеют некий цикл жизни, то есть в какой-то момент компонента должна быть запущена, а позднее остановлена. Все что имеет жизненный цикл мы помечаем как службу. Другое важное свойство служб в том, что обычно они имеют взаимосвязи, соответственно влияющие на их циклы жизни. Для примера, можно сказать, что работа сервлета зависит от веб-сервера. В добавку, можно предположить что если сервлет использует какой-либо другой ресурс, скажем подключение к базе данных или EJB, то он также зависит от их доступности. Когда сервер приложений запускается или развертывает приложение, он должен убедиться, что различные службы запустятся в правильной последовательности. Далее, если какая-либо из этих служб каким-то образом остановлена, он должен сперва остановить все что зависит от данной службы (по-сути в обратном порядке). Это довольно простая задача, если делать в одном треде.
С другой стороны, JBoss AS 7 запускает и развертывает все сервисы параллельно. Эта сложная задача решается нашим новым модульным контейнером сервисов — JBoss Modular Service Container. MSC по-сути есть продвинутый параллельный автомат. Он анализирует зависимости между всеми сервисами на лету и пытается запустить как можно больше сервисов одновременно, соблюдая требования по взаимосвязям. Это дает нам не только быстрый старт, но и возможность параллельного развертывания нескольких приложений.
Вдобавок к параллельным сервисам, JBoss AS 7 также обладает модульностью и параллельной подгрузкой классов. Раскладывая классы в соответствующие модули сервер приложений может естественным образом оптимизировать доступ к классам и искать только там, где этот класс действительно находится. Так как видимость между модулями намеренно ограничена, операция поиска обходится дешево. В случае с JBoss Modules, разрешение модулей и поиск класса происходит за O(1). Все это работает на очень высоком уровне параллелизма, включая существенную часть разбора структуры классов.
Обработка деплойментов также очень эффективна. Важнейшая оптимизация в том, что мы индексируем информацию об аннотациях быстро сканируя часть данных о классах. Для еще большей эффективности мы позволяем модулям заранее сгенерировать компактный индекс, спроектированный для скорой подгрузки. И еще одна оптимизация развертки в том, что мы аккуратно кэшируем и повторно используем данные о структуре классов.
В заключение, последняя оптимизация, которую хотелось бы подчеркнуть — мы были и будем очень строги к нагрузке на CPU и память при старте и развертке. Все это исходит от выбора правильных решений на фазе проектировки. Интересный пример из таких решений — наш мораторий на использование JAXB (и любого другого компоновщика на основе introspection [1]) для разбора конфигурации, считываемой всего лишь раз. Прежде чем приступить непосредственно к разбору конфигурации, JAXB тратит столько же, если не больше, времени на то чтобы понять как делать этот самый разбор. И так везде. Фактически, только разбор XML в AS 5 и 6 занимал времени больше чем подъем всего AS 7.
Надеюсь, это даст более ясную картину того, как мы добились такого выйгрыша производительности, и почему некоторые вещи в AS 7 так сильно отличаются от предыдущих версий. Это, впрочем, только начало. Ждите мой следующий блогпост, в котором мы поговорим о дальнейшем плане развития AS 7.
Спасибо!
[1] Не нашел приемлемого перевода, в оригинале: introspection driven binder — думаю, имеется ввиду десериализатор XML, которой сперва разбирает XMLSchema документа, чтобы понять типы данных, и только потом начинает саму десериализацию.
Если кратко, то ответ следующий: потому что вся проектировка JBoss AS 7 строится на основе закона Эмдейла (эффективная параллелизация задач) в противоположность закону Мура (ждать железа с большей частотой процессора). Почти каждый процессор на вооружении настольных компьютеров, ноутбуков и серверов сегодня имеет не менее двух ядер, при чем тенденция быстро растет. Дни гонок за частотой процессора уже в прошлом. Так что, программам приходится адаптироваться, чтобы выжать все из того железа, что есть сейчас и будет завтра.
Чтобы добиться такой переломной эволюции, JBoss AS подвергся агрессивной трансформации. В AS 7 мы начали с чистого листа и с нуля построили совершенно новую, высокопроизводительную и хорошо управляемую архитектуру ядра. С помощью поистине удивительных инженерных работ мы смогли прийти от крохотного прототипа на Гитхабе к полномасштабной реализации Веб-профиля контейнера Java EE за какой-то год с лишним (не говоря уже о том, что в течение этого времени мы также выпусили AS 6, который предоставил пользователям JBoss ранний доступ к технологиям EE6).
Прежде чем объяснить, позвольте сделать небольшой отступ. Основная задача сервера приложений — это управление службами. Почти все компоненты современных приложений имеют некий цикл жизни, то есть в какой-то момент компонента должна быть запущена, а позднее остановлена. Все что имеет жизненный цикл мы помечаем как службу. Другое важное свойство служб в том, что обычно они имеют взаимосвязи, соответственно влияющие на их циклы жизни. Для примера, можно сказать, что работа сервлета зависит от веб-сервера. В добавку, можно предположить что если сервлет использует какой-либо другой ресурс, скажем подключение к базе данных или EJB, то он также зависит от их доступности. Когда сервер приложений запускается или развертывает приложение, он должен убедиться, что различные службы запустятся в правильной последовательности. Далее, если какая-либо из этих служб каким-то образом остановлена, он должен сперва остановить все что зависит от данной службы (по-сути в обратном порядке). Это довольно простая задача, если делать в одном треде.
С другой стороны, JBoss AS 7 запускает и развертывает все сервисы параллельно. Эта сложная задача решается нашим новым модульным контейнером сервисов — JBoss Modular Service Container. MSC по-сути есть продвинутый параллельный автомат. Он анализирует зависимости между всеми сервисами на лету и пытается запустить как можно больше сервисов одновременно, соблюдая требования по взаимосвязям. Это дает нам не только быстрый старт, но и возможность параллельного развертывания нескольких приложений.
Вдобавок к параллельным сервисам, JBoss AS 7 также обладает модульностью и параллельной подгрузкой классов. Раскладывая классы в соответствующие модули сервер приложений может естественным образом оптимизировать доступ к классам и искать только там, где этот класс действительно находится. Так как видимость между модулями намеренно ограничена, операция поиска обходится дешево. В случае с JBoss Modules, разрешение модулей и поиск класса происходит за O(1). Все это работает на очень высоком уровне параллелизма, включая существенную часть разбора структуры классов.
Обработка деплойментов также очень эффективна. Важнейшая оптимизация в том, что мы индексируем информацию об аннотациях быстро сканируя часть данных о классах. Для еще большей эффективности мы позволяем модулям заранее сгенерировать компактный индекс, спроектированный для скорой подгрузки. И еще одна оптимизация развертки в том, что мы аккуратно кэшируем и повторно используем данные о структуре классов.
В заключение, последняя оптимизация, которую хотелось бы подчеркнуть — мы были и будем очень строги к нагрузке на CPU и память при старте и развертке. Все это исходит от выбора правильных решений на фазе проектировки. Интересный пример из таких решений — наш мораторий на использование JAXB (и любого другого компоновщика на основе introspection [1]) для разбора конфигурации, считываемой всего лишь раз. Прежде чем приступить непосредственно к разбору конфигурации, JAXB тратит столько же, если не больше, времени на то чтобы понять как делать этот самый разбор. И так везде. Фактически, только разбор XML в AS 5 и 6 занимал времени больше чем подъем всего AS 7.
Надеюсь, это даст более ясную картину того, как мы добились такого выйгрыша производительности, и почему некоторые вещи в AS 7 так сильно отличаются от предыдущих версий. Это, впрочем, только начало. Ждите мой следующий блогпост, в котором мы поговорим о дальнейшем плане развития AS 7.
Спасибо!
[1] Не нашел приемлемого перевода, в оригинале: introspection driven binder — думаю, имеется ввиду десериализатор XML, которой сперва разбирает XMLSchema документа, чтобы понять типы данных, и только потом начинает саму десериализацию.