- PVSM.RU - https://www.pvsm.ru -

Потоки vs процессы на примере нативного Node.js аддона для нагрузочного тестирования

Чуть меньше года назад я написал заметку [1] о попытке создать инструмент нагрузочного тестирования на Node.js используя встроенные возможности (модули cluster и net). В комментариях справедливо указали на необходимость анализа RPS и сравнении с другими бенчмарками. В результате сравнения я пришел к естественному выводу, что многопроцессовый сервис никогда не сравнится по производительности с многопоточным из-за очень дорогих издержек на обмен данными (позже мы убедимся в этом на примере)

Процессы или потоки?

В первого взгляда существенной разницы нет, и то и то обеспечивает параллельность запросов, разница только в shared memory для потоков и сам процесс создания процессов чуть более дорогой. Но ведь мы можем создать все процессы заранее и просто передавать им задачи. Но теперь нам нужен канал общения. Давайте посмотрим какие имеются способы межпроцессорного взаимодействия:

Сигналы

Быстрый и универсальный (поддерживается почти всеми ОС) метод общения системы и процессов. Проблема в исключительной негибкости, да и не для того они создавались, чтобы слать по ним JSON.

Сокеты

Именно так реализован cluster в Node. Метод process.send вызывает отправку данных другому процессу по TCP. Что значит сокеты? Это значит новый дескриптор на каждый вызов, куча I/O и CPU вхолостую.

Есть еще несколько способов, но все они либо не кроссплатформенны либо также зависят от I/O.
А теперь посмотрим на состояние системы, когда мы создаем 100 процессов:

Потоки vs процессы на примере нативного Node.js аддона для нагрузочного тестирования - 1

И 100 потоков:

Потоки vs процессы на примере нативного Node.js аддона для нагрузочного тестирования - 2

Очевидно, что теперь CPU занят лишь тем, чтобы поддерживать связь между этими примитивными процессами (каждый должен выполнять по одному запросу, иначе V8 поставит их в синхронный event loop). CPU utilization падает и каждый запрос выполняется дольше (не дай бог еше память кончится и пойдет файл подкачки)

Но ведь нода однопоточна, что делать?

Потоки vs процессы на примере нативного Node.js аддона для нагрузочного тестирования - 3

Делать нативный аддон на С++, используя multithreading. Nan, Node-gyp, POSIX threads и в итоге аддон [2] стал похож на ab — на вход поступает concurrency, на выходе — результаты тестирования. Только в отличии от ab мы можем пользоваться всеми возможностями js для анализа результатов:

[ { time: 80,
      body: '<!doctype html><html itemscope=...',
      headers: 'HTTP/1.1 200 OKrnDate: Mon, 28 Dec 2015 10:37:35 GMTrnConnection: closernrn' },
....
]

Поддерживаются дополнительные хедеры, POST payload и поскольку это POSIX, то к сожалению только Linux/Mac.
При желании можно считывать только хедеры, обычно этого достаточно, тогда можно сэкономить
еще немного времени на процессинге.

В итоге по производительности nnb сравнялся с ab, выдавая на разных машинах и сетях до 3000 RPS.

Зачем это нужно?

Есть JMeter, есть Tsung, есть масса других платных и бесплатных бенчмарков, но причина по которой многие из них не приживаются в арсенале разработчиков — перегруженный функционал и в итоге все равно недостаточная гибкость. На основне nnb [2] же можно создать свой инструмент для специфических целей или просто скрипт из 10 строчек, который делает только что вам нужно на одном из самых популярных языков.
К примеру stress [3], который можно запустить с дефолтовым конфигом и смотреть в лайве что происходит с RPS гугла при росте нагрузки (спойлер: ничего) прямо в браузере и на любой unix машине.

Потоки vs процессы на примере нативного Node.js аддона для нагрузочного тестирования - 4

Здесь по оси абсцисс кол-во отправленных запросов, по оси ординат — время отклика сервера в миллисекундах. На втором графике запросы в секунду. В конце видно замедление, это вероятно меня начал резать хостер [4].

К сожалению, с доступными мне машинами достичь больше 5000 RPS пока не удалось. Обычно все упирается в ограничения сети. При этом CPU и память почти не нагружены. Stress кстати поддерживает и Node.js cluster и мультипоточность через nnb. Можно играться и с тем и тем, предварительно выставив ulimit -u (максимальное количество процессов запущенное пользователем) и ulimit -n (максимальное количество дескрипторов).

Надеюсь, статья была полезной. По-прежнему рад сотрудничеству со всеми, кому интересна эта тема и, конечно, с наступающим!

Автор: yarax

Источник [5]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/node-js/107742

Ссылки в тексте:

[1] заметку: http://habrahabr.ru/post/249403/

[2] аддон: https://github.com/yarax/nnb

[3] stress: https://github.com/yarax/stress

[4] хостер: https://www.reg.ru/?rlink=reflink-717

[5] Источник: http://habrahabr.ru/post/274287/