Pull to refresh

Node.JS + taskset == немного странного юмора

Reading time 6 min
Views 11K
Регулярно слышу фразу типа «Node.js не подходит для хайлоада».

Захотелось самому посмотреть.

Хотел написать комментарий к той статье, но передумал и написал больше. Автору той статьи, большое спасибо за интересный топик, задело.

В интернете кто-то не прав. Наших бъют! Обидно, да. Для себя выводы кое-какие сделал, но это же мои субъективные цифры. Что думать в целом — не знаю, пишите пожалуйста в каментах своё мнение.

UPD 3 По результатам обсуждения найдено то, что было нужно написать с самого начала, то, что я подразумевал, а именно: что тест не репрезентативный, единственное, что он показывает — что На Моей очень слабой машине нода отстаёт on Nginx на пол порядка всего. Нода, как и Nginx, почти ничего не делают, в этом смысле они «равны». Хотел показать, что есть taskset, что нода может не перегружать проц при определённых условиях, что не нужно верить тестам.

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

UPD 1 немножко по-tag'ал как «юмор», м. б. так будет правильней.
UPD 2 не верьте ни единому слову!



Я — шаман! Тихо беру в руки бубен и расчехляю варган

Не люблю ресурсы, т.к. понимаю, что в случае ЧС их у меня не будет.
Поэтому у меня они весьма скромны: AMD C-60 / 4 Gb / SSD.

Всё это запаковано в нетбук, весит около килограмма и управляется Linux Mint. Предвижу вопросы, поэтому отвечу сразу. Да, бывает и такое, что я готовлю. Ещё я крестиком вышивать умею как Матроскин. Пою на гитаре как Элвис. По дому там могу гвоздь забить пассатижами. В общем — подарок семье: незаменимый специалист широкого профиля.

А увлекаюсь я программированием на JavaScript. Нет, я могу читать Python, Ruby, PHP, Perl, VB, C#, Java, etc. Но писать не могу, «не лежит душа». И образования у меня нет профильного, ИТ-шного, поэтому пользуюсь банальной логикой и тем, что от природы иногда предпочитаю думать своей собственной головой, а не чъей-нибудь чужой. Тем и живу.

Поставили мне Заказчики задачу сферического сравнительыного анализа Node.JS и Nginx. Т.к. мерять нужно было потенциальную производительность самой ноды, то задачу поставили хитро:

— NGINX отдаёт только свою дефолтную статическую страницу index.html.
— Сервер Node должен вести подсчёт соединений и выдавать в каждом ответе результат, так же считать и максимальное количество.
— Клиентское ПО должно считать количество обработанных запросов в секунду, т.е. удачно завершившихся со статусом 200 OK.

Понятно, что nginx выиграет. Но суть не в нём, а в сравнении. Т.е. именно во сколько раз интерпретатор ноды хуже чем статика Nginx.

Конечно, я понимаю, что заставить ноду отдавать статику тоже можно. Но Вы попробуйте научить nginx бизнес-логике в десяток таблиц за пару часов?

Ссылка на GIT будет в конце. Use Case тем кто «в танке» будет там же.

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

Все мы знаем, что современные процессоры работают последовательно.

Знаем то все, но вот понимаем как хотим, а не так как правильно!

Скажите, Вы можете думать над несколькими вещами сразу? А если в этот момент зазвонит телефон и Вам нужно будет ответить на звонок? А если параллельно с телефоном к Вам подойдёт человек-коллега, к котор[ой||му] у Вас симпатия и задаст какой-нибудь очень важный вопрос? А если при этом ещё вдруг мимо будет проходить человек-БОСС, заглянет в экран на котором в несвёрнутом окне браузера красуется лурк или ещё чего веселей?

Вот то то же — обработка прерываний и переполнение стека.

Казалось бы — при чём здесь асинхронность?

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

У Вас, например, максимально мозг может удерживать 8 оперативных задач, по аналогии с 8-ю ядрами проца. Остальные — они где-то там, когда-то будут, до них ещё далеко.

Сами думайте как это представить, поиграйте в Загадку Энштейна чтоль. Получается у Вас там всю многопоточность только в голове удержать (как в L1-L2 Cache), всмысле, да — без листочка (Mem)?




Вот теперь давайте считать.

Запускаете Вы свою приложуху на ноде, там у Вас стандартный код, может быть отсюда .

var cluster = require('cluster');
var numCPUs = require('os').cpus().length;
...

for (var i = 0; i < numCPUs; i++) {
    cluster.fork();
...


Или что-нибудь похожее, с многопоточностью.

Как Вы думаете, кто будет потоками рулить?

Правильно — Operating System.
А в системе кто ими рулит?

Правильно — Linux Kernel \ Windows Core — Hardware Abstraction Layer (hal.dll, наверное, могу ошибаться).

Пока вроде бы, ничего такого подозрительного нет.

Но давайте всё-таки чуточку подумаем ещё!
Пусть кроме ноды у нас больше вообще ничего не установлено.

Что ещё есть на этом «железе» кроме неё?
Правильно — Operating System.

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

Итак, каждое из железных ядер процессора считает последовательно. Над ними исполняемый код ядра, который типа пытается ВСЁ представить как параллельное мультизадачное и прочие рюшечки. Внутри, под управлением ядра OS крутится однопоточный код нодовых процессов, которых у нас 8 штук, по количеству ядер CPU.

Что будет с полимерами когда к нам поступит «IO» в ядро по сетевому стеку, например по HTTP? Вроде пока ядро OS справляется…

А если нода уже всё утилизировала на всех 8-ми ядрах? Вроде пока ядро OS тоже справляется…

Но здесь я бы уже хотел посмотреть на бенчмарк!

Давайте так и поступим!

  1. Сравним ноду с Nginx, как описано в задачке выше.
  2. Сравним отзывчивость ноды с полной загрузкой CPU и без неё.


Сразу скажу, что все тесты я крутил минут по 10, занимаясь при этом обычными задачами типа кода и сёрфинга.

Да, для того, чтобы заставить процесс работать лишь на определённых ядрах в Linux существует taskset.

В ноде я использую его так:

  var PID = process.pid;
  exec('taskset -pc ' + affinity + ' ' + PID);


ПО для запросов я тоже написал на ноде через request.js, важно было не забыть про http.agent.maxSockets. Можно было, конечно, CURL, но хотелось самому всё посчитать.

Итак, первый тест: сервера на Nginx и Node, Max 10000 открытых запросов. В реальности вышло меньше, конечно. Эта цифра — просто количество request в массиве запросов а не их реальное значение в секунду. Можно и больше запросов, но я мерил разницу, а не производительность.

На моём железе нода выдержала больше 1200 ответов в секунду. А nginx выдержал их около 3500.

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

Т.е. разница даже не на порядки, а всего лишь в разы!

Интересно, что первое время отдача постепенно возрастает, потом стабилизируется итоговой цифре. Минуты через три примерно.

Второй тест был для самой ноды:

  Режим ~RPS ~PWait ~Mem
1. Когда сервер ноды и ПО запросов не получили affinity вообще. 1400 6.5 95M
2. Cервер и Запросы с affinity из теста с nginx. ~1200-1300 ~5.2 85M
3. Сервер с affinity, запросы без. 1100 ~5.5 100M
4. Сервер без affinity, запросы с ним. 1200 ~6. 90M


Все замеры цифр производились визуально после 3 минут работы, когда всё стабилизируется.
Интересно, что память нодой сначала интенсивно «жрётся», потом чуть чуть падает, видимо сборщик отрабатывает.

~RPS — примерно Requests Per Second.
~PWait — примерное время ожидания страницы в реальном браузере. Косвенный показатель нагруженности системы когда что-то делаешь ещё кроме смотрения на бегущие циферки.

За памятью я подглядывал через htop.

Эмм — то есть всё как бы в пределе статистической погрешности.

Просто представим, что там кроме ноды ещё БД, redis, HaProxy и Nginx.
+ Бизнес логика реальная, а не пара сумматоров.
Чьими будут «тапки»?

Мои выводы для меня:
0. Node — уже вполне себе хорош как интерпретатор.
  1. Оставить одно ядро самой системе, если это возможно.
  2. Оставить ещё ядер системе, если мне нужно будет ещё что-то на нём «крутить».
  3. Остальное можно отдать Node серверам под 100% утилизацию.


GIT с тестом.

Обещанный Use Case:
  • Если кто не в курсе, установка зависимостей производится как npm install.
  • Если ничего не менять, то после node test_requester.js нужно нажать Enter один раз, чтобы запустить запросы.
  • Остановка по Ctrl + C.
  • Это всё в консоли. Offtopic — я использую Guake Terminal — IMHO: очень удобно.
  • Сервер запускается как node test_httpserver.js.


Да, и не делайте тестов, если не понимаете архитектуры систем на железном уровне. Хотите понять — курите мануалы, например: Ч. Петцольд — «Код. Тайный язык информатики.» Там всё подробненько изложено на весьма доступном языке. У меня её даже дедушка читал, а дедушке 75 лет и он бывший шахтёр.

На всякий случай поясню — если у Вас 4 ядра, из которых реальных 2, то numCPUs может Вам нещадно наврать.

Да, и мои конфиги, если интересно:

cat /etc/sysctl.conf
fs.file-max=65535

kernel.max_lock_depth = 4096
fs.mqueue.queues_max = 1024
fs.mqueue.msg_max = 2048
fs.mqueue.msgsize_max = 16384
fs.inotify.max_user_watches = 1048576
fs.inotify.max_queued_events = 65536
fs.inotify.max_user_instances = 16384
net.ipv4.tcp_fin_timeout = 150
kernel.sem = 1000 32000 128 2048

cat /etc/security/limits.conf
root hard msgqueue 131072
root soft msgqueue 131072
root hard sigpending 131072
root soft sigpending 131072
root hard nproc 131072
root soft nproc 131072
root hard core 131072
root soft core 131072
root hard nofile 131072
root soft nofile 131072

* hard msgqueue 131072
* soft msgqueue 131072
* hard sigpending 131072
* soft sigpending 131072
* hard nproc 131072
* soft nproc 131072
* hard core 131072
* soft core 131072
* hard nofile 131072
* soft nofile 131072


Проверил без этих конфигов, вышло лучше процентов на 30.
Only registered users can participate in poll. Log in, please.
Если Вы всё же запустили тесты, то:
43.33% Ничего не понятно — какой-то псевдодокод. 13
6.67% Запустили и выставили affinity < количества ядер. 2
10% Запустили, и в параллели нагрузили чем-нибудь тяжёлым само железо. 3
20% Запускали всё так же как тут и было. 6
43.33% Не запускали, но имеете своё мнение, м.б. отпишетесь в коментах. 13
30 users voted. 73 users abstained.
Only registered users can participate in poll. Log in, please.
Статья сложна для восприятия потому что:
35.9% В ней применён разговорный стиль речи: обсуждается в комментариях. 28
25.64% Вообще не понятно о чём речь, сложно понять 20
20.51% Я Не люблю Node.JS || JavaScript 16
14.1% У меня иное мнение 11
3.85% В комментариях напишу что не так 3
78 users voted. 58 users abstained.
Tags:
Hubs:
0
Comments 28
Comments Comments 28

Articles