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