На кой черт мне использовать Node.js? Индивидуальное руководство

Опубликовано: 2022-03-11

Введение

Растущая популярность JavaScript принесла с собой множество изменений, и современная веб-разработка кардинально изменилась. Вещи, которые мы можем делать в Интернете в настоящее время с помощью JavaScript, работающего на сервере, а также в браузере, было трудно представить всего несколько лет назад или они были инкапсулированы в изолированных средах, таких как Flash или Java-апплеты.

Прежде чем углубляться в решения Node.js, вы можете прочитать о преимуществах использования JavaScript в стеке, который унифицирует язык и формат данных (JSON), позволяя оптимально повторно использовать ресурсы разработчиков. Поскольку это больше преимущество JavaScript, чем конкретно Node.js, мы не будем здесь его подробно обсуждать. Но это ключевое преимущество включения Node в ваш стек.

Как гласит Википедия: «Node.js — это упакованная компиляция движка Google V8 JavaScript, уровня абстракции платформы libuv и базовой библиотеки, которая сама в основном написана на JavaScript». Кроме того, стоит отметить, что Райан Даль, создатель Node.js, стремился создавать веб-сайты в реальном времени с возможностью push-уведомлений , «вдохновленные такими приложениями, как Gmail». В Node.js он дал разработчикам инструмент для работы в парадигме неблокирующего, управляемого событиями ввода-вывода.

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

Одним предложением: Node.js сияет в веб-приложениях реального времени, использующих технологию push через веб-сокеты. Что в этом революционного? Что ж, после более чем 20 лет безгосударственной сети, основанной на парадигме запрос-ответ без сохранения состояния, у нас наконец-то появились веб-приложения с двусторонними соединениями в режиме реального времени, где и клиент, и сервер могут инициировать связь, что позволяет им свободно обмениваться данными. . Это резко контрастирует с типичной парадигмой веб-ответа, где клиент всегда инициирует общение. Кроме того, все это основано на открытом веб-стеке (HTML, CSS и JS), работающем через стандартный порт 80.

Кто-то может возразить, что у нас это было в течение многих лет в форме Flash и Java-апплетов, но на самом деле это были просто изолированные среды, использующие Интернет в качестве транспортного протокола для доставки клиенту. Кроме того, они запускались изолированно и часто работали через нестандартные порты, для которых могли потребоваться дополнительные разрешения и тому подобное.

Со всеми своими преимуществами Node.js теперь играет решающую роль в стеке технологий многих известных компаний, которые зависят от его уникальных преимуществ. Фонд Node.js объединил все лучшие размышления о том, почему предприятиям следует рассматривать Node.js, в короткой презентации, которую можно найти на странице тематических исследований Node.js Foundation.

В этом руководстве по Node.js я расскажу не только о том, как достигаются эти преимущества, но и о том, почему вы можете захотеть использовать Node.js — и почему нет — на некоторых классических моделях веб-приложений в качестве примеров.

Как это работает?

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

Это полный рот.

На самом деле это означает, что Node.js не является новой платформой с серебряной пулей, которая будет доминировать в мире веб-разработки. Наоборот, это платформа, которая удовлетворяет определенные потребности.
Твитнуть

На самом деле это означает, что Node.js не является новой платформой с серебряной пулей, которая будет доминировать в мире веб-разработки. Наоборот, это платформа, которая удовлетворяет определенные потребности . И понимание этого совершенно необходимо. Вы определенно не хотите использовать Node.js для операций с интенсивным использованием ЦП; на самом деле, использование его для тяжелых вычислений сведет на нет почти все его преимущества. Где Node действительно хорош, так это в создании быстрых, масштабируемых сетевых приложений, поскольку он способен обрабатывать огромное количество одновременных подключений с высокой пропускной способностью, что соответствует высокой масштабируемости.

Как это работает под капотом, довольно интересно. По сравнению с традиционными методами веб-обслуживания, когда каждое соединение (запрос) порождает новый поток, занимая системную оперативную память и, в конечном итоге, максимально используя объем доступной оперативной памяти, Node.js работает в одном потоке, используя неблокирующий ввод/вывод. O, что позволяет ему поддерживать десятки тысяч одновременных соединений, удерживаемых в цикле событий.

Диаграмма традиционного и серверного потока Node.js

Быстрый подсчет: если предположить, что каждый поток потенциально имеет сопутствующие 2 МБ памяти, то при работе в системе с 8 ГБ ОЗУ теоретический максимум составляет 4000 одновременных подключений (расчеты взяты из статьи Майкла Абернети «Just what is Node. .js?», опубликованный на IBM developerWorks в 2011 году; к сожалению, статья больше не доступна) , плюс стоимость переключения контекста между потоками. Это сценарий, с которым вы обычно имеете дело в традиционных методах веб-обслуживания. Избегая всего этого, Node.js достигает уровня масштабируемости более 1 млн одновременных подключений и более 600 тыс. одновременных подключений через веб-сокеты.

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

Техника, используемая для предотвращения всплытия исключений на поверхность, заключается в передаче ошибок вызывающей стороне в качестве параметров обратного вызова (вместо их выдачи, как в других средах). Даже если возникнет какое-то необработанное исключение, были разработаны инструменты для мониторинга процесса Node.js и выполнения необходимого восстановления поврежденного экземпляра (хотя вы, вероятно, не сможете восстановить текущее состояние сеанса пользователя). наиболее распространенным является модуль Forever или другой подход с внешними системными инструментами upstart и monit или даже просто upstart.

NPM: диспетчер пакетов узлов

При обсуждении Node.js нельзя упускать из виду одну вещь — встроенную поддержку управления пакетами с помощью NPM, инструмента, который поставляется по умолчанию при каждой установке Node.js. Идея модулей NPM очень похожа на Ruby Gems : набор общедоступных повторно используемых компонентов, доступных через простую установку через онлайн-репозиторий, с управлением версиями и зависимостями.

Полный список упакованных модулей можно найти на веб-сайте npm или получить к нему доступ с помощью инструмента npm CLI, который автоматически устанавливается вместе с Node.js. Экосистема модулей открыта для всех, и каждый может опубликовать свой собственный модуль, который будет указан в репозитории npm.

Вот некоторые из наиболее полезных модулей npm на сегодняшний день:

  • express — Express.js — или просто Express — вдохновленная Sinatra среда веб-разработки для Node.js и стандарт де-факто для большинства приложений Node.js, существующих сегодня.
  • hapi — очень модульная и простая в использовании структура, ориентированная на конфигурацию, для создания веб-приложений и сервисов.
  • connect — Connect — это расширяемая структура HTTP-сервера для Node.js, предоставляющая набор высокопроизводительных «плагинов», известных как промежуточное ПО; служит базовой основой для Express.
  • socket.io и sockjs — серверный компонент из двух наиболее распространенных сегодня компонентов веб-сокетов.
  • pug (ранее Jade ) — один из популярных движков шаблонов, вдохновленный HAML, по умолчанию в Express.js.
  • mongodb и mongojs — оболочки MongoDB для предоставления API для объектных баз данных MongoDB в Node.js.
  • redis — клиентская библиотека Redis.
  • lodash (подчеркивание, lazy.js) — утилита JavaScript. Underscore инициировал игру, но был свергнут одним из двух своих аналогов, в основном из-за лучшей производительности и модульной реализации.
  • навсегда — вероятно, самая распространенная утилита для обеспечения непрерывной работы данного скрипта узла. Поддерживает рабочий процесс Node.js в случае любых неожиданных сбоев.
  • bluebird — полнофункциональная реализация Promises/A+ с исключительно хорошей производительностью
  • moment — библиотека дат JavaScript для синтаксического анализа, проверки, манипулирования и форматирования дат.

Список можно продолжить. Существует множество действительно полезных пакетов, доступных всем (не в обиду тем, которые я здесь не упомянул).

Примеры использования Node.js

ЧАТ

Чат является наиболее типичным многопользовательским приложением, работающим в режиме реального времени. От IRC (когда-то) через множество проприетарных и открытых протоколов, работающих на нестандартных портах, до возможности реализовать все сегодня в Node.js с веб-сокетами, работающими через стандартный порт 80.

Приложение для чата — действительно лучший пример для Node.js: это легкое приложение с высоким трафиком и интенсивным использованием данных (но с низким уровнем обработки/вычислений), которое работает на распределенных устройствах. Это также отличный пример использования для обучения, поскольку он прост, но охватывает большинство парадигм, которые вы когда-либо будете использовать в типичном приложении Node.js.

Попробуем изобразить, как это работает.

В самом простом примере у нас есть один чат на нашем веб-сайте, куда люди приходят и могут обмениваться сообщениями в режиме «один ко многим» (фактически всем). Например, скажем, у нас есть три человека на веб-сайте, и все они подключены к нашей доске объявлений.

На стороне сервера у нас есть простое приложение Express.js, которое реализует две вещи:

  1. Обработчик GET / запроса, который обслуживает веб-страницу, содержащую как доску объявлений, так и кнопку «Отправить», для инициализации ввода нового сообщения, и
  2. Сервер веб-сокетов, который прослушивает новые сообщения, отправляемые клиентами веб-сокетов.

На стороне клиента у нас есть HTML-страница с несколькими настроенными обработчиками, один для события нажатия кнопки «Отправить», который получает входящее сообщение и отправляет его по веб-сокету, а другой прослушивает новые входящие сообщения. на клиенте веб-сокетов (т. е. сообщения, отправленные другими пользователями, которые сервер теперь хочет, чтобы клиент отображал).

Когда один из клиентов публикует сообщение, происходит следующее:

  1. Браузер перехватывает нажатие кнопки «Отправить» через обработчик JavaScript, извлекает значение из поля ввода (т. е. текст сообщения) и отправляет сообщение веб-сокета, используя клиент веб-сокета, подключенный к нашему серверу (инициализируется при инициализации веб-страницы).
  2. Серверный компонент подключения через веб-сокет получает сообщение и пересылает его всем другим подключенным клиентам, используя широковещательный метод.
  3. Все клиенты получают новое сообщение в виде push-сообщения через клиентский компонент веб-сокетов, работающий на веб-странице. Затем они берут содержимое сообщения и обновляют веб-страницу на месте, добавляя новое сообщение на доску.

Схема клиентских и серверных веб-сокетов в приложении Node.js

Это самый простой пример. Для более надежного решения вы можете использовать простой кеш на основе хранилища Redis. Или, в еще более продвинутом решении, очередь сообщений для обработки маршрутизации сообщений клиентам и более надежный механизм доставки, который может компенсировать временные потери соединения или хранить сообщения для зарегистрированных клиентов, когда они находятся в автономном режиме. Но независимо от внесенных вами улучшений, Node.js по-прежнему будет работать по тем же основным принципам: реагировать на события, обрабатывать множество одновременных подключений и обеспечивать плавность взаимодействия с пользователем.

API ПОВЕРХ БД ОБЪЕКТОВ

Хотя Node.js действительно блестяще работает с приложениями реального времени, он вполне естественно подходит для предоставления данных из объектных баз данных (например, MongoDB). Сохраненные данные JSON позволяют Node.js работать без несоответствия импеданса и преобразования данных.

Например, если вы используете Rails, вы должны преобразовать JSON в двоичные модели, а затем предоставить их обратно как JSON через HTTP, когда данные потребляются Backbone.js, Angular.js и т. д., или даже простым jQuery AJAX. звонки. С помощью Node.js вы можете просто предоставлять свои объекты JSON с помощью REST API для использования клиентом. Кроме того, вам не нужно беспокоиться о преобразовании между JSON и чем-то еще при чтении или записи из вашей базы данных (если вы используете MongoDB). Таким образом, вы можете избежать необходимости многократного преобразования, используя единый формат сериализации данных для клиента, сервера и базы данных.

ВХОДЫ В ОЧЕРЕДИ

Если вы получаете большое количество одновременных данных, ваша база данных может стать узким местом. Как показано выше, Node.js может легко обрабатывать одновременные подключения самостоятельно. Но поскольку доступ к базе данных является блокирующей операцией (в данном случае), у нас возникают проблемы. Решение состоит в том, чтобы подтвердить поведение клиента до того, как данные будут действительно записаны в базу данных.

При таком подходе система сохраняет свою отзывчивость при большой нагрузке, что особенно полезно, когда клиенту не требуется твердое подтверждение успешной записи данных. Типичные примеры включают в себя: регистрацию или запись данных отслеживания пользователей, которые обрабатываются пакетами и не используются до более позднего времени; а также операции, которые не нужно отражать мгновенно (например, обновление счетчика «Нравится» на Facebook), где возможная согласованность (так часто используемая в мире NoSQL) приемлема.

Данные помещаются в очередь через какую-либо инфраструктуру кэширования или очередей сообщений, например RabbitMQ или ZeroMQ, и обрабатываются отдельным процессом пакетной записи базы данных или серверными службами, требующими больших вычислительных ресурсов, написанными на более производительной платформе для таких задач. Подобное поведение может быть реализовано с другими языками/фреймворками, но не на том же оборудовании с такой же высокой поддерживаемой пропускной способностью.

Схема пакетной записи базы данных в Node.js с очередями сообщений

Короче говоря: с помощью Node вы можете отложить записи в базу данных и заняться ими позже, действуя так, как если бы они увенчались успехом.

ПОТОКОВАЯ ПЕРЕДАЧА ДАННЫХ

На более традиционных веб-платформах HTTP-запросы и ответы обрабатываются как изолированные события; на самом деле это потоки. Это наблюдение можно использовать в Node.js для создания некоторых интересных функций. Например, можно обрабатывать файлы, пока они еще загружаются, так как данные поступают через поток, и мы можем обрабатывать их онлайн. Это может быть сделано для кодирования аудио или видео в реальном времени и проксирования между различными источниками данных (см. следующий раздел).

ПРОКСИ

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

Пример: рассмотрим серверное приложение, взаимодействующее со сторонними ресурсами, извлекающее данные из разных источников или хранящее активы, такие как изображения и видео, в сторонних облачных службах.

Несмотря на то, что выделенные прокси-серверы существуют, использование Node может оказаться полезным, если ваша прокси-инфраструктура отсутствует или вам нужно решение для локальной разработки. Под этим я подразумеваю, что вы можете создать клиентское приложение с сервером разработки Node.js для ресурсов и проксирования/заглушки запросов API, в то время как в производстве вы будете обрабатывать такие взаимодействия с помощью выделенной прокси-службы (nginx, HAProxy и т. д.). .).

БРОКЕРСКАЯ ИНФОРМАЦИЯ - ИНФОРМАЦИОННАЯ ПАНЕЛЬ ТОРГОВА

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

Переход на веб-решение, работающее в режиме реального времени, позволит брокерам легко переключаться между рабочими станциями или рабочими местами. Скоро мы можем увидеть их на пляжах Флориды... или Ибицы... или Бали.

ИНФОРМАЦИОННАЯ ПАНЕЛЬ МОНИТОРИНГА ПРИЛОЖЕНИЙ

Еще один распространенный вариант использования, в котором Node-with-web-sockets идеально подходят: отслеживание посетителей веб-сайта и визуализация их взаимодействия в режиме реального времени.

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

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

ИНФОРМАЦИОННАЯ ПАНЕЛЬ МОНИТОРИНГА СИСТЕМЫ

Теперь давайте посетим инфраструктурную сторону вещей. Представьте, например, поставщика SaaS, который хочет предложить своим пользователям страницу мониторинга услуг, такую ​​как страница состояния GitHub. С помощью цикла обработки событий Node.js мы можем создать мощную веб-панель управления, которая асинхронно проверяет статусы сервисов и отправляет данные клиентам с помощью веб-сокетов.

С помощью этой технологии можно сообщать о состоянии как внутренних (внутрикорпоративных), так и государственных услуг в режиме реального времени. Продвиньте эту идею немного дальше и попытайтесь представить приложения мониторинга Network Operations Center (NOC) в телекоммуникационном операторе, облачном/сетевом/хостинг-провайдере или каком-либо финансовом учреждении, все они работают на открытом веб-стеке, поддерживаемом Node.js и веб-сокетами. вместо Java и/или Java-апплетов.

Примечание. Не пытайтесь создавать системы жесткого реального времени в Node (т. е. системы, требующие постоянного времени отклика). Erlang, вероятно, лучший выбор для этого класса приложений.

Где можно использовать Node.js

СЕРВЕРНЫЕ ВЕБ-ПРИЛОЖЕНИЯ

Node.js с Express.js также можно использовать для создания классических веб-приложений на стороне сервера. Однако, хотя это возможно, эта парадигма запроса-ответа, в которой Node.js будет нести визуализированный HTML, не является наиболее типичным вариантом использования. Приводятся аргументы за и против такого подхода. Вот несколько фактов для размышления:

Плюсы:

  • Если в вашем приложении нет вычислений, интенсивно использующих ЦП, вы можете создать его в Javascript сверху вниз, даже на уровне базы данных, если вы используете объектную базу данных хранилища JSON, например MongoDB. Это значительно облегчает развитие (включая найм).
  • Сканеры получают полностью отрендеренный HTML-ответ, который гораздо более удобен для SEO, чем, скажем, одностраничное приложение или приложение для веб-сокетов, работающее поверх Node.js.

Минусы:

  • Любые вычисления с интенсивным использованием ЦП будут блокировать отзывчивость Node.js, поэтому многопоточная платформа является лучшим подходом. В качестве альтернативы вы можете попробовать масштабировать вычисления [*].
  • Использование Node.js с реляционной базой данных все еще довольно проблематично (подробнее см. ниже). Сделайте себе одолжение и выберите любую другую среду, такую ​​как Rails, Django или ASP.Net MVC, если вы пытаетесь выполнять реляционные операции.
[*] Альтернативой этим вычислениям с интенсивным использованием ЦП является создание хорошо масштабируемой среды на основе MQ с внутренней обработкой, чтобы Node оставался фронтальным «клерком» для асинхронной обработки клиентских запросов.

Где Node.js не следует использовать

СЕРВЕРНОЕ ВЕБ-ПРИЛОЖЕНИЕ С РЕЛЯЦИОННОЙ БД

Сравнивая Node.js с Express.js с Ruby on Rails, например, раньше было четкое решение в пользу последнего, когда дело доходило до доступа к реляционным базам данных, таким как PostgreSQL, MySQL и Microsoft SQL Server.

Инструменты реляционной базы данных для Node.js все еще находились на ранних стадиях. С другой стороны, Rails автоматически обеспечивает настройку доступа к данным прямо из коробки вместе с инструментами поддержки миграции схемы БД и другими жемчужинами (каламбур). Rails и аналогичные фреймворки имеют зрелые и проверенные реализации уровня доступа к данным Active Record или Data Mapper.[*]

Но все изменилось. Sequelize, TypeORM и Bookshelf прошли долгий путь, чтобы стать зрелыми решениями ORM. Возможно, вам также стоит проверить Join Monster, если вы хотите генерировать SQL из запросов GraphQL.

[*] Нередко можно использовать Node исключительно в качестве интерфейса, сохраняя при этом серверную часть Rails и ее легкий доступ к реляционной БД.
Связанный: Серверная часть: Использование Gatsby.js и Node.js для статических обновлений сайта

ТЯЖЕЛЫЕ ВЫЧИСЛЕНИЯ/ОБРАБОТКА НА СЕРВЕРНОЙ СТОРОНЕ

Когда дело доходит до тяжелых вычислений, Node.js — не лучшая платформа. Нет, вы определенно не хотите создавать сервер вычислений Фибоначчи в Node.js. В целом, любая операция с интенсивным использованием ЦП сводит на нет все преимущества пропускной способности, которые Node предлагает благодаря своей управляемой событиями, неблокирующей модели ввода-вывода, потому что любые входящие запросы будут блокироваться, пока поток занят вашей обработкой чисел — при условии, что вы пытаетесь для выполнения ваших вычислений в том же экземпляре Node, которым вы отвечаете на запросы.

Как указывалось ранее, Node.js является однопоточным и использует только одно ядро ​​ЦП. Когда дело доходит до добавления параллелизма на многоядерном сервере, основная команда Node выполняет некоторую работу в виде модуля кластера [ссылка: http://nodejs.org/api/cluster.html]. Вы также можете довольно легко запустить несколько экземпляров сервера Node.js за обратным прокси через nginx.

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

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

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

Заключение

Мы обсудили Node.js от теории к практике, начиная с его целей и амбиций и заканчивая его преимуществами и ловушками. Когда у людей возникают проблемы с Node, они почти всегда сводятся к тому, что блокировка операций — корень всех зол — 99% неправильного использования Node являются прямым следствием.

В Node блокирующие операции — это корень всех зол — 99% неправильного использования Node являются прямым следствием.
Твитнуть

Помните: Node.js никогда не создавался для решения проблемы масштабирования вычислений. Он был создан для решения проблемы масштабирования ввода-вывода, с которой он справляется очень хорошо.

Зачем использовать Node.js? Если ваш вариант использования не содержит операций с интенсивным использованием ЦП и доступа к каким-либо блокирующим ресурсам, вы можете воспользоваться преимуществами Node.js и пользоваться быстрыми и масштабируемыми сетевыми приложениями. Добро пожаловать в сеть реального времени.