我目前在Apache + PHP + MySQL下运行一个小规模的Web服务器,并希望探索使用NodeJS的选项。服务器实际上做了两件事:
但是,我遇到了一些性能问题,而我正试图找出问题所在。为了解决这个问题,我创建了一个最小的NodeJS应用程序,该应用程序针对MySQL运行查询并返回50行数据作为JSON。以下是我的代码:
var express = require('express');
var compression = require('compression');
var mysql = require('mysql');
var db = mysql.createPool({
host: <host>,
user: <user>,
password: <password>,
database: <database>,
debug: false
});
var app = express();
app.use(compression());
app.get('/data', function(req, res) {
var sql = 'SELECT column_1, column_2 FROM table';
db.query(sql, function (error, rows, fields) {
if (error) throw error;
res.json(rows);
});
});
app.listen(3000, function () {
console.log("Running on port 3000.");
});
通过使用ApacheBench以并发级别1发出1000个请求(为了不使单线程Node应用程序不利),结果如下:
Concurrency Level: 1
Time taken for tests: 10.377 seconds
Complete requests: 1000
Failed requests: 0
Total transferred: 3057000 bytes
HTML transferred: 2829000 bytes
Requests per second: 96.37 [#/sec] (mean)
Time per request: 10.377 [ms] (mean)
Time per request: 10.377 [ms] (mean, across all concurrent requests)
Transfer rate: 287.69 [Kbytes/sec] received
作为比较,下面是我在PHP中的代码:
<?php
$hostname = <host>;
$username = <user>;
$password = <password>;
$database = <database>;
try {
$db_handler = new PDO('mysql:host=' . $hostname . ';dbname=' . $database, $username, $password);
} catch (PDOException $e) {
throw new Exception('[ERROR] Unable to connect to the database.');
}
$sql = 'SELECT column_1, column_2 FROM table';
$statement = $db_handler->prepare($sql, array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));
$statement->execute();
$rows = array();
while ($row = $statement->fetch(PDO::FETCH_ASSOC)){
$rows[] = $row;
}
print json_encode($rows);
$db_handler = null;
?>
ApacheBench的结果:
Concurrency Level: 1
Time taken for tests: 6.726 seconds
Complete requests: 1000
Failed requests: 0
Total transferred: 3023000 bytes
HTML transferred: 2829000 bytes
Requests per second: 148.68 [#/sec] (mean)
Time per request: 6.726 [ms] (mean)
Time per request: 6.726 [ms] (mean, across all concurrent requests)
Transfer rate: 438.92 [Kbytes/sec] received
从上面的结果可以看出,PHP比NodeJS快得多。如果触发更复杂的查询(差异可能是20次,比如20ms vs 400ms),或者并发级别增加,则差异会更大。
我试图在Node应用程序中添加最多4名工作人员(我在Raspberry Pi 2上运行服务器,它有4个核心),看看它是否有帮助,不幸的是它仍然没有接近PHP中的结果。你能告诉我可能做错了什么吗?或者NodeJS对我想要实现的目标不是一个好选择?
[EDITED]
非常感谢您的所有评论。似乎大多数人怀疑这个问题是由NodeJS MySQL驱动程序引起的。我还做了一些测试,以确定是否属于这种情况,我偶然发现了一些非常有趣的东西。
通过在另一台PC(Core 2 Duo E7200)中运行相同的Node应用程序,但在Raspberry Pi上连接到相同的MySQL,结果实际上相当不错:
Concurrency Level: 1
Time taken for tests: 2.705 seconds
Complete requests: 1000
Failed requests: 0
Total transferred: 3057000 bytes
HTML transferred: 2829000 bytes
Requests per second: 369.71 [#/sec] (mean)
Time per request: 2.705 [ms] (mean)
Time per request: 2.705 [ms] (mean, across all concurrent requests)
Transfer rate: 1103.72 [Kbytes/sec] received
作为比较,我还在该PC上运行Apache服务器,连接到Raspberry Pi上的相同MySQL,结果如下:
Concurrency Level: 1
Time taken for tests: 6.297 seconds
Complete requests: 1000
Failed requests: 0
Total transferred: 3034000 bytes
HTML transferred: 2829000 bytes
Requests per second: 158.80 [#/sec] (mean)
Time per request: 6.297 [ms] (mean)
Time per request: 6.297 [ms] (mean, across all concurrent requests)
Transfer rate: 470.50 [Kbytes/sec] received
总结一下,以下是我到目前为止所取得的成果。只有Web服务器部分不同,而数据库在Raspberry Pi上始终是MySQL:
Server Time Taken
Node (Pi) 10.337s
PHP (Pi) 6.726s
Node (PC) 2.705s
PHP (PC) 6.297s
在两台服务器上,PHP的结果或多或少相同,而NodeJS的结果差异很大。基于上面的结果,我觉得NodeJS对CPU性能更敏感,换句话说就是CPU密集型? (我使用的NodeJS版本是v6.9.4,仅供参考)
答案 0 :(得分:5)
使用ApacheBench以并发级别1发出1000个请求(为了不使单线程Node应用程序不利)
通过将并发性限制为1,您实际上取消了节点的最大优势,即异步IO。即使node.js是单线程的,它也会在等待db.query调用时处理其他请求。
因为节点没有使用系统线程,而是它自己的轻量级调度程序,它可以比Apache便宜得多的并发请求。 Apache可以以不同的方式配置来处理多个请求(例如,预先分配固定数量的进程或事件驱动的分叉),但是一旦你有一定数量的并发请求,事情就会变慢,因为请求可能需要等待其他人要完成,即使其他人只是在等待数据库。
因此,总而言之,对于同步执行单个请求,是的PHP可能会更快;但是一旦你有足够的请求超过了Apache的配置设置的限制,并且受到你的机器大小的影响,你应该看到node.js整体上更快。