目前我在Apache + PHP + MySQL下运行了一台小型的Web服务器,但我想探索使用NodeJS的选项。该服务器只做两件事:
- 提供一些静态文件(HTML/CSS/image等资源)
- 查询数据库(仅限选择和插入,没有更新或删除)
然而,我遇到了一些性能问题,正在努力找出问题所在。为了隔离问题,我创建了一个最小的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个worker(我正在Raspberry Pi 2上运行服务器,该服务器有四个核心),并查看它是否有所帮助,但不幸的是,它仍然无法接近PHP的结果。请问我可能做错了什么?还是说NodeJS并不适合我想要实现的目标?
[已编辑]
非常感谢所有的评论。似乎大部分人怀疑问题是由于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
作为比较,我也在那台电脑上运行了一个Apache服务器,连接到树莓派上相同的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服务器部分不同,而数据库始终在树莓派上使用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)