- PVSM.RU - https://www.pvsm.ru -
Регулярно слышу фразу типа «Node.js не подходит для хайлоада».
Захотелось самому посмотреть.
Хотел написать комментарий к той [1] статье, но передумал и написал больше.
Автору той статьи, большое спасибо за интересный топик, задело.
В интернете кто-то не прав. Наших бъют! Обидно, да.
Для себя я выводы сделал, но это мои субъективные цифры и немножко GITа.
Что думать — не знаю, пишите пожалуйста в каментах своё мнение.
Я — шаман! Тихо беру в руки бубен и расчехляю варган [2]…
Не люблю ресурсы, т.к. понимаю, что в случае ЧС их у меня не будет.
Поэтому у меня они весьма скромны: AMD C-60 [3] / 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 тем кто «в танке» будет там же.
Расскажу немного как я до этого докатился, чтобы, так сказать, развеять сомнения.
Все мы знаем, что современные процессоры работают последовательно.
Знаем то все, но вот понимаем как хотим, а не так как правильно!
Скажите, Вы можете думать над несколькими вещами сразу?
А если в этот момент зазвонит телефон и Вам нужно будет ответить на звонок?
А если параллельно с телефоном к Вам подойдёт человек-коллега, к котор[ой||му] у Вас симпатия и задаст какой-нибудь очень важный вопрос? А если при этом ещё вдруг мимо будет проходить человек-БОСС, заглянет в экран на котором в несвёрнутом окне браузера красуется лурк или ещё чего веселей?
Вот то то же — обработка прерываний и переполнение стека.
Казалось бы — при чём здесь асинхронность?
Но, если Вы, вдруг, по какой-нибудь страшной причине всё-таки не поняли до конца, то советую ещё раз задуматься.
У Вас, например, максимально
Остальные — они где-то там, когда-то будут, до них ещё далеко.
Сами думайте как это представить, поиграйте в Загадку Энштейна [5], чтоль, получается у Вас там всю многопоточность только в голове удержать (как в L1-L2 Cache), всмысле, да — без листочка (Mem)?
Вот теперь давайте считать.
Запускаете Вы свою приложуху на ноде, там у Вас стандартный код, может быть отсюда [6].
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.
А в ней вся та требуха, которая рулит потоками.
Вам не кажется загадочным то, что такая простая штука как последовательные инструкции, пусть даже в асинхронном режиме, обслуживается и абстрагируется такой сложной штукой как многопоточность и параллельность задач в мире ядра?
Итак, каждое из железных ядер процессора считает последовательно.
Над ними исполняемый код ядра, который типа пытается ВСЁ представить как параллельное мультизадачное и прочие рюшечки.
Внутри, под управлением ядра крутится однопоточный код нодовых процессов, которых у нас 8 штук, по количеству ядер.
Что будет с полимерами когда к нам поступит «IO» в ядро по сетевому стеку, например по HTTP?
Вроде пока ядро OS справляется…
А если нода уже всё утилизировала на всех 8-ми ядрах?
Вроде пока ядро OS тоже справляется…
Но здесь я бы уже хотел посмотреть на бенчмарк.
Давайте так и поступим!
1. Сравним ноду с Nginx, как описано в задачке выше.
2. Сравним отзывчивость ноды с полной загрузкой CPU и без неё.
Сразу скажу, что все тесты я крутил минут по 10, занимаясь при этом обычными задачами типа кода и сёрфинга.
Да, для того, чтобы заставить процесс работать лишь на определённых ядрах в Linux существует taskset.
В ноде я использую его так:
var PID = process.pid;
exec('taskset -pc ' + affinity + ' ' + PID);
ПО для запросов я тоже написал на ноде через request.js [7], важно было не забыть про http.agent.maxSockets. Можно было, конечно, CURL, но хотелось самому всё посчитать.
Итак, первый тест: сервера на Nginx и Node, max 10000 открытых запросов.
Можно и больше запросов, но я мерил разницу, а не производительность.
На моём железе нода выдержала больше 1200 ответов в секунду.
А nginx выдержал их около 3500.
Я понимаю, что такой хлам кому-то — не показатель.
Но мне очень даже показатель, учитывая что сервер ноды без всякого кластера крутился на нулевом ядре, а запросы на первом.
Т.е. разница даже не на порядки, а всего лишь в разы!
Интересно, что первое время отдача постепенно возрастает, потом стабилизируется итоговой цифре.
Второй тест был для самой ноды:
Режим | ~RPS | ~PWait | ~Mem | |
1. | Когда сервер ноды и ПО запросов не получили affinity вообще. | 1400 | 6.5 | 95M |
2. | Cервер и Запросы с affinity из теста с nginx. | 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 серверам.
GIT [8] с тестом.
Если кто не в курсе, установка зависимостей производится как npm install.
Если ничего не менять, то после node test_requester.js нужно нажать Enter один раз, чтобы запустить запросы.
Остановка по Ctrl + C.
Да, и не делайте тестов, если не понимаете архитектуры систем на железном уровне.
Хотите понять — курите мануалы, например Ч. Петцольда — КОД.
Там всё подробненько изложено на весьма доступном языке, у меня её дедушка читал, дедушке 75.
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
* 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
…
Автор: wentout
Источник [9]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/news/51698
Ссылки в тексте:
[1] той: http://habrahabr.ru/post/207460/
[2] варган: http://ru.wikipedia.org/wiki/%D0%92%D0%B0%D1%80%D0%B3%D0%B0%D0%BD
[3] AMD C-60: http://ru.wikipedia.org/wiki/AMD_Brazos
[4] мозг: http://www.braintools.ru
[5] Загадку Энштейна: http://en.wikipedia.org/wiki/Zebra_Puzzle
[6] отсюда : http://nodejs.org/api/cluster.html
[7] request.js: https://github.com/mikeal/request
[8] GIT: https://github.com/wentout/nodejs_benchmark
[9] Источник: http://habrahabr.ru/post/207612/
Нажмите здесь для печати.