Бенчмаркинг Производительность node.js (кластера) с пулами mysql: Lighttpd + PHP?

Изменить (2): Теперь используйте db-mysql с модулем generic-pool. Частота ошибок значительно снизилась и колеблется на 13%, но пропускная способность по-прежнему составляет около 100 реад / сек.

Edit (1): После того, как кто-то предположил, что ORDER BY RAND () заставит MySQL быть медленным, я удалил это предложение из запроса. Node.js теперь колеблется около 100 req / sec, но все же сервер сообщает об ошибке CONNECTION: Слишком много соединений.

Node.js или Lighttpd с PHP?

Вероятно, вы видели множество тестов «Hello World» для node.js …, но тесты «hello world», даже те, которые были отложены на 2 секунды за запрос, даже не близки к использованию в реальном мире. Я также выполнил эти варианты тестов «Hello World», используя node.js, и пропускную способность около 800 req / sec с частотой ошибок 0.01%. Тем не менее, я решил некоторые тесты, которые были немного более реалистичными.

Возможно, мои тесты не завершены, скорее всего, что-то ДЕЙСТВИТЕЛЬНО неправильно в отношении node.js или моего тестового кода, и поэтому, если ваш эксперт node.js, пожалуйста, помогите мне написать несколько лучших тестов. Мои результаты опубликованы ниже. Я использовал Apache JMeter для тестирования.

Тестовый корпус и системные характеристики

Тест довольно прост. Запрос mysql для числа пользователей упорядочен случайным образом. Имя пользователя первого пользователя извлекается и отображается. Соединение с базой данных mysql осуществляется через unix-сокет. ОС – FreeBSD 8+. 8 ГБ оперативной памяти. Процессор Intel Xeon Quad Core 2.x Ghz. Я немного настроил конфигурации Lighttpd, прежде чем я столкнулся с node.js.

Настройки Apache JMeter

Количество потоков (пользователей): 5000 Я считаю, что это число одновременных подключений

Период разгона (в секундах): 1

Количество циклов: 10 Это количество запросов на пользователя

Результаты Apache JMeter

 Этикетка |  # Образцы |  Среднее |  Мин |  Макс |  Std.  Девиация  |  Ошибка% |  Пропускная способность |  KB / sec |  Avg.  Б

 Запросы HTTP Lighttpd |  49918 |  2060ms |  29ms |  84790ms |  5524 |  19,47% |  583,3 / сек |  211,79 |  371,8

 Запросы HTTP Node.js |  13767 |  106569мс |  295ms |  292311мс |  91764 |  78,86% |  44,6 / сек |  79,16 |  1816

Результат

Node.js был настолько плохим, что мне пришлось рано прекратить тест. [ Исправлено тестирование полностью]

Node.js сообщает об ошибке «CONNECTION: Слишком много соединений» на сервере. [ Исправлено ]

В большинстве случаев Lighttpd имел пропускную способность около 1200 req / sec.

Однако node.js имел пропускную способность около 29 req / sec. [ Исправлено сейчас при 100req / sec]

Это код, который я использовал для node.js (с использованием пулов MySQL)

var cluster = require('cluster'), http = require('http'), mysql = require('db-mysql'), generic_pool = require('generic-pool'); var pool = generic_pool.Pool({ name: 'mysql', max: 10, create: function(callback) { new mysql.Database({ socket: "/tmp/mysql.sock", user: 'root', password: 'password', database: 'v3edb2011' }).connect(function(err, server) { callback(err, this); }); }, destroy: function(db) { db.disconnect(); } }); var server = http.createServer(function(request, response) { response.writeHead(200, {"Content-Type": "text/html"}); pool.acquire(function(err, db) { if (err) { return response.end("CONNECTION error: " + err); } db.query('SELECT * FROM tb_users').execute(function(err, rows, columns) { pool.release(db); if (err) { return response.end("QUERY ERROR: " + err); } response.write(rows.length + ' ROWS found using node.js<br />'); response.end(rows[0]["username"]); }); }); }); cluster(server) .set('workers', 5) .listen(8080); 

Это код, который я использовал для PHP (Lighttpd + FastCGI)

 <?php $conn = new mysqli('localhost', 'root', 'password', 'v3edb2011'); if($conn) { $result = $conn->query('SELECT * FROM tb_users ORDER BY RAND()'); if($result) { echo ($result->num_rows).' ROWS found using Lighttpd + PHP (FastCGI)<br />'; $row = $result->fetch_assoc(); echo $row['username']; } else { echo 'Error : DB Query'; } } else { echo 'Error : DB Connection'; } ?> 

Это плохое сравнительное сравнение. В node.js вы выбираете всю таблицу и помещаете ее в массив. В php ваш единственный синтаксический анализ первой строки. Таким образом, чем больше ваша таблица, тем медленнее будет выглядеть узел. Если вы сделаете php, используйте mysqli_fetch_all, это будет аналогичное сравнение. В то время как db-mysql должен быть быстрым, он не очень полный и не имеет возможности сделать это справедливым сравнением. Использование другого модуля node.js, такого как node-mysql-libmysqlclient, должно позволить вам обрабатывать только первую строку.

100 соединений – это значение по умолчанию для MySQL, максимальное количество подключений.

Так почему-то ваши соединения не используются повторно для разных запросов. Вероятно, у вас уже есть один запрос для каждого соединения.

Возможно, используемая вами библиотека nodejs MySQL не будет размещать запросы в одном и том же соединении MySQL, но попытаться открыть другое соединение и выйти из строя.

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

Проблема заключается в том, что один процесс от узла привязывается к одному ядру процессора, а PHP получает масштабирование со всеми четырьмя ядрами через многопоточность. Я бы сказал, что с процессором Quad Core 2.x GHz, PHP, безусловно, будет иметь значительное преимущество перед узлом только благодаря возможности использования дополнительных ресурсов.

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

Я довольно новичок в Node сам, но я надеюсь, что это поможет вам улучшить свой тест 🙂

Включили ли вы APC с PHP?

Можете ли вы попытаться включить постоянные соединения с PHP? например

 $conn = new mysqli('p:localhost', 'root', 'password', 'v3edb2011'); 

Разве вы не используете 10 максимальных подключений MySQL в Node.js и 5000 максимальных подключений MySQL через PHP?

Пока вы запускаете тесты в любой из систем, я бы посмотрел на MySQL «ПОКАЗАТЬ ПОЛНЫЙ ПРОЦЕССЛИСТ».

Одна вещь, которую следует учитывать, – это то, что драйвер – производительность для баз данных может быть очень привязана к конкретному используемому вами драйверу. Самый популярный драйвер mysql и тот, который наиболее активно поддерживается, – https://github.com/felixge/node-mysql . Могут получить разные результаты.

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

Это плохой бенчмарк, это должен быть простой «мир привет», так как тысячи тестов, которые доказывают, что nodejs является сервером «привет мир» быстрее всех: D