Пояснительная записка к электронному журналу с использованием технологии Блокчейн, Обзор инструментальных средств: часть 2


Продолжаем.

1.2.2 Node.js

Node (другое название – Node.js) — это недавно появившаяся платформа,
которая выводит язык JavaScript за пределы браузера и позволяет
использовать его в серверных приложениях. В основе платформы лежит
исключительно быстрый движок JavaScript, заимствованный из браузера
Chrome, V8, к которому добавлена быстрая и надежная библиотека
асинхронного сетевого ввода/вывода. Основной упор в Node
делается на создании высокопроизводительных, хорошо масштабируемых
клиентских и серверных приложений для «веб реального времени».

Эту платформу разработал Райан Дал (RyanDahl) в 2009 году, после двух
лет экспериментирования с созданием серверных веб-компонентов на Ruby
и других языках. В ходе своих исследований он пришел к выводу, что
вместо традиционной модели параллелизма на основе потоков следует
обратиться к событийно-ориентированным системам. Эта модель была
выбрана за простоту (хорошо известно, что многопоточные системы
трудно реализовать правильно), за низкие накладные расходы, по
сравнению с идеологией «один поток на каждое соединение», и за
быстродействие. Цель Node - предложить «простой способ построения
масштабируемых сетевых серверов». При проектировании за образец
были взяты такие системы, как EventMachine (Ruby) и каркас Twisted
(Python).

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

Принятая в Node модель принципиально отличается от распространенных
платформ для построения серверов приложений, в которых
масштабируемость достигается за счет многопоточности.
Утверждается, что благодаря событийно-ориентированной архитектуре
снижается потребление памяти, повышается пропускная способность и
упрощается модель программирования. Сейчас платформа Node быстро
развивается, и многие считают ее привлекательной альтернативой
традиционному подходу к разработке веб-приложений - на базе
Apache, РНР, Python и т. п.

В основе Node лежит автономная виртуальная машина JavaScript с
расширениями, делающими ее пригодной для программирования
общего назначения с упором на разработку серверов приложений.
Платформу Node не имеет смысла напрямую сравнивать ни с языками
программирования, которые обычно используются для создания
веб-приложений (PHP/Python/Ruby/Java и прочие), ни с
контейнерами, реализующими протокол HTTP
(Apache/Tomcat/Glassfish ит. д.). В то же время многие считают, что
потенциально она может заменить традиционные стеки веб-приложений.

В основе реализации лежит цикл обработки событий неблокирующего
ввода/вывода и библиотеки файлового и сетевого ввода/вывода,
причем все это построено поверх движка V8 JavaScript
(заимствованного из веб-браузера Chrome). Библиотека
ввода/вывода обладает достаточной общностью для реализации любого
протокола на базе TCP или UDP: DNS, HTTP, IRC, FTP и др. Но хотя она
поддерживает разработку серверов и клиентов произвольного протокола,
чаще всего применяется для создания обычных веб-сайтов, где заменяет
Apache/PHP или Rails.

Node - платформа для написания JavaScript-приложений вне веб-браузера.
Это не тот JavaScript, с которым все мы знакомы по опыту работы с
браузерами. В Node не встроена ни объектная модель документа (DOM),
ни какие-либо ещё возможности браузера. Именно язык JavaScript в
сочетании с асинхронным вводом/выводом делает Node мощной
платформой для разработки приложений. Но вот для чего Node
непригодна, так это для разработки персональных приложений с
графическим интерфейсом пользователя (ГИП). На сегодняшний день в
Node нет встроенного эквивалента Swing (или SWT). Нет и подключаемой
библиотеки ГИП для Node, и внедрить Node в браузер тоже нельзя. Если
бы для Node существовала библиотека ГИП, то на этой платформе можно было
строить и персонал

ьные приложения. Недавно появилось несколько проектов
по созданию интерфейса между Node и GTK, итогом которых должна стать
кросс-платформенная библиотека ГИП. В состав движка V8, используемого
в Node, входят API-расширения, позволяющие писать на C/C++ код для
расширения JavaScript или интеграции движка с платформенными
библиотеками.

Помимо встроенного умения исполнять код на JavaScript, включенные в
состав дистрибутива модули предоставляют и другие возможности:

  • утилиты командной строки (для включения в скрипты оболочки);

  • средства написания интерактивных консольных программ (цикл «чтение

    • выполнение - печать»);
  • великолепные функции управления процессами для наблюдения за
    дочерними процессами;

  • объект Buffer для работы с двоичными данными;

  • механизм для работы с сокетами TCP и UDP с полным комплектом
    обратных вызовов в ответ на события;

  • поиск в системе DNS;

  • средства для создания серверов и клиентов протоколов HTTP и HTTPS,
    построенные на основе библиотеки ТСР-сокетов;

  • средства доступа к файловой системе;

  • встроенная рудиментарная поддержка автономного тестирования с
    помощью утверждений.

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

Иными словами, написать на Node HTTP-сервер очень просто, но типичному
разработчику веб-приложений нет нужды работать на таком низком уровне.
Например, кодируя на РНР, программист предполагает, что Apache уже
присутствует, так что реализовывать серверную часть стека ему не
нужно. Сообщество, сложившееся вокруг Node, создало широкий спектр
каркасов для разработки веб-приложений, в том числе Connect, которые
позволяют быстро сконфигурировать HTTP так, чтобы предоставлялось все, к
чему мы привыкли, - сеансы, куки, обслуживание статических файлов,
протоколирование и т.д. - и пусть разработчик занимается
бизнес-логикой приложения.

Язык JavaScript очень популярен благодаря присутствию в любом
веб-браузере. Он ни в чем не уступает другим языкам, но при
этом поддерживает многие современные представления о том, каким
должен быть язык программирования. Благодаря широкому
распространению имеется немало опытных программистов на
JavaScript.

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

Один из основных недостатков JavaScript - Глобальный Объект. Все
переменные верхнего уровня «сваливаются» в Глобальный Объект, и
при использовании одновременно нескольких модулей это может привести к
неуправляемому хаосу. Поскольку веб-приложения обычно состоят из
множества объектов, возможно, создававшихся разными
организациями, то может возникнуть опасение, будто
программирование для Node сродни хождению по минному полю,
нашпигованному конфликтующими между собой глобальными объектами.
Однако это не так. На самом деле в Node используется система
организации модулей CommonJS, а это означает, что локальные
переменные некоторого модуля так и будут локальными в нем, пусть
даже выглядят как глобальные. Такое четкое разграничение между
модулями решает проблему Глобального Объекта.

Использование единого языка программирования на сервере и на клиенте
давно уже было мечтой

разработчиков для веб. Своими корнями эта
мечта уходит в период становления Java, когда апплеты
представлялись клиентским интерфейсом к написанным на Java
серверным приложениям, a JavaScript первоначально виделся как
облегченный скриптовый язык взаимодействия с апплетами. Но
что-то на этом пути не сложилось, и в результате не Java, a
JavaScript стал основным языком на стороне клиента-браузера. С
появлением Node мы, наконец, сможем реализовать мечту -
сделать JavaScript языком, используемым по обе стороны веб - на
стороне клиента и сервера.

У единого языка есть несколько потенциальных плюсов:

  • одни и те же программисты могут работать над обеими сторонами
    приложения;

  • код проще переносить с сервера на клиент и обратно;

  • общий для клиента и сервера формат данных (JSON);

  • общий программный инструментарий;

  • общие для клиента и сервера средства тестирования и контроля
    качества;

  • на обеих сторонах веб-приложения можно использовать общие шаблоны
    представлений;

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

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

Архитектура: потоки или асинхронный ввод/вывод с управлением по
событиям.

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

В Node имеется единственный поток выполнения, без какого-либо
контекстного переключения или ожидания ввода/вывода. При
любом запросе ввода/вывода задаются функции обработки, которые
впоследствии вызываются из цикла обработки событий, когда станут
доступны данные или произойдет еще что-то значимое. Модель цикла
обработки событий и обработчика событий – вещь распространённая,
именно так исполняются написанные на JavaScript скрипты в браузере.
Ожидается, что программа быстро вернет управление циклу обработки,
чтобы можно было вызвать следующее стоящее в очереди задание. Чтобы
повернуть наши мысли в нужном направлении, Райан Дал (в презентации
«Cincode Node») спрашивает, что происходит при выполнении такого кода:

result = query('SELECT \* from db);

Разумеется, программа в этой точке приостанавливается на время, пока
слой доступа к базе данных отправляет запрос базе, которая вычисляет
результат и возвращает данные. В зависимости от сложности запроса его
выполнение может занять весьма заметное время. Это плохо, потому что
пока поток простаивает, может прийти другой запрос, а если заняты все
потоки, то запрос будет просто отброшен. Расточительно это как-то. Да
и контекстное переключение обходится не бесплатно; чем больше запущено
потоков, тем больше времени процессор тратит на сохранение и
восстановление их состояния. Кроме того, стек каждого потока
занимает место в памяти. И просто за счет асинхронного
событийно-ориентированного ввода/вывода Node устраняет
большую часть этих накладных расходов, привнося совсем немного
собственных.

Часто рассказ о реализации параллелизма с помощью потоков сопровождается
предостережениями типа «дорого и чревато ошибками», «ненадежные
примитивы синхронизации в Java» или «проектирование
параллельных программ может оказаться сложным, и не
исключены ошибки» (фразы взяты из результатов, выданных
поисковой системой). Причиной этой сложности являются доступ к
разделяемым переменным и различные стратегии предотвращения
взаимоблокировок и состязаний между потоками. «Примитивы
синхронизации в Java» - один из примеров такой стратегии, и,
очевидно, многие программисты считают, что пользоваться ими
трудно. Чтобы как-то скрыть сложность, присущую многопоточному
параллелизму, создаются каркасы типа java.util.concurrent, но все
равно некоторые считают, что

попытка упрятать сложность подальше не
делает проблему проще.

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

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

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

query( SELECT \* from db', function (result) {

// произвести какие-то операции с результатом

}):

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

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

Всё

Благодарю за внимание. С вами был незрячий автор, программист и делегат @denis-skripnik. До встречи в новых постах.


Comments 3


Здравствуйте, @denis-skripnik. Вы получили 100% апвот от UPRomo за сожженные GBG. Продвигали сей пост в очереди: @denis-skripnik.
Сервис прибавил к вашему посту примерно 123.191 GBG.

Инструкция по сжиганию для продвижения или задвигания постов.

Соглашение об использовании UPRomo.


Делегируйте СГ сервису UPRomo и способствуйте уменьшению количества GBG, что поможет выйти из кризиса, возобновить GBG и восстановить его цену, равную 1 МГ золота.

10.08.2019 05:04
0