This post is also available in: Английский
Уже стало понятно, что Node.js — яркий тренд в сообществе web-разработчиков. В данной статье мы попытаемся затронуть следующие вопросы: какие подводные камни могут ожидать разработчика, и стоит ли вообще переходить на нее.
В основном Node.js ассоциируется у разработчиков с небольшими сервисами народе чата. (подробнее в статье «Разработка высокопроизводительных сервисов на Node.js»). На то есть веские причины. Нода отлично подходит для сервисов, которые поддерживают постоянное подключение к клиенту, либо долгое время ожидают ответа от него. Отсутствие блокировки ввода/вывода позволит читать большие файлы, оставляя при этом ваш сервис готовым к обработке новых запросов.
Итак, вот за что сообщество так любит Node.js:
• Нода может держать тысячи открытых соединений с клиентами, параллельно с этим осуществляя запись в БД.
• Событийная модель работы отлично подходит для каскадов асинхронных запросов к другим частям приложения.
• Большое и отзывчивое сообщество, а также быстрая скорость разработки самой технологии.
• Множество отличных модулей.
• JSON — родной формат описания объектов. А при использовании MongoDB вообще отпадает вопрос сериализации.
Кстати, нода позволяет также быстро реализовать и высоконагруженные REST-сервисы. А такие модули как express существенно упрощают эту задачу.
Тем не менее у каждой медали есть и обратная сторона.
Неблокиремый поток?
Мнение, что node.js невозможно заблокировать, ошибочно. Архитектурно нода устроена таким образом, что все выполняется в единственном потоке. Соответственно тяжелые математические вычисления спокойно повесят приложение на какое-то время.
Как же с этим бороться? Существует несколько подходов к решению данной проблемы. Все они основаны на идее вынесения тяжелые вычисления из основного потока исполнения (Control Flow). Итак, вот они:
- Разбить выполнение кода на итерации и выполнять их через функцию setTimeout с задержкой в 0 мс. Стоит понимать, что 0 абсолютно не значит, что задержка будет отсутствовать. Это означает, что нода начнет исполнять код так скоро, как сможет. Конечно, придется где-то сохранять промежуточные результаты. Также стоит упомянуть и об увеличении длительности выполнения этих самых вычислений.
- Вынести исполнение в воркеры. По сути такой подход породит дополнительные процессы в системе, в которых и выполнится наш код.
Чтение/запись в файлы и возникновение коллизий
В случае, если вы оперируете содержимым больших файлов между воркерами, то нужно помнить об особенностях доступа к первым. При открытии файла нода получит от системы его дескриптор. В воркеры будет необходимо его передавать
Также часто возникает ситуация, когда нужно уведомить воркеры и другие инстансы ноды о том, что c файлом проводятся манипуляции. Фактически нужно заблокировать файл для других процессов, дабы запретить параллельную запись в него. Для таких целей пишется отдельная нода-контроллер, которая будет выдавать другим разрешение на чтение/запись и составлять очередь ожидания на запись.
Стоит заметить, что такой подход справедлив не только для работы с файлами, но и для любых задач, в которой необходимо обеспечить контроль за коллизиями.
Блокировка исполнения при работе Garbage Collector.
Как известно, Node.js построена на базе движка V8. Его особенность заключается в том, что при запуске GC нода останавливается до окончания его работы. Время задержки напрямую зависит от числа объектов в куче. «Текущие» приложения теряют в производительности именно из-за работы garbage collector. Результаты работы сборщика мусора можно вывести, запустив ноду следующим образом:
node <script> —trace-gc
Существует подход, когда приложение разделяют на несколько частей с целью уменьшения числа объектов в пределах одного модуля системы. Тогда работа сборщика мусора в каждом из них будет занимать меньшее время. Идея правильная, однако стоит помнить, что работу асинхронного кода модулей нужно согласовывать, создавая сложные конструкции.
Таким образом, аккуратное и вдумчивое создание объектов должно стать вашей основной парадигмой при написании сервисов на Node.js.
Подводные камни при отладке.
Отладка ноды — непростая задача. Конечно, можно просто запустить ноду с в debug-режиме. Но удобство отладки приложения в нем довольно низкое. Гораздо проще использовать сторонние приложения:
Этот продукт позволяет удаленно отлаживать ноду в интерфейсе WebInspector, редактировать runtime-код и даже профилировать приложение.
Ниже небольшое видео про отладку ноды при помощи node-inspector
2) PHPStorm/WebStorm Node.js Debugger
Данные редакторы имеют встроенный функционал для локальной и удаленной отладки ноды в своей собственной среде.
Событийная модель, заложенная в Node.js может легко запутать разработчика. Вывод стека, состоящего из последовательных вызовов callback-функций как правило абсолютно не информативен. Тем не менее можно повысить читаемость вывода если принять за правило все коллбекам давать имена. Например:
1 2 3 | setTimeout(function do() { /* Some code here */ }); |
Теперь при выводе стека вы не получите множество сообщений о вызове безымянных функций.
Каскады callback-функций
Сложные приложения на Node.js подразумевают последовательный вызовов множества коллбеков. Часто в коде можно увидеть следующие конструкции:
1 2 3 4 5 6 7 8 9 | do(function () { ... function() { ... function() { ... } } }); |
Читать и поддерживать такой код крайне сложно. Для организации кода при таких ситуациях используются специальные паттерны. Подробнее о них можно прочитать в статье «Node.js Control flow».
Изменчивое API
Нода и ее модули быстро меняются. Потому существуют риски, что новые версии как самой Node.js, так и ее модулей сломают работу всего приложения. Нужно быть готовым к тому, что переход на новые версию означает изменение реализации целых блоков сервиса.
По этой самой причине мы рекомендуем не ставить ни один модуль глобально. Вполне вероятна ситуация, когда 2 разных ноды на одной машине используют 2 несовместимые между собой версии одного и того же модуля.
npm install <module>
Примеры успешного применения Node.js
На GitHub расположен целый список компаний, которые используют ноду в своих сервисах. ознакомится с ним можно по этой ссылке.
Мы остановимся на некоторых из них:
- Yahoo реализовали на ноде фреймворк Mojito, позволяющий писать приложения, работающие как на клиентской, так на серверной стороне, в зависимости от того, какое устройство из запускает.
- Yammer использует сервис на Node.js для кросс-доменного проксирования запросов к API. В качестве основного преимущество разработчики из Yammer приводят возможность ноды обслуживать множество одновременных запросов.
- Bocoup написали на ноде IRC_бота. Выбор в пользу этой технологии был сделан исходя идеи использования JavaScript на стороне сервера (У Bocoup много JS-разработчиков)
Резюме
Использовать или не использовать Node.js — решать только вам, исходя из специфики конкретной задачи. Но стоит понимать, что у нее есть и сильные, и слабые стороны.
Полезные ссылки
- PHP + Apache Stack vs Node.js
- node inspector — инструмент отладки и профилирования
- Running and Debugging Node.Js in WebStorm
- Node.js Control flow