Персональный | |
Почему Google V8 пока не подходит для встраивания в серверы
09.06.2010 Последние время я изучал возможность встроить javascript в nginx с помощью библиотеки Google V8 Javascript Engine, что, надо заметить, было непростой задачей, так как всё, что сложнее классического "Hello World!", в документации отражено крайне отрывочно. Поскольку V8 разрабатывается в первую очередь для Chrome, то это наложило на него существенный отпечаток и, перефразируя высказывание Генри Форда о цвете машины, можно сказать, что V8 будет хорошо работать в любой программе, при условии, что эта программа называется Chrome. Прежде всего, V8 не умеет обрабатывать ошибки выделения памяти он просто завершает процесс. Это приемлемо для такого браузера, как Chrome, который каждую страницу отображает в отдельном процессе, и аварийное завершение одного процесса никак не сказывается на остальных страницах, но для сервера, обрабатывающего в одном процессе тысячи одновременных соединений, это не подходит. И хотя V8 позволяет установить свой обработчик ошибок выделения памяти, тем не менее, сделать в обработчике что-то, отличное от завершение процесса, не представляется возможным. V8 исполняет скрипты внутри контекстов, которые представляют из себя отдельные виртуальные машины. Однако, несмотря на то, что сама концепция контекстов позволяют выполнять несколько скриптов параллельно, V8 поддерживает потоки (threads) только в кооперативном режиме: внутри одного процесса может исполняться только один контекст, остальные в это время должны быть неактивны. В предыдущей редакции статьи я утверждал, что экземпляр внешнего объекта, например, в случае nginx'а это HTTP-запрос, в контексте может быть только один. Это было вызвано тем, что на FreeBSD/i386, где я проводил тесты, V8 падал при попытке использования второго экземпляра объекта. На это же наводила фраза из V8 Embedder's Guide: However you can only have one instance of any template in any given context.Но позже оказалось, что на FreeBSD/amd64 и других платформах несколько экземпляров работают без проблем. Время создания контекста 2 миллисекунды. Конечно, когда контекст создаётся для каждой страницы в браузере, пользователь эти 2 миллисекунды не заметит, но если сервер будет создавать контекст для каждого запроса, то это означает, что он может создать в секунду не более 500 контекстов и, следовательно, не сможет обработать больше 500 запросов в секунду. Кстати, на создание первого контекста уходит больше 20 миллисекунд это связано с тем, что часть V8, например, функции для работы со строками и массивами, написана на javascript'е. А поскольку у Chrome каждый контекст в отдельном процессе первый, то разработчики решили ускорить его создание с помощью snapshot'ов, в которых javascript уже скомпилирован и в этом случае первый контекст создаётся за те же 2 миллисекунды. Для сервера же, наоборот, время создания первого контекста не так критично, гораздо важнее время создания последующих контекстов. V8 использует автоматическую сборку мусора, при этом он сам выбирает моменты для этой процедуры, исходя из того, как это можно лучше сделать в браузере, что не всегда удобно. Впрочем, кое-какой интерфейс для работы со сборкой мусора есть, например, вот так можно вызвать до трёх раз процедуру частичной сборки мусора: for (int i = 0; v8::V8::IdleNotification() && i < 3; i++); Как и Chrome, V8 на данный момент работает только на трёх платформах: i386, amd64 и arm. Это связано с тем, что V8 компилирует javascript сразу в исполняемый код, минуя стадию промежуточного байт-кода. Кстати, первоначально поддержки amd64 не было, она появилась только летом 2009 года. Впрочем, поскольку разработчики V8 работают на обычных x86 компьютерах, то для ускорения отладки кода, который V8 компилирует для архитектуры arm, был написан симулятор arm, который позволяет выполнять код arm на любой платформе. Теоретически этот симулятор можно было бы использовать и для любой неподдерживаемой специальным образом платформы. Подытоживая вышеописанное, можно сказать, что на данный момент (версия 2.0.6.4, февраль 2010 года) V8 не подходит для серьёзного встраивания в серверы. Возможно, это положение постепенно изменится например, летом 2009 года разработчики добавили метод v8::Script::New для компиляции контекстно независимых скриптов, а до этого скрипт был привязан к контексту, в котором он был скомпилирован, что подходит для браузера, который компилирует скрипт и затем однократно его выполняет и совсем не подходит для серверов, которые исполняют один и тот же скрипт тысячи раз в секунду в разных контекстах. (C) Игорь Сысоев |