Node.js V.S. php 連接資料庫效能實測

下雨天在家,原本想改寫某個專案的api,從php改寫成node.js,可寫到一半突然覺得到底有沒有這個必要,所以反正機器都有了,就寫了各種不同版本來實測看看效能怎樣。

每個版本的功能都一樣,也在同一台機器,連同一個資料庫,下一樣的sql指令,回傳一樣的檔案格式JSON。使用一樣的測試工具,一樣的參數,指令如下

ab -n 1000 -c 1000 -t 10 http://example.com/

首先第一號選手登場的是純粹apache+php7.2的組合,程式碼是這樣

<?php
$servername = "mysql.example.com";
$username = "root";
$password = "123456";
$dbname = "test_menu_db";
  
// Create connection
$conn = mysqli_connect($servername, $username, $password, $dbname);
mysqli_set_charset( $conn, 'utf8');
// Check connection
if (!$conn) {
    die("Connection failed: " . mysqli_connect_error());
}

$sql = "SELECT * FROM menu limit 200";
$result = mysqli_query($conn, $sql);

$myArray = mysqli_fetch_all($result,MYSQLI_ASSOC);
header("Content-Type:text/html; charset=utf-8");
header('Content-Type: application/json; charset=utf-8');
$json = json_encode($myArray, JSON_UNESCAPED_UNICODE);
echo $json;
mysqli_close($conn);

?>

雖然這是最原始最古早的寫法,可是我試了幾次,包含試了後面的組合,覺得這其實是最簡單暴力,能簡單快速達到高效能的方法。但就是吃效能,如果有很多記憶體可以揮霍是沒差。下面是測試結果

完成數要求數614

第二號選手是用swoole,聽說是php的強化版,效能很棒棒就是了,可以看其他網路文章,下面是程式碼

<?php 

$http = new swoole_http_server("127.0.0.1", 8080);

$http->set(array(
    'worker_num' => 40,
    'backlog' => 128,
));

$http->on("start", function ($server) {
    //var_dump($server);
    echo "Swoole http server is started at http://127.0.0.1:8080\n";
});
$http->on("request", function ($request, $response) {
    $servername = "mysql.example.com";
    $username = "root";
    $password = "123456";
    $dbname = "test_menu_db";
    
    $conn = mysqli_connect($servername, $username, $password, $dbname);
    mysqli_set_charset( $conn, 'utf8');
    
    $sql = "SELECT * FROM menu";
    $result = mysqli_query($conn, $sql);
    
    $res_array = mysqli_fetch_all($result,MYSQLI_ASSOC);
    $response->header('content-type', 'application/json');
    $response->end(json_encode($res_array));
});
$http->start();

他可以設worker_num數量,這個只有設1的話結果很慘,完成數只有兩位數而已,這邊我是故意設一個數據比較好看的,以下設40的結果,設100,完成數可達到1370。那這樣跟原始php比起來,其實我也不知道哪個好,因為我不知道原始的php開了多少個執行緒,只是swool比較可以彈性調整。

第三號選手登場的是node.js,使用express

const express = require('express')
const app = express()

const mysql = require('mysql')

const pool = mysql.createPool({
  host: "mysql.example.com",
  user: "root",
  password: "123456",
  database: "test_menu_db"
})

app.get('/', function (req, res) {
  pool.query("SELECT * FROM menu", function (err, result, fields) {
    if (err) throw err;
    res.json(result);
  });
})

app.listen(8080, function () {
  console.log('Example app listening on port 8080!');
});

剛使用node.js連接mysql的時候,我不知道有連接池這種東西,一用才發現效能提升不少,下面是使用連接池的結果,只使用單一連線的話,完成數只有105

第四號選手一樣使用node.js,只是改用也是聽說效能很好的框架koa。這邊我把連接mysql的程式,封裝成promise了,封裝方法可看這裡,因為這個框架限制必須用promise,大概是因為這樣,效能才這麼好吧

const Koa = require('koa')
const app = new Koa()

const query = require('./database.js');

app.use(async ctx => {
    let result = await query("SELECT * FROM menu")
    ctx.status = 200
    ctx.response.type = 'json';
    ctx.response.body = result;
})

app.listen(8080)
console.log('Example app listening on port 8080!');

實測結果,果然就是比express快了一些,完成數528

這樣看起來好像node.js的性能比php還差,不過我想吃硬體資源的程度可能差很多,php可以很暴力的每個request都開一個執行緒,但node基本上是單執行緒的,要多執行緒執行node也是有辦法的,我上網查到了看這個

於是有了加開第五號選手,多執行緒的koa,express我就懶得試了,大概就是慢一點吧,我一次開了40個執行緒,仿照上面swoole的worker_num,結果如下,完成數達1028,有種封印解除的感覺。

那為了看node和swoole消耗的硬體資源,我用ps -aux指令來看占用的百分比。

swoole如果開了80個worker_number,完成的要求數有1344,平均每個執行緒使用了0.7%的記憶體,總共佔了0.7*80=56%,cpu使用率都顯示0,可能執行完就釋放了看不到。

node開了40個執行緒,完成的要求數是1028,平均使用記憶體2%,總共使用了80%,cpu使用率平均也大概2%,總共也約80%

以這個結果來看,swoole的cp值比較高。但以單一執行緒來說,node還是很高效,而且占用的資源也很低,相對cp值就高了很多,在使用硬體資源上也相對謹慎。

所以結論就是見仁見智,看個人喜好,哈哈,有說跟沒說一樣。個人還是比較偏好node啦,至少社群活耀,要找什麼套件資源或問題比較好找。

以後有空再來試golane,看有沒有真的那麼厲害。

Leave a Reply

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *