2014-01-20 66 views
16

我正在做一個NodeJS與Java的快速性能測試。所選的簡單用例是查詢MySQL數據庫中的單個表。初始結果如下:如何在多個內核上線性擴展NodeJS?

Platform      | DB Connections | CPU Usage | Memory Usage | Requests/second 
==============================|================|===========|===============|================ 
Node 0.10/MySQL    | 20    | 34%  | 57M   | 1295 
JBoss EAP 6.2/JPA    | 20    | 100%  | 525M   | 4622 
Spring 3.2.6/JDBC/Tomcat 7.0 | 20    | 100%  | 860M   | 4275 

請注意,節點的CPU和內存使用率低於Java,但吞吐量也約爲三分之一!然後我意識到Java正在使用我的CPU上的所有四個內核,而Node僅在一個內核上運行。所以我改變了節點代碼來整合集羣模塊,現在它使用了所有四個內核。下面是新的結果:

Platform      | DB Connections | CPU Usage | Memory Usage | Requests/second 
==============================|================|===========|===============|================ 
Node 0.10/MySQL (quad core) | 20 (5 x 4)  | 100%  | 228M (57 x 4) | 2213 

注意,CPU和內存使用情況,現在都漲了,但比例吞吐量僅70%上升。我期待增加四倍,超過Java吞吐量。我該如何解釋這個缺點?我可以做些什麼來線性增加吞吐量?

下面是利用多個內核的代碼:查詢數據庫

if (Cluster.isMaster) { 
    var numCPUs = require("os").cpus().length; 
    for (var i = 0; i < numCPUs; i++) { 
     Cluster.fork(); 
    } 

    Cluster.on("exit", function(worker, code, signal) { 
     Cluster.fork(); 
    }); 
} 
else { 
    // Create an express app 
    var app = Express(); 
    app.use(Express.json()); 
    app.use(enableCORS); 
    app.use(Express.urlencoded()); 

    // Add routes 

    // GET /orders 
    app.get('/orders', OrderResource.findAll); 

    // Create an http server and give it the 
    // express app to handle http requests 
    var server = Http.createServer(app); 
    server.listen(8080, function() { 
     console.log('Listening on port 8080'); 
    }); 
} 

我使用的節點MySQL驅動程序。連接池被設置爲每個內核5個連接,但這沒有什麼區別。如果我將這個數字設置爲1或20,我就可以獲得大致相同的吞吐量!

var pool = Mysql.createPool({ 
    host: 'localhost', 
    user: 'bfoms_javaee', 
    password: 'bfoms_javaee', 
    database: 'bfoms_javaee', 
    connectionLimit: 5 
}); 

exports.findAll = function(req, res) { 
    pool.query('SELECT * FROM orders WHERE symbol="GOOG"', function(err, rows, fields) { 
     if (err) throw err; 
     res.send(rows); 
    }); 
}; 
+0

你可以嘗試'NODE_ENV = production' https://groups.google.com/forum/#!topic/express-js/fqtr1Carr0E – KeepCalmAndCarryOn

+0

另外,你是否正確地連接了連接?這是建議的方式'var mysql = require('mysql'); var pool = mysql.createPool(...); pool.getConnection(function(err,connection){ //使用連接 連接。查詢('SELECT some FROM sometable',函數(err,rows){//並且完成了連接 connection.release(); //不要在這裏使用連接,它已經返回到pool。 }); });'https://github.com/felixge/node-mysql – KeepCalmAndCarryOn

+0

是的,我正確地使用了池。我所展示的代碼只是你所擁有的一個捷徑(我已經試過了這兩種方式)。在這個node-mysql問題上進行了廣泛的闡述:https://github.com/felixge/node-mysql/issues/712。 – Naresh

回答

1

嘗試設置環境變量export NODE_CLUSTER_SCHED_POLICY="rr"。根據this blog post

+0

該文正在討論NodeJS版本0.12,該版本尚未在http://nodejs.org/上提供。另外它說,循環算法不會影響Windows上的性能,而這正是我進行測試的地方。 – Naresh

+1

是的,但它確實也適用於最新版本的v0.10。但是,它特別補償了linux內核調度程序的一個方面,所以不需要在Windows上進行。 –

2

從我看到的,你不僅僅比較平臺,而且還比較框架。您可能想要刪除框架效果並實現普通的HTTP服務器。例如,Express應用程序中的所有中間件都會增加延遲。另外,您是否確保Java庫不會緩存頻繁請求的數據,這會顯着提高性能?

要考慮的其他事情是Node中內置的http模塊(因此,包含node-mysql的任何構建於其上的庫)通過代理類維護一個內部連接池(不要與MySQL連接池混淆),以便它可以利用HTTP保持活動。當您向同一服務器運行多個請求而不是打開TCP連接,發出HTTP請求,獲取響應,關閉TCP連接並重復時,這有助於提高性能。因此,TCP連接可以重新使用。

默認情況下,HTTP代理將只打開5個同時連接到單個主機,如MySQL服務器。你可以很容易地改變它如下:

var http = require('http'); 
http.globalAgent.maxSockets = 20; 

考慮到這些變化,看看你可以得到什麼樣的改進。

其他想法是通過在連接打開和關閉時檢查MySQL日誌來驗證MySQL連接池是否正確使用。如果它們經常打開,則可能需要增加node-mysql中的空閒超時值。

+0

感謝您的想法。我目前專注於其他事情,但有一個待辦事項來嘗試這些建議。 – Naresh