Статьи

5 советов по повышению производительности приложений Node.js


«Если #nginx не сидит перед сервером вашего узла, вы, вероятно, делаете это неправильно».
Брайан Хьюз в Твиттере

Node.js — это ведущий инструмент для создания серверных приложений на JavaScript, самом популярном в мире языке программирования. Предлагая функциональность как веб-сервера, так и сервера приложений, Node.js теперь считается ключевым инструментом для всех видов разработки и доставки на основе микросервисов. (Загрузите бесплатный отчет Forrester на Node.js и NGINX .)

Node.js может заменить или дополнить Java или .NET для разработки серверных приложений.

Node.js является однопоточным и использует неблокирующий ввод / вывод, что позволяет ему масштабировать и поддерживать десятки тысяч одновременных операций. Он разделяет эти архитектурные характеристики с NGINX и решает проблему C10K — поддерживает более 10 000 одновременных подключений — которую NGINX также придумал для решения. Node.js известен высокой производительностью и производительностью разработчиков.

Итак, что может пойти не так?

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

Кроме того, Node.js является отличным инструментом для создания и запуска логики приложения, которая создает основное, переменное содержимое для вашей веб-страницы. Но он не так хорош для обслуживания статического контента — например, изображений и файлов JavaScript — или для распределения нагрузки между несколькими серверами.

Чтобы получить максимальную отдачу от Node.js, вам необходимо кэшировать статический контент, прокси и балансировку нагрузки между несколькими серверами приложений, а также управлять конфликтами портов между клиентами, Node.js и помощниками, такими как серверы, на которых работает Socket.IO. NGINX можно использовать для всех этих целей, что делает его отличным инструментом для настройки производительности Node.js.

Используйте эти советы для улучшения производительности приложения Node.js:

  1. Реализовать обратный прокси-сервер
  2. Кэшировать статические файлы
  3. Распределение нагрузки между несколькими серверами
  4. Прокси-соединения WebSocket
  5. Реализация SSL / TLS и HTTP / 2

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

1. Реализация обратного прокси-сервера

Мы в NGINX, Inc. всегда немного испуганы, когда видим, что серверы приложений напрямую подвержены входящему интернет-трафику, используемому в ядре высокопроизводительных сайтов. Это включает в себя , например, много сайтов на WordPress , а также сайты Node.js.

Node.js в большей степени, чем большинство серверов приложений, предназначен для масштабируемости, и его сторона веб-сервера может достаточно хорошо обрабатывать большую часть интернет-трафика. Но веб-сервис не является смыслом существования Node.js — не то, для чего он был создан.

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

NGINX работает как обратный прокси-сервер Node.js

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

Существуют определенные преимущества использования NGINX в качестве обратного прокси-сервера Node.js , в том числе:

  • Упрощение обработки привилегий и назначения портов
  • Более эффективное обслуживание статических изображений (см. Следующий совет )
  • Manage Node.js успешно падает
  • Смягчение DoS-атак

Примечание . В этих руководствах объясняется, как использовать NGINX в качестве обратного прокси-сервера в средах Ubuntu 14.04 или CentOS , и они полезны для любого, кто ставит NGINX перед Node.js.

2. Кэширование статических файлов

По мере роста использования сайта на базе Node.js сервер начнет демонстрировать нагрузку. На этом этапе вы хотите сделать две вещи:

  1. Получите максимум от сервера Node.js.
  2. Упростите добавление серверов приложений и распределение нагрузки между ними.

Это на самом деле легко сделать. Начните с реализации NGINX в качестве обратного прокси-сервера, как описано в предыдущем разделе. Это позволяет легко реализовать кэширование, балансировку нагрузки (если у вас несколько серверов Node.js) и многое другое.

На сайте для Modulus, платформы контейнеров приложений, есть полезная статья о повышении производительности приложений Node.js с помощью NGINX. С Node.js, выполняющим всю работу самостоятельно, сайт автора мог обслуживать в среднем почти 900 запросов в секунду. С NGINX в качестве обратного прокси-сервера, обслуживающего статический контент, один и тот же сайт обслуживал более 1600 запросов в секунду — повышение производительности почти в 2 раза.

Удвоение производительности дает вам время, чтобы предпринять дополнительные шаги для обеспечения дальнейшего роста, такие как проверка (и, возможно, улучшение) дизайна вашего сайта, оптимизация кода вашего приложения и развертывание дополнительных серверов приложений.

Ниже приведен код конфигурации, который работает для веб-сайта, работающего на модуле :

server {
  listen 80;
  server_name static-test-47242.onmodulus.net;

  root /mnt/app;
  index index.html index.htm;

  location /static/ {
   try_files $uri $uri/ =404;
  }

  location /api/ {
   proxy_pass http://node-test-45750.onmodulus.net;
  }
}

Например, в блоке расположения NGINX вы, вероятно, захотите освободить часть содержимого от кэширования. Например, обычно вы не хотите кэшировать административный интерфейс для платформы блогов. Вот код конфигурации, который отключает [или освобождает] кэширование административного интерфейса Ghost:

location ~ ^/(?:ghost|signout) { 
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header Host $http_host;
        proxy_pass http://ghost_upstream;
        add_header Cache-Control "no-cache, private, no-store,
        must-revalidate, max-stale=0, post-check=0, pre-check=0";
    }

Кэширование статических файлов на сервере NGINX значительно разгружает работу с сервера приложений Node.js, что позволяет ему достичь гораздо более высокой производительности.

3. Внедрить балансировщик нагрузки Node.js

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

Балансировка нагрузки Node.js может быть особенно сложной, поскольку Node.js обеспечивает высокий уровень взаимодействия между кодом JavaScript, выполняемым в веб-браузере, и кодом JavaScript, выполняемым на сервере приложений Node.js, с объектами JSON в качестве средства обмена данными. Это подразумевает, что данный клиентский сеанс постоянно выполняется на определенном сервере приложений, и постоянство сеанса по своей природе трудно достичь с несколькими серверами приложений.

Одним из основных преимуществ Интернета и Интернета является их высокая степень безгражданства, которая включает возможность выполнения клиентских запросов любым сервером, имеющим доступ к запрашиваемому файлу. Node.js подрывает безгражданство и лучше всего работает в среде с состоянием, где один и тот же сервер последовательно отвечает на запросы от любых конкретных клиентов.

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

NGINX поддерживает методы балансировки нагрузки без сохранения состояния :

  • Круглый Робин . Новый запрос отправляется на следующий сервер в списке.
  • Наименее Связи . Новый запрос отправляется на сервер, который имеет наименьшее количество активных соединений.
  • IP Hash . Новый запрос отправляется на сервер, назначенный хэшу IP-адреса клиента.

Только один из этих методов, IP Hash, надежно отправляет запросы данного клиента на тот же сервер, что выгодно для приложений Node.js. Однако IP-хэш может легко привести к тому, что один сервер получит непропорциональное количество запросов за счет других серверов, как описано в этом сообщении в блоге о методах балансировки нагрузки. Этот метод поддерживает отслеживание состояния за счет потенциально неоптимального распределения запросов по ресурсам сервера.

В отличие от NGINX, NGINX Plus поддерживает сохранение сессии . При постоянном использовании сеанса один и тот же сервер надежно получает все запросы от данного клиента. Преимущества Node.js с его связью с состоянием между клиентом и сервером, а также NGINX Plus с его расширенными возможностями балансировки нагрузки максимально увеличены.

Таким образом, вы можете использовать NGINX или NGINX Plus для поддержки балансировки нагрузки между несколькими серверами Node.js. Однако только с NGINX Plus вы сможете достичь как максимальной производительности балансировки нагрузки, так и дружественного состояния Node.js. В мед.обследование приложений и возможности контроля , встроенные в Nginx Plus полезны здесь.

NGINX Plus также поддерживает удаление сеансов , что позволяет серверу приложений корректно завершать текущие сеансы после запроса на отключение сервера.

4. Прокси-соединения через WebSocket

HTTP во всех версиях предназначен для «вытягивания» связи, когда клиент запрашивает файлы с сервера. WebSocket — это инструмент, позволяющий осуществлять связь «push» и «push / pull», где сервер может заблаговременно отправлять файлы, которые клиент не запрашивал.

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

Протокол WebSocket имеет надежный интерфейс JavaScript и, как таковой, вполне подходит для Node.js в качестве сервера приложений, а также для веб-приложений с умеренным объемом транзакций в качестве веб-сервера. Когда объемы транзакций растут, имеет смысл вставить NGINX между клиентами и веб-сервером Node.js, используя NGINX или NGINX Plus между несколькими серверами приложений.

Node.js часто используется вместе с Socket.IO — API WebSocket, который стал довольно популярным для использования вместе с приложениями Node.js. Это может вызвать переполнение порта 80 (для HTTP) или порта 443 (для HTTPS), и решение состоит в том, чтобы прокси-сервер к серверу Socket.IO. Вы можете использовать NGINX для прокси-сервера , как описано выше, а также получить дополнительные функции, такие как статическое кэширование файлов, балансировка нагрузки и многое другое.

Node.js и Socket.IO с NGINX

Ниже приведен код файла приложения узла server.js, который прослушивает порт 5000. Он действует как прокси-сервер (не веб-сервер) и направляет запросы на соответствующий порт:

var io = require('socket.io').listen(5000);

io.sockets.on('connection', function (socket) {
  socket.on('set nickname', function (name) {
    socket.set('nickname', name, function () {
      socket.emit('ready');
    });
  });

  socket.on('msg', function () {
    socket.get('nickname', function (err, name) {
      console.log('Chat message by ', name);
    });
  });
});

var socket = io (); // ваш код инициализации здесь.

Подробные инструкции, включая настройку NGINX, см. В нашем блоге об использовании NGINX и NGINX Plus с Node.js и Socket.IO . Более подробную информацию о потенциальных проблемах архитектуры и инфраструктуры для веб-приложений такого рода можно найти в нашем блоге о веб-приложениях реального времени и WebSocket.

5. Внедрить SSL / TLS и HTTP / 2.

Все больше и больше сайтов используют SSL / TLS для защиты всего взаимодействия с пользователем на сайте. Вы сами решаете, делать ли этот шаг и когда, но если и когда вы это сделаете, NGINX поддерживает переход двумя способами:

  1. Вы можете разорвать соединение SSL / TLS с клиентом в NGINX, как только вы настроили NGINX в качестве обратного прокси-сервера. Сервер Node.js отправляет и получает незашифрованные запросы и контент туда и обратно с обратным прокси-сервером NGINX.
  2. Ранние признаки — то, что использование HTTP / 2 , новой версии протокола HTTP, может в значительной степени или полностью компенсировать снижение производительности, которое иначе наложено использованием SSL / TLS. NGINX поддерживает HTTP / 2, и вы можете завершить HTTP / 2 вместе с SSL, снова устраняя необходимость внесения изменений в сервер (ы) приложений Node.js.

Среди шагов по внедрению, которые вам необходимо предпринять, — обновление URL-адреса в файле конфигурации Node.js, создание и оптимизация безопасных соединений в вашей конфигурации NGINX и использование SPDY или HTTP / 2, если это необходимо. Добавление поддержки HTTP / 2 означает, что версии браузера, поддерживающие HTTP / 2, обмениваются данными с вашим приложением по новому протоколу; Более старые версии браузера продолжают использовать HTTP / 1.x.

Используйте HTTP / 2 и SSL / TLS с Node.js

Следующий код конфигурации предназначен для блога Ghost, использующего SPDY, как описано здесь . Он включает в себя расширенные функции, такие как сшивание OCSP. Сведения об использовании NGINX для завершения SSL, включая параметр сшивания OCSP, см. Здесь . Общий обзор тех же тем смотрите здесь .

Вам необходимо внести незначительные изменения, чтобы настроить приложение Node.js и перейти с SPDY на HTTP / 2, сейчас или когда поддержка SPDY прекратится в начале 2016 года.

server {
   server_name domain.com;
   listen 443 ssl spdy;
   spdy_headers_comp 6;
   spdy_keepalive_timeout 300;
   keepalive_timeout 300;
   ssl_certificate_key /etc/nginx/ssl/domain.key;
   ssl_certificate /etc/nginx/ssl/domain.crt;
   ssl_session_cache shared:SSL:10m;  
   ssl_session_timeout 24h;           
   ssl_buffer_size 1400;              
   ssl_stapling on;
   ssl_stapling_verify on;
   ssl_trusted_certificate /etc/nginx/ssl/trust.crt;
   resolver 8.8.8.8 8.8.4.4 valid=300s;
   add_header Strict-Transport-Security 'max-age=31536000; includeSubDomains';
   add_header X-Cache $upstream_cache_status;
   location / {
        proxy_cache STATIC;
        proxy_cache_valid 200 30m;
        proxy_cache_valid 404 1m;
        proxy_pass http://ghost_upstream;
        proxy_ignore_headers X-Accel-Expires Expires Cache-Control;
        proxy_ignore_headers Set-Cookie;
        proxy_hide_header Set-Cookie;
        proxy_hide_header X-powered-by;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto https;
        proxy_set_header Host $http_host;
        expires 10m;
    }
    location /content/images {
        alias /path/to/ghost/content/images;
        access_log off;
        expires max;
    }
    location /assets {
        alias /path/to/ghost/themes/uno-master/assets;
        access_log off;
        expires max;
    }
    location /public {
        alias /path/to/ghost/built/public;
        access_log off;
        expires max;
    }
    location /ghost/scripts {
        alias /path/to/ghost/core/built/scripts;
        access_log off;
        expires max;
    }
    location ~ ^/(?:ghost|signout) { 
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header Host $http_host;
        proxy_pass http://ghost_upstream;
        add_header Cache-Control "no-cache, private, no-store,
        must-revalidate, max-stale=0, post-check=0, pre-check=0";
        proxy_set_header X-Forwarded-Proto https;
    }
}

Вывод

В этом блоге описаны некоторые из наиболее важных улучшений производительности, которые вы можете внести в свои приложения Node.js. Основное внимание уделяется добавлению NGINX в ваш набор приложений наряду с Node.js — путем использования NGINX в качестве обратного прокси-сервера, для кэширования статических файлов, для балансировки нагрузки, для прокси-соединений WebSocket и для завершения SSL / TLS и HTTP / 2. протоколы.

Комбинация NGINX и Node.js широко известна как способ создания новых приложений, дружественных к микросервисам, или повышения гибкости и возможностей существующих приложений на основе SOA, использующих Java или Microsoft .NET. Этот пост поможет вам оптимизировать ваши приложения Node.js и, если вы захотите, оживить сотрудничество между Node.js и NGINX.