Как стать автором
Обновить

Комментарии 53

Довольно резкая книга. После ее прочтения нет никаких шансов найти оправдания, чтобы не тестировать весь код.
Меньше мутабельности) Вместо Array.prototype.push.apply(arr1, arr2) лучше [...a, ...b]
чем лучше?
Тем, что не меняет массив «a»
Я понимаю, что не меняет. Только зачем, если нужно изменить?
Обратите внимание на то, как и где нужно выставлять LimitNOFILE, чтобы изменения не затирались после очередного апдейта.

habrahabr.ru/post/268583/#comment_8608261
Если Вы сервис создали сами «с-нуля» (как я в примере), то после апгрейда ему ничего не будет. Если модифициворали существующий, то точно затрет, ну тогда вы дали правильную ссылку.
Если сервис создан с нуля, его нужно помещать в /etc/systemd/system, а не /usr/lib/systemd/system.
Туда он поместится при systemctl enable [service]
Нет. enable только создаёт симлинк, например, в цель multi-user (multi-user.target.wants) и ничего никуда не копирует. Вопрос в том, где лежит то, на что будет симлинк.
ps. Хотя, да, если имеется в виду ложить в корень /etc/systemd/system, то все будет работать аналогично.
Ну, если автор ноду пакует в RPM, то вероятно он и свои сервисы раскатывает из пакетов. Тогда класть юниты в {/usr,}/lib/systemd/systemd как раз правильно. Чтобы локально, per-machine, админ мог перекрыть настройки drop-in-ами.
Если пакет, то, конечно, /usr/lib.
Мы это делаем путем внесения правок в конфиг и релоада nginx до и после перезагрузки инстанса.

а почему не через pm2 graceful reload? кстати говоря, у них есть ещё keymetrics.io, из которой можно делать ручной graceful reload и прочие полезные штуки
Потому что я не в курсе что там есть такой функционал :), обязательно попробую. И keymetrics.io тоже мне понравился, буду тестить.
Несколько сумбурно написано и структурированности не хватает. По пунктам:
Теперь перед этими 4-ма инстанами нужно установить балансировщик, который будет распределять нагрузку
Тут, есть множество вариантов, например: Запустить еще один инстанс ноды и задействовать модуль cluster

Cluster-модуль содержит балансировку по воркерам внутри себя, ничего дополнительно ставить не нужно. А вот для статики — действительно, неплохо иметь nginx сверху. Но это опять же ничуть не исключает наличия кластер-модуля в апстриме.

Периодичность перезагрузки (в зависимости от разных причин) от 1 раза в час до 1 раза в сутки.

Я могу понять когда сервис жрет память и не отдает (от чего кстати хорошо помогают лимиты по использованию памяти в pm2), но от чего сервис может становиться более медленным с течением времени — непонятно. Так или иначе, выше уже упомянули про graceful reload. И да, перезагружать весь инстанс довольно странно, если есть кластер-модуль и можно, грубо говоря, послать SIGTERM медленному воркеру.

написано множество cli утилит, которые следят за процессом ноды и в случае необходимости его перегружают

Не могу сказать за остальные три, но могу сказать за pm2 — падает как миленький весь God Daemon :) Особенно на node/io от 0.11 до 4.1.2, из-за бага, имевшего место быть в тех версиях в модуле кластера. Так что за pm2 тоже желательно следить, через upstart-скрипт, например. А можно вообще впилить голый кластер-модуль и мониторить/перезагружать его опять же через upstart.

По пункту 10 — чот вообще вcё в кучу смешалось. Да, мониторинг нужен. Да, юнит-тестирование нужно. Но из пункта сложилось впечатление, что вы предлагаете использовать mocha/jasmine на продакшене для проверки окружения о.0 Это довольно странный способ использования этих фреймворков.
Не могу сказать за остальные три, но могу сказать за pm2 — падает как миленький весь God Daemon :) Особенно на node/io от 0.11 до 4.1.2, из-за бага, имевшего место быть в тех версиях в модуле кластера.

Вы говорите о встроенной кластеризации pm2? У меня сейчас на проекте запускаются воркеры через apps.json с записанными апстримами в nginx, ни одного вылета не заметил
Да. Она там правда не совсем встроенная и тоже использует node-cluster, правда с весьма солидным обвесом. Поэтому и падало, собственно. Был даже вот такой замечательный баг: github.com/nodejs/node-v0.x-archive/issues/9261
И я кажется наврал насчет версии, вроде в io v3 фикс уже приземлился :)
Я могу понять когда сервис жрет память и не отдает (от чего кстати хорошо помогают лимиты по использованию памяти в pm2), но от чего сервис может становиться более медленным с течением времени — непонятно. Так или иначе, выше уже упомянули про graceful reload.

Если даже код идеален, сервис теряет приоритет для операционной системы и начинает работать медленее и это есть проблема. В nginx, например, можно задать принудительно приоритет для процесса параметром worker_priority.

И да, перезагружать весь инстанс довольно странно, если есть кластер-модуль и можно, грубо говоря, послать SIGTERM медленному воркеру.


Вы невнимательно читали, можно использовать модуль cluster, и я об этом написал. Это менее стабильное решение чем балансировщик nginx или ha-proxy. Я не могу понять чем так плохо раз в сутки ребутнуть инстанс ноды?

По пункту 10 — чот вообще вcё в кучу смешалось. Да, мониторинг нужен. Да, юнит-тестирование нужно. Но из пункта сложилось впечатление, что вы предлагаете использовать mocha/jasmine на продакшене для проверки окружения о.0 Это довольно странный способ использования этих фреймворков.


Не совсем так, я не нашел время чтоб расписать, это будет в следующих сериях. В каждом проекте, есть папочка ./spec, там лежат тесты, и да перед тем как на продакшине запустить приложение после апдейта именно на продакшине надо запустить npm test и убедиться что все работает.
Я не могу понять чем так плохо раз в сутки ребутнуть инстанс ноды?
Зависит от нагрузки :) Ребут инстанса означает, что некоторые клиенты могут отвалиться от сервиса или не смогут достучаться до него. Если ночью инстанс пустует — почему бы и нет.

именно на продакшине надо запустить npm test и убедиться что все работает
Вы не думали о внедрении continuous integration с прогоном всех тестов на тестовых средах, идентичных боевым?
НЛО прилетело и опубликовало эту надпись здесь
redis с publish/subscribe, полет отличный
НЛО прилетело и опубликовало эту надпись здесь
Спасибо за полезную информацию.
Молодцы!

Уходите от REST-а, вы его переросли. Переходите на AMQP (а именно RabbitMQ с роутингом). Это даст вам асинхронность и все преимущества event-based loose-coupling системы. В том числе такие приятные вещи, как параллелизация нагруженных узлов, кворумные воутеры, возможность рестарта любого сервиса без потерь, dry-run новых версий сервисов, debug «на ходу» и т.д.

А во вторых — очень любопытно, как вы решаете вопросы совместимости API при внесении breaking changes? Когда у вас десятки сервисов, предполагаю, вам нужно или передепловать всю кучу на новую версию API или поддерживать две версии одновременно. Как именно вы поступаете?
Мы используем RabbitMQ, там где это уместно (точнее RabbitMQ Cluster из 3-х инстансов — так спокойнее).
А во вторых — очень любопытно, как вы решаете вопросы совместимости API при внесении breaking changes?

Поддерживаем и старое и новое API и плавно все сервисы перетекают на новое.
Нода под нагрузкой требует увеличения ограничения nofile limit

Зачем он вам? Вы же не отдаете статику через ноду?

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

Можете примерно сказать нагрузку? У нас тоже есть такое, но начинают тормозить инстансы с говнокодом. За нормальными такого замечено не было.
При асинхронном обращении к большому числу REST-сервисов проблема существует.

У нас проект среднего размера. Мы обслуживаем чуть более полмиллиона пользователей в день. На нагруженых сервисах в пики бывает до 200 req/sec.
9. Не бойтесь использовать ECMAScript 2015 (ES6)

Извините, но пример совершенно не впечатляет, т.к. можно использовать
arr1 = arr1.concat(arr2);

без всяких ES6
НЛО прилетело и опубликовало эту надпись здесь
По поводу шестого пункта.
Может кто-нибудь посоветовать пример проекта с грамотно построенной микросервисной архитектурой?
Из последнего Берлинского митапа по node.js могу порекомендовать отличную презентацию от автора coyno.
Хотя там ориентация была в сторону контейнеризации и использования tutum сервиса для CI
По поводу утечек памяти и перезагрузок. В конечном счёте обычно выясняется, что виноват код, либо ваш, либо npm. У нас игра на nodejs, очень интенсивная, сетевое взаимодействие через websocket с клиентами. Были «детские» проблемы, которые тоже время от времени забивали память и приходилось перезагружать инстанс, но под пристальным анализом они все были выявлены и исправлены, и да, все они были в коде приложения, хотя далеко не все были так очевидны, т.е. на первый взгляд казалось, что всё в коде хорошо. Но анализ дампов heap и примерных ситуаций, в которых они возникали, помог их выявить. Сейчас инстансы работают спокойно столько, сколько нужно. Неделю недавно работали, т.к. долго не апдейтили код.
У меня ещё есть сайт написанный на node.js, там тоже всё отлажено, писал давно его и долго мучился сначала, но после того, как все проблемы устранил — работает без перезагрузок вообще, поскольку код там не обновляется, аптайм там месяцами измеряется. Ну и все относительно популярные модули npm довольно серьёзно относятся к проблемам утечек памяти, в целом с ними там ситуация хорошая, их либо нет, либо их быстро исправляют.
НЛО прилетело и опубликовало эту надпись здесь
Все ситуации разные. Подход один: когда видим, что память расходуется не так, как должна, делаем дамп heap и разбираем его в профайлере (Google Chrome). Когда нормальный расход процесса, например, 100Мб, а фактический — гигабайт, не сложно будет увидеть, что за объекты наполняют heap. Ну а далее — думаем, почему GC их не собрал. Причины появления в программе разные, но причина не сбора обычно одна — где-то осталась ссылка на объект, возможно и не явная. Мог где-то быть запущен setInterval или установлен EventListener, в область видимости которого попадает объект. Может быть взаимная ссылка между объектами — очень коварный баг. Ещё могут заполняться буферы, если куда-то пишут быстрее, чем читают. Вообще ситуаций полно, каждую раскручивать нужно исходя из того, что именно утекло.
Каков масштаб проекта? У нас в проекте использование профайлера весьма затруднено из-за чудовищной вложенности вызовов, которая в свою очередь является следствием огромной кодобазы и массы библиотек, пробовали профилировать — погрязли в цепочках вызовов, плюнули, оставили как есть. Очевидно, что нужен рефакторинг, но непонятно в какую сторону двигаться.

В общем, присоединюсь к просьбе поделиться опытом, возможно даже в виде статьи, а не комментария :)
Я конечно JS только начал изучать и могу ляпнуть чушь, но не помогут ли для профилирования проблемных инстансов FlameGraphs? Я понимаю, что они как бы для профилирования onCPU/offCPU, но может быть имеет смысл сравнить срезы нормальных и проблемных инстансов на предмет подозрительных изменений цепочек вызовов?
Пожалуй, но проблема тут скорее в том, что нормальных инстансов нет, есть только проблемные %)
Это ж какой у вас QPS к каждому процессу ноды, что нужно 131070? Или это просто «с потолка», и реально хватило бы 5000-8000? Замеряли реальное потребление fd?
8000 не хватает. Для большинства случаев хватает 16000 я уже об этом писал.
Да тут указан лимит «с запасом», а в чем проблема увеличения этого лимита?
Проблем нет, интересна нагрузка, требующая такого количества дескрипторов, и при этом вытягиваемая нодой.
Паралельное обращение к микросервисам, любой внешний request это открытый файловый дескриптор.
А keep-alive?
keep-alive включен «по-умолчанию», мы его не отключаем.
В следующих сериях мы рассмотрим тюнинг ядра для нужд ноды, грабли виртуализации, как правильно закэшировать nginx-ом ответы от инстансов nodejs.

"..., а Германа всё нет."

Нода не однопоточная, так как использует под капотом libuv, который как минимум использует дополнительный поток для i/o операций да и несколько потоков для работы с запросами ей ни к чему, там все работает на основе non-blocking event-driven I/O. W. Richard Stevens в своей книге "Unix network programming" отлично объясняет этот момент

Node.js является однопоточным по своей сути. Он работает в одном потоке через архитектуру Event Loop. Да он использует библиотеку libuv в отдельном потоке, но многопоточный код все равно написать не получиться, если это не так то напишите мне пример кода который работает, к примеру, в 10 потоков.
В контексте этой статьи если у вас 4 ядра, напишите мне код на nodejs, который займет ресурсы всех 4-х ядер, кроме варианта запустить одновременно 4 копии одного и того же js-скрипта.

worker_threads, нативная библиотека ноды, создает реальный отдельный поток

Это неполноценная многопоточность, по сути библиотека запускает отдельный инстанс nodejs для каждого потока и организовывает общение между потоками через специальные объекты message passing, при этом у потоков нету доступа к общим ресурсам, нету общих переменных, общего контекста, невозможно организовать прослушивание веб-сервером одного и того же порта, там можно поизвращаться и передавать дочерним потокам запросы, но это уже будут "костыли".
Поэтому все пункты статьи остаются актуальными, надежнее запустить reverse proxy (например, nginx) и за ним несколько отдельных инстансов nodejs, чем колхозить на worker_threads.

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

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории