NodeJS比PHP慢得多吗?

14

目前我在Apache + PHP + MySQL下运行了一台小型的Web服务器,但我想探索使用NodeJS的选项。该服务器只做两件事:

  1. 提供一些静态文件(HTML/CSS/image等资源)
  2. 查询数据库(仅限选择和插入,没有更新或删除)

然而,我遇到了一些性能问题,正在努力找出问题所在。为了隔离问题,我创建了一个最小的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)


1
另外,在Node示例中,您正在使用压缩中间件,但是在PHP场景中是否也使用压缩并不清楚。最后,您可以针对Node核心HTTP服务器(而不是Express)进行基准测试,以了解Express的性能有多慢。 - mscdex
@CLDev请同时提及PHP版本。您正在使用的是Node v6.9.4(最新版本)。尝试使用PHP v7(最新版本),这样比较更好。PHP7的性能比PHP5高出多倍。我已经探索过并了解到,Node应用程序消耗了大量资源。 - kaushik karan
@Adiii 感谢您的评论。在发布我的问题之前,我已经阅读了那个SO问题。不幸的是,它并没有真正帮助我解决问题。实际上,在PC上,Node应用程序比PHP运行得更快,但在树莓派上却不是这样。因此,实际上似乎并不是MySQL的问题。此外,如果您查看文档,default connectionLimit 的默认值为10 (https://github.com/mysqljs/mysql#pool-options),我想我不必显式指定它? - CLDev
默认值是10,但您可以增加它们或使用mysql2。 - Adiii
@Adiii 令人沮丧的是,PC和Raspberry Pi上NodeJS应用程序的设置是相同的。如果这仅与池中连接数有关,那么在PC上也应该很慢,对吧?我已经尝试了mscdex建议的mysql2,差异并不显著,可能快了10%左右,但仍然无法接近PHP的性能水平。 - CLDev
显示剩余17条评论
1个回答

5
通过使用ApacheBench在并发级别为1的情况下对1000个请求进行测试(以不影响单线程Node应用程序)。
通过限制并发性为1,实际上削弱了Node的最大优势,即异步IO。即使node.js是单线程的,在等待db.query调用时,它也会处理其他请求。
因为Node不是使用系统线程来处理这些请求,而是使用自己的轻量级调度程序,所以它可以比Apache更便宜地执行并发请求。Apache可以以不同的方式进行配置来处理多个请求(例如,预分叉固定数量的进程或事件驱动的分叉),但一旦你有一定数量的并发请求,事情就会变慢,因为请求可能需要等待其他请求完成,即使这些请求什么都没做,只是在等待数据库。
因此,总之,对于同步执行单个请求,PHP可能更快;但一旦您拥有足够的请求超过了Apache配置的限制,并且还受到机器大小的影响,您应该看到node.js总体上更快。

嗨,巴斯蒂安。感谢你的回答。那么你的意思是,如果我有很多并发请求,NodeJS可能会更好,否则Apache + PHP可能是更好的选择?为了给你更多背景,我正在从Apache + PHP堆栈迁移到NodeJS。迁移后,我意识到我的API调用需要更长的响应时间,并且由于每天访问者很少,大部分时间API调用是自动触发的。 - CLDev
对于单个API调用,速度差异可能在2倍到20倍之间(例如20毫秒与400毫秒,或者对于复杂的API,1.2秒与2.4秒)。因此,我开始研究可能出了什么问题,但目前还没有找到任何确凿的证据。 - CLDev
@CLDev,这意味着使用大量请求时,在资源受限的机器上,Node.js 可以更加有效率。但是,在你的显然很少的请求中,这种 Node.js 的优势将无法被利用。但是,如果你的性能问题与 PHP 和 Node.js 本身无关,那么我会感到非常惊讶——从明显的 1.2 秒到 2.4 秒的减速情况来看,这表明其他地方存在严重问题,即使使用不那么高效的 Node mysql 驱动程序(而不是 mysql2)。 - Bastian Blankenburg
例如,Apache会执行一些额外的操作,比如缓存,而在node中你无法直接获得这些功能。也就是说,对于幂等请求(例如重复获取相同URL和查询参数的GET请求),一个配置良好的Apache将在后续调用中返回缓存版本。在node中,这取决于你使用的框架,你可以自己实现缓存,或者在其前面放置一个Apache或其他Web服务器。 - Bastian Blankenburg

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接