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

В рамках нашей работы в MyHeritage мы разработали двойное приложение для конкурса Евровидение 2019, где вы можете сделать селфи и узнать, на какую звезду Евровидения вы больше всего похожи.

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

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

  1. Надейтесь на лучшее, ожидайте худшего: измерьте, сколько одновременных пользователей может обслуживать ваше приложение за X промежуток времени (за один раз). Например, в нашем случае тест определил, что мы можем обслуживать 200 одновременных пользователей в каждом экземпляре EC2 в течение 10 секунд, поэтому, когда мы знали, что должны обслуживать 10 000 одновременных пользователей, нам просто нужно было подготовить 50 серверов за нашим балансировщиком нагрузки. Мы использовали отличный инструмент под названием JMeter для выполнения этого теста.
    Мы нашли этот учебник полезным для выполнения нагрузочного тестирования с использованием JMeter.
  2. Избегайте блокировки: блокирующие действия (такие как fs.readSync) заманчивы, потому что они выглядят чище в вашем коде, но они буквально убивают производительность. Вместо этого используйте async / await, потому что пока выполняется асинхронное действие, ЦП может обрабатывать другие задачи (Цикл событий).
    До: const res = fs.readSync('file.txt');
    После: const res = await fs.readAsync('file.txt');
  3. Увеличьте лимит памяти. По умолчанию узел настроен на ограничение памяти в 1 ГБ. Предполагая, что ваш сервер выделил 4 ГБ только для вашего приложения, вам придется вручную установить максимальный предел памяти, используя Node CLI и следующий флаг: --max-old-space-size
    Например: node --max-old-space-size=4096 server.js
  4. Убедитесь, что вы используете все ядра процессора. Node по умолчанию является однопоточным. Если вы не определили какую-либо специальную конфигурацию, которая запускает несколько потоков Node на одном сервере, сэкономьте деньги и выберите сервер только с 1 ядром.
  5. Сохраните поездки в свое приложение. Используйте правила страницы, такие как принудительное использование HTTPS или постоянное перенаправление на самом высоком уровне (например, прокси). Это сделает ваше приложение менее загруженным и более доступным для получения новых запросов, которые действительно необходимо обработать.
  6. Обработка ошибок. Используйте средство ведения журнала, например Logz.io/AWS CloudWatch, для отслеживания ошибок, которые могут легко привести к сбою вашего приложения. НЕ сообщайте обо всех своих ошибках в такие службы, как Slack, потому что ошибок обычно много, и они могут легко заблокировать ваше приложение для регулирования. Мы использовали отличную библиотеку для логирования NodeJS под названием Winston.

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

Спасибо за чтение 🙂