Node.js и фрагментация

Фон. Я пришел из мира Microsoft, в котором у меня были сайты, хранящиеся в IIS. Опыт научил меня перерабатывать мой пул приложений один раз в день, чтобы устранить странные проблемы из-за фрагментации. Утилизация пула приложений в основном означает перезапуск приложения без перезагрузки всего IIS. Я также смотрел лекцию, в которой объяснялось, как Microsoft значительно сократила фрагментацию в .Net 4.5.

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

Чтобы обеспечить быстрое распределение объектов, короткие паузы в сборке мусора и "без фрагментации памяти V8" используется стоп-мир, генератор, точный сборщик мусора.

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

Итак, мой вопрос:

Должен или не должен перезапускать приложение каждый раз, а затем во избежание фрагментации?

Ответ 1

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

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

  • Настройте некоторые инструменты мониторинга, такие как https://newrelic.com/, которые позволяют вашему монитору работать.
  • Постоянно контролируйте свою память. Попытайтесь увидеть, есть ли постоянное увеличение объема потребляемой памяти, или если она выравнивается.
  • Определите приемлемый порог, прежде чем вам нужно будет действовать. Например, если ваше приложение потребляет 60% системной памяти, вам нужно начать думать о перезапуске сервера и выбрать интервал перезагрузки.
  • Решите, согласны ли вы с "простоями" при перезапуске или нет. Если вы не хотите простоя, вам может понадобиться создать прокси-слой для прямого трафика.

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

Ответ 2

Я согласен с @Parris. Вероятно, вам следует выяснить, действительно ли вам нужна политика перезапуска. Я бы предложил использовать pm2 docs здесь. Даже если вы не хотите подписываться на ключевые вопросы, это довольно хороший менеджер процессов и очень быстро настраивается. Вы можете получить отчет об использовании памяти из командной строки. Выглядит примерно так.

pm2 output

Кроме того, если вы начинаете работу в режиме кластера, как описано выше, вы можете вызвать pm2 restart my_app, и первый, вероятно, снова появится до того, как последний будет удален в автономном режиме (это дополнительное преимущество, настоящая причина наличия 8 процессов - использовать все 8 ядер). Если вы непреклонны в отношении простоя, вы можете перезапустить их по 1 на 1 по идентификатору.

Ответ 3

Я согласен с @Parris, это кажется преждевременной оптимизацией. Кроме того, перезапуск не является решением основной проблемы, это лечение симптомов.

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

Я считаю, что две вещи помогут вам.

  • неизменные объекты помогут много, они намного более предсказуемы, чем использование изменяемых объектов, и на них не будет влиять продолжительность жизни проекта. Кроме того, поскольку неизменяемые объекты являются только блоками памяти только для чтения, они быстрее, чем изменяемые объекты, которые серверу приходится тратить ресурсы, решая, читать ли или записывать в блок памяти, который хранит объект. В настоящее время я использую библиотеку под названием IMMUTABLE, и она работает хорошо для меня. Есть и другие, такие как Deep Freeze, однако я никогда не использовал его.

  • Убедитесь, что вы правильно управляете своими приложениями, утечка памяти является второй большой причиной этой проблемы, с которой я столкнулся. Опять же, это можно решить, подумав о том, как структурировано ваше приложение и как обрабатываются пользовательские события, убедившись, что процесс не используется клиентом, чтобы он был правильно удален из heap, если он не является heap продолжает расти до тех пор, пока не будет уничтожена вся память, что приведет к сбою приложения (см. рисунок ниже, чтобы увидеть схему памяти V8 и где находится heap). node - это программа на С++, и она контролируется Google V8 и Javascript.

Схема памяти V8

Вы можете использовать Node.js process.memoryUsage() для отслеживания использования памяти. Когда вы определяете, как управлять своей кучей, V8 предлагает два решения: один - это Scavenge, который очень быстрый, но неполный. Другой - Mark-Sweep, который медленный и освобождает всю память без ссылок.

Обратитесь к this в блоге для получения дополнительной информации о том, как управлять своей кучей и управлять своей памятью на V8, который запускает Node.js

Таким образом, ответственный подход к вашей реализации заключается в том, чтобы внимательно следить за открытыми процессами, глубоким пониманием heap и как освобождать блоки памяти без ссылок. Создание вашего проекта с учетом этого также делает проект намного более масштабируемым, а также.