-
-
Notifications
You must be signed in to change notification settings - Fork 34.2k
Description
When using anonymous functions (in IIFEs or Promises) to prepare the response of an HTTP request, the performance of the server suddenly slows down. Performance remains low until the server is restarted.
I initially found the problem using Promises. A script to replicate the problem:
var http = require('http');
var srv = http.createServer(function (req, res) {
promiseValue().then(function(value){
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end(value);
});
});
function promiseValue() {
return Promise.resolve().then(function() {
var j = 0;
for (var i = 0, l = 300000; i < l; i++) { j = j + 2; }
return "Hi " + j;
});
}But Promises are not required:
var http = require('http');
var srv = http.createServer(function (req, res) {
callbackValue(function(value){
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end(value);
});
});
function callbackValue(cb) {
(function() {
var j = 0;
for (var i = 0, l = 300000; i < l; i++) {
j = j + 2;
}
cb("Hi " + j);
})();
}
srv.listen(3000, '127.0.0.1', function() {
"use strict";
console.log("Server listening on 127.0.0.1:3000");
});Using a HTTP benchmarking tool to test the server, e.g. wrk:
#! /bin/bash
while :
do
wrk -t2 -c32 -d5s "http://127.0.0.1:3000" | grep "Requests"
doneThe server starts providing good performance, but an unpredictable point in time the performance drops:
Requests/sec: 2389.40
Requests/sec: 2394.00
Requests/sec: 2396.53
Requests/sec: 1071.95
Requests/sec: 890.80
Requests/sec: 889.23
Requests/sec: 893.15
Once it drops, it doesn't matter if you stop the load testing tool and let the server recover for a while, performance remains low until the server is restarted.
¿Is it a bug or am I doing something wrong?
If it is a bug, I don't know if it belongs to Nodejs or V8, although I have been unable to reproduce the problem only with Promises/IIFEs without the 'http' module.
Some additional details I have collected while hunting down the issue that may or may not be of interest to solve the problem:
- It can be reproduced in all versions of Nodejs, at least in OSX. In particular, using Promises, I have been able to reproduce it in: v5.0.0, v4.2.1, iojsv1.0.0, even v0.11.13 (the first version that introduced Promise). Previous versions (v10.x, <v0.11.13) didn't have native Promise support, I have tested them using a 3rd party library (Bluebird) and performance matches the low one since the start up.
- Performance drops after an unpredictable amount of time or requests. Following the same steps, I have found the drop in performance in a wide range of time (e.g. 15 seconds - 30 minutes).
- The anonymous function used in the
.then(function(){...})ofpromiseValue()is the main cause of performance. - According to its performance, during the 1st phase the function seems to be optimized and during the 2nd phase it seems to become deoptimized (see comment).
- If the anonymous function is refactorized as a named function, performance matches the high level and does NOT drop over time.
- If an instruction that prevents optimization (e.g.
try {} catch (e) {}) is added to the anonymous function, performance matches the low level and doesn't vary over time.
- According to
v8, the functionis always not optimized(I could copy the snippet of how I tested this if required. Basically, it follows @petkaantonov's tip). (EDIT: The function starts being optimized and, at some point, becomes deoptimized also according tov8, see comment).
(I can also provide snippets for these points)
EDIT: