Зачем нужен Node.js? Возрастающая популярность JavaScript повлекла за собой множество изменений, в том числе и в том, что собой представляет современная веб-разработка. Перед тем как углубиться в Node.js, вам, вероятно, будет интересно узнать о преимуществах использования JavaScript в стеке, в котором объединен язык и текстовый формат данных (JSON).
Так как это по большей части преимущество JavaScript в целом, а не Node.js, мы не будем на этом останавливаться. Тем не менее, это главный аргумент в пользу внедрения Node в ваш стек. Перед тем как мы перейдем к cамой статье, рекомендую вглянуть на один из самых лучших курсов по Node.js на сегодняшний день.
Из статьи в Википедии становится понятно, что Node.js это программный пакет, основанный на JavaScript-движке Google V8. Он включает уровень абстракции платформы – библиотеку libuv, и базовую библиотеку, которая сама главным образом написана на JavaScript. Кроме того, стоит отметить, что создатель Node.js Райан Даль намеревался создавать сайты, работающие в реальном времени с технологией push, вдохновившись такими приложениями, как Gmail. В Node.js он предоставил разработчикам инстумент для работы с парадигмой неблокирующего событийно-ориентированного ввода/вывода.
«Спустя больше 20 лет существования парадигмы «веб-приложения без запоминания состояния на базе соединения запрос-отклик без запоминания состояния», у нас наконец появились веб-приложения с двунаправленными соединениями в реальном времени.»
Зачем нужен Node.js
Если коротко, то Node.js блистательно себя показывает в веб-приложениях реального времени, используя технологию push в веб-сокетах. Что же здесь такого инновационного? Спустя более 20 лет существования парадигмы «веб-приложения без запоминания состояния на базе соединения запрос-отклик без запоминания состояния», у нас наконец появились веб-приложения с двунаправленными соединениями в реальном времени, в которых связь может быть инициирована клиентом или сервером, что позвляет им свободно обмениваться данными. Такой подход резко контрастирует с традиционной парадигмой веб-откликов, в которой связь всегда инициирует клиент. Кроме того, она основана на открытом веб-стеке (HTML, CSS и JS), работающем через стандартный порт 80.
Кто-то скажет: «Но ведь уже несколько лет по такому же принципу работают Flash- и Java-апплеты». В действительности они были реализованы на базе сред песочниц, в которых Веб использовался в качестве транспортного протокола для доставки клиенту. Вдобавок к этому, они работали изолированно и, чаще всего, через нестандартные порты, для которых были необходимы дополнительные права доступа и так далее.
Благодаря всем своим преимуществам Node.js играет важнейшую роль в технологическом стеке многих именитых компаний, которые широко используют его ключевые преимущества. Сообщество Node.js Foundation собрало основые доводы относительно того, почему компаниям стоит присмотреться к Node.js, и объединило их в небольшую презентацию, с которой можно ознакомиться здесь.
В этой статье я расскажу не только о том, как реализованы эти преимущества, но и о том, для чего стоит или не стоит использовать Node.js. И сделаю я это на примере некоторых классических моделей веб-приложений.
Зачем нужен Node.js — Как это работает?
Основная идея Node.js заключается в использовании неблокирующего событийно-ориентированного ввода/вывода, чтобы оставаться легковесным и эффективным при работе с приложениями, обрабатывающими большие объемы данных в реальном времени и работающими на распределенных устойствах. Звучит довольно сложно, да?
«На самом деле это значит, что Node.js НЕ является универсальной платформой для любых задач, которая станет передовой на рынке веб-разработки. Совсем наоборот – это платформа для конкретных целей.»
На самом деле это значит, что Node.js НЕ является универсальной платформой для любых задач, которая станет передовой на рынке веб-разработки. Совсем наоборот – это платформа для конкретных целей. И это очень важно понимать. Node.js определенно не стоит использовать для операций с интенсивной вычислительной нагрузкой на центральный процессор. Такого рода применение сведет на нет все его преимущества. Зато Node отлично себя покажет при построении быстрых масштабируемых сетевых приложений, поскольку он может одновременно обрабатывать большое количество соединений с большой пропускной способностью, что равноценно высокой масштабируемости.
То, как это работает изнутри, заслуживает особого внимания. В отличие от традиционных веб-сервисов, в которых каждое соединение (запрос) создает новый поток, используя при этом системную оперативную память и в конечном счете выжимая максимум из всего доступного объема памяти, Node.js работет на базе одного потока и использует при вызовах неблокирующий ввод/вывод, что позволяет ему поддерживать десятки тысяч одновременных соединений (хранящихся в цикле событий).
Зачем нужен Node.js
Вот, навскидку простой пример: представьте, что каждый поток может затребовать 2 Мб памяти, а объем оперативной памяти всей системы составляет 8 Гб. Теоретически максимальное количество одновременных соединений составляет 4000 (данные расчета взяты из статьи Майкла Абернети «Что именно собой представляет Node.js?», опубликованной на ресурсе IBM для разработчиков «IBM developerWorks» в 2011 году; к сожалению, статьи больше нет в свободном доступе), плюс затраты на переключение контекста между потоками. Обычно с таким сценарием приходится сталкиваться при использовании традиционных веб-сервисов. Node.js позволяет избежать всего этого и добиться уровня масштабируемости свыше миллиона одновременных соединений и свыше 600 тысяч одновременных соединений веб-сокетов.
Конечно, открытым остается вопрос распределения единственного потока между всеми клиентскими запросами, и это является одним из подводных камней при создании приложений на Node.js. Во-первых, сложные вычисления могут забить единственный поток Node, что, в свою очередь, создаст всем клиентам определенные проблемы (об этом чуть позже), поскольку входящие запросы будут заблокированы до тех пор, пока эти вычисления не будут завершены. Во-вторых, разработчикам нужно быть очень осторожными, чтобы не допустить появления исключений до базового (самого верхнего) цикла событий Node.js – это может привести к прекращению работы копии Node.js (фактически, к завершению работы всей программы).
Для избежания исключений до самой поверхности используем прием, который заключается в обратной передаче ошибок вызывающей стороне в виде параметров обратного вызова (без выбрасываний, что характерно для других сред). Даже если какие-то необработанные исключения все-таки всплывают, для отслеживания процесса Node.js и выполнения необходимого восстановления копии, которая аварийно завершилась (хотя восстановить пользовательский сеанс вряд ли удастся), были разработаны специальные инструменты. Самый распространенный из них это модуль Forever; также можно использовать внешние системные инструменты Upstart и Monit.
NPM: Менеджер пакетов Node
При разговоре о Node.js очень важно не упустить одну важную деталь. Это встроенная поддержка управления пакетами с помощью инструмента NPM, который по умолчанию идет в любой установке Node.js. Принцип модулей NPM схож с принципом Ruby Gems – это набор повторно используемых компонентов, находящихся в открытом доступе. Их можно легко установить из сетевого репозитория, с поддержкой управления версиями и зависимостями.
С полным списком пакетных модулей можно ознакомиться на сайте npm; он также доступен в CLI-инструменте npm, который автоматически устанавливается вместе с Node.js. Экосистема модулей открыта для всех, то есть любой желающий может опубликовать свой собственный модуль, который впоследствии будет размещаться в репозиторие npm. С кратким введением в npm можно ознакомиться в Руководстве для начинающих, а подробнее о том, как размещать модули здесь (информация на английском языке).
Предлагаем вашему вниманию список самых полезных модулей npm:
- express (он жеjs) – это фреймворк для веб-разработки для Node.js в духе Sinatra; фактически стандартный для большинства существующих приложений Node.js.
- hapi– очень модульный и простой в работе фреймворк, ориентированный на кофигурацию, для создания веб- и сервисных приложений
- connect– это HTTP-серверный фреймворк для js с возможностью расширения, который предоставляет коллекцию высокопроизводительных плагинов, известных под названием «межплатформенное ПО»; служит основой для Express.
- socket.io и sockjs – серверная часть двух самых популярных на сегодняшний день веб-сокетных компонентов.
- pug(ранее Jade) – один из известных шаблонных движков в духе HAML; используется по умолчанию в js.
- mongodb и mongojs – обертки MongoDB, которые предоставляют ИПП для объектных баз данных MongoDB в Node.js.
- redis– клиентская библиотека.
- lodash (underscore, lazy.js)– своеобразный «пояс с инструментами» JavaScript. Первопроходцем была Underscore, но ее обошли две аналогичные библиотеки, в основном за счет более высокой производительности и модульной реализации.
- forever– чуть ли не самая распространенная утилита, которая обеспечивает непрерывное выполнение сценария на конкретном узле. Позволяет вашему процессу js работать бесперебойно при любых непредвиденных сбоях.
- bluebird– полнофункциональная реализация промисов/A+ с невероятно высокой производительностью.
- moment– легкая JavaScript-библиотека для анализа, подтверждения, обработки и форматирования дат.
Список можно продолжать очень долго. Существует еще очень много полезных пакетов, доступных каждому.
Зачем нужен Node.js — примеры использования
ЧАТ
Чат это самое типичное многопользовательское приложение, работающее в режиме реального времени. Если раньше были ретрансплируемые интернет-чаты на базе технологии IRC (были и такие времена), использующие различные частные и открытые протоколы, работающие через нестандартные порты, то сегодня можно реализовать все на Node.js с помощью веб-сокетов, работающих через стандартный порт 80.
Чат это действительно отличный пример приложения на Node.js: это легковесное приложение с высоким трафиком, интенсивно обрабатывающее большие объемы данных (с низким потреблением вычислительных мощностей) и работающее на распределенных устройствах. Он также хорошо подходит для обучения, поскольку довольно простой, и в то же время охватывает большинство парадигм, которые вам когда-либо понадобятся в типичном приложении Node.js.
Давайте разберемся, как он работает на простом примере. Представим, что у нас на сайте есть одна комната чата, куда люди заходят и могут обмениваться сообщенияи со всеми пользователями. И, к примеру, на сайте находится три человека, которые могут писать сообщения на нашем форуме.
На стороне сервера у нас работает простое приложение Express.js, в котором реализуются две функции: 1) обработчик запросов GET ‘/’, который обслуживает веб-страницу, на которой находится форум с сообщениями и кнопка «Отправить», которая инициирует ввод нового сообщения; 2) сервер веб-сокетов, который отслеживает поступление новых сообщений, выдаваемых клиентами веб-сокетов.
На стороне клиента у нас находится HTML-страница с двумя настроенными обработчиками; один отслеживает события нажатия кнопки «Отправить», которая «подхватывает» введенное сообщение и отправляет его вниз на веб-сокет, а второй отслеживает новые входящие сообщения, поступающие клиенту веб-сокетов (то есть, сообщения, отправленные другими пользователями, которые сервер хочет отобразить с помощью этого клиента).
Зачем нужен Node.js
Как только один из клиентов отправляет сообщение, происходит следующее:
- Браузер «подхватывает» нажатие кнопки «Отправить» с помощью обработчика JavaScript, забирает значение из поля ввода (то есть, текст сообщения) и выдает сообщение веб-сокета с помощью клиента веб-сокетов, подключенного к нашему серверу (он инициализируется одновременно с веб-страницей).
- Серверный компонент веб-сокетного соединения получает сообщение и перенаправляет его на все остальные подключенные клиенты путем широковещательней передачи.
- Все клиенты получают новое push-сообщение с помощью веб-сокетного клиентского компонента, который работает на веб-странице. После этого они «подхватывают» содержание сообщения и локально обновляют веб-страницу, добавляя новое сообщение на форум.
Это был самый простой пример. Чтобы создать более надежное решение, можно использовать простой кэш на базе хранилища Redis. Можно пойти дальше и создать еще более продвинутое решение. Это очередь сообщений для обработки маршрутизации сообщений к клиентам и более надежный механизм доставки. Он может компенсировать временные потери соединения или хранить сообщения для зарегистрированных клиентов, пока они находятся в режиме офлайн. Независимо от того, какие улучшения вы захотите реализовать, Node.js будет по-прежнему работать согласно тем же базовым принципам: реагирование на события, обработка большого количества одновременных соединений и обеспечение плавного взаимодействия с пользователем.
ИПП ПОВЕРХ ОБЪЕКТНО-ОРИЕНТИРОВАННОЙ БАЗЫ ДАННЫХ
Хотя Node.js отлично показывает себя в приложениях, работающих в режиме реального времени, он также хорошо подходит для выдачи данных из объектных баз данных (например, из MongoDB). Данные в формате JSON позволяют Node.js работать без рассогласования интерфейсов и преобразования данных.
К примеру, если вы используете Rails, вам необходимо преобразовывать JSON в бинарные модели, а затем выдавать их обратно в виде JSON по HTTP, когда данные используются Backbone.js, Angular.js и т.п., и даже обычными вызовами jQuery AJAX. С помощью Node.js вы можете просто выдавать свои объекты JSON клиенту для использования с помощью ИПП REST. Вам также не нужно беспокоиться о преобразовании между JSON и чем-то другим при считывании или записи в свою базу данных (если вы используете MongoDB). В целом, вы сможете устранить множественные преобразования, используя стандартный формат сериализации данных на клиенте, сервере и в базе данных.
ОЧЕРЕДИ ВВОДА
Если вы одновременно получаете большие объемы данных, ваша база данных может стать узким местом. Как уже было описано выше, Node.js может легко обрабатывать одновременные соединения. Но поскольку обращение к базе данных в данном случае блокирующая операция, у нас появляются проблемы. Решением будет записать поведение клиента до того, как данные будут на самом деле записаны в базу.
При таком подходе система будет сохранять свою отзывчивость при высокой нагрузке, что в особености полезно, когда клиенту не нужно четкое подтверждение успешной записи данных. Типичные примеры: регистрация или запись данных об активности пользователей, которые обрабатываются пакетами и не используются до определенного времени; операции, которые не требуют мгновенного отображения (например, счетчик лайков на Facebook), и в которых допустима согласованность в конечном счете (которая часто используется в NoSQL).
Данные выстраиваются в очередь с помощью специальной инфраструктуры кэширования или организации очередей сообщений (например RabbitMQ, ZeroMQ) и обрабатываются в рамках процесса записи отдельных пакетов в базу данных или с помощью серверных служб по обработке, расчитанных на интенсивные вычисления и записанных для таких целей на более производительной платформе. Похожее поведение можно реализовать и с помощью других языков/фреймвороков, но на другом аппаратном оборудовании с другой высокой стабильной пропускной способностью.
Если коротко, то с помощью Node можно откладывать операции записи в базу данных и обработать их позже, продолжая работу таким образом, как будто они были выполнены.
ПОТОКОВАЯ ПЕРЕДАЧА ДАННЫХ
На более традиционных веб-платформах HTTP-запросы и отклики воспринимаются как отдельные события; на самом деле они представляют собой потоки. Это можно использовать в Node.js для создания очень полезных возможностей. Например, можно обрабатывать файлы, пока они еще загружаются. Поскольку данные поступают в виде потока, мы можем обрабатывать их в режиме онлайн. Это можно применить, к примеру, для кодирования аудио- и видеоинформации в режиме реального времени. И для установки прокси-сервера между различными источниками данных (об этом подробнее в следующем разделе).
ПРОКСИ-СЕРВЕР
Node.js можно легко использовать в качестве прокси-сервера, в котором он сможет обрабатывать большое количество одновременных соединений в режиме неблокирования. Это особенно удобно при проксировании различных сервисов с различным временем отклика, а также при сборе данных из большого количества источников.
Давайте рассмотрим такой пример. Существует серверное приложение, которое связывается со сторонними ресурсами. Оно принимает данные с различных источников или хранит такие ресурсы, как изображения и видео, и передает их на сторонние облачные сервисы.
Несмотря на то, что выделенные прокси-серверы существуют, использование вместо них Node может быть удобным. Удобным тогда, когда у вас нет прокси-инфраструктуры или если вам нужно решение для локальной разработки. Под этим я понимаю то, что вы сможете создать клиентское приложение с сервером разработки Node.js для хранения ресурсов и добавления прокси/заглушек для запросов к ИПП, в то время как в реальных условиях такие взаимодействия выполнялись бы с помощью выделенного прокси-сервера (nginx, HAProxy и т.п.).
БРОКЕРИДЖ – ИНФОРМАЦИОННАЯ ПАНЕЛЬ БИРЖЕВОГО МАКЛЕРА
Давайте вернемся на уровень приложений. Еще одним примером, в котором преобладают программы для ПК, но их можно легко заменить на веб-решения, работающие в реальном времени, это ПО для брокерского трейдинга, которое отслеживает котировки акций, выполняет вычисления и технический анализ, а также выводит графики и диаграммы.
Переход на веб-решения, работающие в реальном времени, позволит брокерам легко переключаться между рабочими станциями или рабочими местами. Вполне возможно, что в скором времени мы начнем замечать их на пляжах Флориды, Ибицы и Бали.
ПАНЕЛЬ МОНИТОРИНГА ПРИЛОЖЕНИЙ
Еще одним типичным вариантом использования, для которого отлично подходит модель Node с веб-сокетами, является слежение за посетителями сайта и отображение их взаимодействия в реальном времени.
Можно собирать статистику о пользователях в реальном времени; можно пойти еще дальше и добавить целевые воздействия со своими посетителями, открывая канал связи при достижении ими определенной точки в вашей воронке (если вас это заинтересовало, эта идея уже реализована с помощью CANDDi).
Только представьте, как вы могли бы улучшить свой бизнес, если бы знали, что делают ваши пользователи в реальном времени, если бы можно было визуализировать их взаимодействия. Теперь у вас будет такая возможность с помощью двунаправленных сокетов Node.js, работающих в реальном времени.
ПАНЕЛЬ КОНТРОЛЯ СИСТЕМЫ
Давайте теперь поговорим об инфраструктуре. Представьте, что есть SaaS-провайдер, который хочет предложить своим клиентам страницу для отслеживания сервисов (такую как статусную страницу GitHub, например). Используя цикл событий Node.js мы можем создать мощную веб-панель, которая асинхронно отслеживает статус сервисов и отправляет данные клиентам через веб-сокеты.
С помощью этой технологии можно в реальном времени передавать информацию о статусе как внутренних (корпоративных), так и общедоступных сервисов. Если развить эту идею дальше, можно довольно легко представить сетевой операционный центр, который осуществляет контроль работы приложений оператора связи, поставщика облачных сервисов, сетевых услуг и хостинга, а также финансового учреждения. Все это работает в открытом веб-стеке на базе Node.js и веб-сокетов вместо Java и/или Java-апплетов.
Примечание: Не пытайтесь создавать на базе Node системы жесткого реального времени Node (то есть системы, требующие точного времени отклика). Для такого рода приложений лучше всего использовать Erlang.
Зачем нужен Node.js — где можно использовать
Зачем нужен Node.js — СЕРВЕРНЫЕ ВЕБ-ПРИЛОЖЕНИЯ
Node.js с Express.js можно также использовать для создания классических серверных веб-приложений. И хоть это и возможно, эта парадигма запрос-отклик, в которой Node.js будет переносить отображенный HTML, не является типичным вариантом использования. Есть аргументы за и против этого подхода. Вот некоторые из них:
Преимущества:
- Если ваше приложение не выполняет вычислений с интенсивной нагрузкой на центральный процессор, его можно полностью создать на Javascript. В том числе и базу данных, если вы используете объектную базу данных JSON, например MongoDB. Это существенно упрощает процесс разработки (в том числе подбор специалистов).
- Поисковые модули получают в ответ полностью отображенный HTML. Он гораздо более дружественный к SEO, чем, скажем, одностраничное приложение или веб-сокетное приложение, работающее на базе js.
Недостатки:
- Любые вычисления с интенсивной нагрузкой на центральный процесор будут блокировать отзывчивость js, поэтому лучше в таком случае использовать мнгопоточную платформу. Можно также попробовать горизонтальное масштабирование вычислений*.
- Использование js с реляционной базой данных несет в себе много сложностей (об этом подробнее ниже). Для реляционных операций лучше всего выбрать какую-нибудь другую среду, к примеру Rails, Django или ASP.Net MVC.
* Как вариант, для таких вычислений с интенсивной нагрузкой на центральный процессор можно создать высокомасштабируемую среду на базе MQ с обработкой на стороне сервера, чтобы Node оставался спереди и асинхронно обрабатывал клиентские запросы.
Зачем нужен Node.js — где не стоит использовать
Зачем нужен Node.js — СЕРВЕРНОЕ ВЕБ-ПРИЛОЖЕНИЕ С РЕЛЯЦИОННОЙ БАЗОЙ ДАННЫХ
Если сравнивать Node.js и Express.js с Ruby on Rails с точки зрения доступа к реляционным данным, выбор будет явно в пользу последнего.
Инструменты реляционных баз данных для Node.js по-прежнему находятся на этапе доработок, поэтому работать с ними пока не очень удобно. Rails же осуществляет автоматическую настройку доступа доступа к данным «прямо из коробки». Он также предоставляет инструменты для поддержки миграций схем баз данных и другие «плюшки». Rails и соответствующие фреймворки имеют серьезные и проверенные реализации доступа к уровню данных (Active Record или Data Mapper), которых вам будет очень не хватать, если вы решите воссоздать их на чистом JavaScript.*
Но если вы действительно склоняетесь к тому, чтобы все делать исключительно на JavaScript (и готовы немного помучиться), будьте внимательны при работе с Sequelize и Node ORM2 – они пока находятся не в самом идеальном виде, но в скором времени это изменится.
* Можно использовать Node (что довольно часто практикуется) исключительно на стороне клиента, а back-end при этом реализовать на Rails, что позволит обеспечить простой доступ к реляционной базе данных.
Зачем нужен Node.js — СЛОЖНЫЕ СЕРВЕРНЫЕ ВЫЧИСЛЕНИЯ И ОБРАБОТКА
Если говорить о сложных вычислениях, Node.js не самая лучшая платформа. Вам определенно не стоит создавать на Node.js сервер вычислений Фибоначчи. В общем, любые операции с интенсивной вычислительной нагрузкой на центральный процессор сводят на нет все преимущества пропускной способности, которые предоставляет Node в рамках модели неблокирующего событийно-ориентированного ввода/вывода, поскольку любые входящие запросы будут блокироваться, пока поток занят обработкой данных.
Как было указано выше, Node.js однопоточный и использует всего лишь одно ядро процессора. Когда необходимо реализовать параллельную работу на многоядерном сервере, группа разработчиков ядра Node должна заняться подготовкой кластерного модуля. Можно также легко запустить несколько экземпляров сервера Node.js за обратным прокси-сервером через nginx.
С помощью кластеризации вы все равно сможете выгрузить все сложные вычисления в фоновые процессы, работающие в более приемлемой для этого среде, и обеспечить между ними соединение через сервер очереди сообщений, такой как RabbitMQ.
Несмотря на то, что изначально ваша фоновая обработка данных могла осуществляться на том же сервере. Такой подход позволяет добиться очень высокой масштабируемости. Такие службы фоновой обработки можно легко распределить на отдельные рабочие серверы без необходимости в настройке нагрузки фронтальных веб-серверов.
Конечно, такой же подход можно применить и на других платформах, но с Node.js вы сможете получить ту самую пропускную способность (количество запросов в секунду), о который мы говорили ранее, поскольку каждый запрос это маленькая задача, выполняемая очень быстро и эффективно.
Зачем нужен Node.js — Вывод
Мы рассказали все о Node.js с теоретической и практической точек зрения. Вы узнали о целях и назначениях, а также о различных «плюшках» и подводных камнях. Когда у людей возникают проблемы при работе с Node, чаще всего они сводятся к тому, что корнем зла являются блокирующие операции. В 99% случаев причина всех проблем заключается в неправильном использовании Node.
«При работе с Node корнем зла являются блокирующие операции. В 99% случаев причина всех проблем заключается в неправильном использовании Node.»
Помните о том, что Node.js не был создан для решения проблем, связанных с масштабированием вычислений. Он был создан для решения проблем масштабирования ввода/вывода, с которой он отлично справляется.
Так, зачем нужен Node.js? Если ваш вариант использования не предполагает операций с интенсивной вычислительной нагрузкой на центральный процессор или обращения к блокируемым ресурсам, вы можете смело использовать преимущества Node.js. И наслаждайтесь быстрыми и масштабируемыми сетевыми приложениями!
Добро пожаловать в веб-приложения, работающие в реальном времени!
Comments