I've just tested performance on a simple nest's controller, that returns text on a get request (no database).
And the same simple GET controller (middleware) with express.
I used WRK tool to test performance.
And as a result plain express is 2 x times faster than nestjs.
Why is so much overhead created by nestjs?
UPDATE - 17.03.2020
We are now running benchmarks for every new PR. One of the latest benchmarks can be found here: https://github.com/nestjs/nest/runs/482105333
Req/sec Trans/sec
Nest-Express 15370 3.17MB
Nest-Fastify 30001 4.38MB
Express 17208 3.53MB
Fastify 33578 4.87MB
That means Nest + FastifyAdapter is now almost 2 times faster than express.
UPDATE - 22.09.2018
Benchmarks directory has been added to the repository: https://github.com/nestjs/nest/blob/master/benchmarks/all_output.txt (you can run benchmarks on your machine as well).
UPDATE - 24.06.2018
Nest v5.0.0 supports fastify. Fastify + Nest integration is even more performant than plain(!) express.
The following list shows what Nest is doing in comparison to plain express route handler:
it surrounds your route handler body with try..catch blocks
it makes every route handler async
it creates a global express router
it creates a separated router for each controller
it binds error-handling middleware
it binds body-parser middleware (both json and extended urlencoded)
All of the mentioned things reflect a real-world example (probably 99.9% express apps have to do this as well, it's unavoidable). It means that if you want to compare Express and Nest performance, you should at least cover above points. The comparison with the example below:
app.get('/', (req, res, next) => res.status(200).send('Hello world'));
Is unfair in this case, because it's not enough. When I cover these points, this is what I received (express 4.16.2):
Running 10s test # http://localhost:3000
1024 connections
Stat Avg Stdev Max
Latency (ms) 225.67 109.97 762
Req/Sec 4560 1034.78 5335
Bytes/Sec 990 kB 226 kB 1.18 MB
46k requests in 10s, 9.8 MB read
Additionally, Nest has to:
recognize whether a result is a Promise/Observable/plain value
based on the result type, use send() or json() (+1 condition)
add 3 conditions (if statements) to check pipes, interceptors and guards
There's an output for Nest (4.5.8):
Running 10s test # http://localhost:3000
1024 connections
Stat Avg Stdev Max
Latency (ms) 297.79 55.5 593
Req/Sec 3433.2 367.84 3649
Bytes/Sec 740 kB 81.9 kB 819 kB
34k requests in 10s, 7.41 MB read
This implies that Nest performance is around 79% express (-21%). This is due to the reasons set out above, and moreover, because Nest is compatible with Node 6.11.x which means that it can't use async/await under the hood - it has to use generators.
Which conclusion is to be drawn based on those stats? None, because we aren't used to creating applications that only returns plain strings without any asynchronous stuff. The comparisons with Hello world means nothing, it's only a titbit :)
PS. I used autocannon library https://github.com/mcollina/autocannon
autocannon -c 1024 -t30 http://localhost:3000
Related
We have built a graphql API , with our services written in node.js and leveraging apollo server. We are experiencing high CPU usage whenever requests per sec reach 20. We did profiling with flamegraphs and node built in profiler. Attaching the result of the built in profiler:-
[Summary]:
ticks total nonlib name
87809 32.1% 95.8% JavaScript
0 0.0% 0.0% C++
32531 11.9% 35.5% GC
182061 66.5% Shared libraries
3878 1.4% Unaccounted
[Shared libraries]:
ticks total nonlib name
138326 50.5% /usr/bin/node
30023 11.0% /lib/x86_64-linux-gnu/libc-2.27.so
12466 4.6% /lib/x86_64-linux-gnu/libpthread-2.27.so
627 0.2% [vdso]
567 0.2% /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25
52 0.0% /lib/x86_64-linux-gnu/libm-2.27.so
Results from flamegraph also complement the above result that we didn't see any javascript function consuming high CPU.
Why /usr/bin/node is consuming so much CPU? has it something to do with the way code has been written or it is in general the trend?
Also to give little info about what our graphQL API Does:- upon receiving a request, depending on the request it makes 3 to 5 downstream API calls and doesn't do any CPU intensive work on it's own.
Versions:-
Node version:- 10.16.3
graphql-modules/core:- 0.7.7
apollo-datasource-rest:- 0.5.0
apollo-server-express:- 2.6.8
A help is really appreciated here.
Something that seems easy, but I don't find the way to do that. Does it possible to change the header sent in a response
server: ArangoDB
by something else (in order to be less verbose and more secure) ?
Also, I need to store a large string (very long url + lot of informations) in a document, but what is the max length of a joi.string ?
Thx,
The internal string limit in V8 (the JavaScript engine used by ArangoDB) is around 256 MB in the V8 version used by ArangoDB. Thus 256 MB will be the absolute maximum string length that can be used from JavaScript code that's executed in ArangoDB.
Regarding maximum URL lengths as mentioned above: URLs should get too long because very long URLs may not be too portable across browsers. I think in practice several browser will enforce some URL max length limits of around 64 K, so URLs should definitely not get longer than this value. I would recommend using much shorter URLs though and passing hugh payloads in the HTTP request body instead. This also means you may need to change from HTTP GET to HTTP POST or HTTP PUT, but its at least portable.
Finally regarding the HTTP response header "Server: ArangoDB" that is sent by ArangoDB in every HTTP response: starting with ArangoDB 2.8, there is an option to turn this off: --server.hide-product-header true. This option is not available in the stable 2.7 branch yet.
No, there currently is no configuration to disable the server: header in ArangoDB.
I would recommend prepending an NGiNX or similar HTTP-Proxy to achieve that (and other possible hardening for your service).
The implementation of server header can be found in lib/Rest/HttpResponse.cpp.
Regarding Joi -
I only found howto specify a string length in joi - not what its maximum could be.
I guess the general javascript limit for strings should be taken into account.
However, it rather seems that you shouldn't exceed the limit of 2000 chars for URLs which thereby should be the limit.
I have a list of thousands of URLs. I want to get a health check (healt.php) with an http request.
This is my problem:
I've wrote an application in node. It makes the requests in a pooled way. I use a variable to control how many concurrent connections I open. 300, ie.
One by one, each request is so fast, no more than 500ms.
But when I run the application, the result is:
$ node agent.js
200ms url1.tld
250ms url4.tld
400ms url2.tld
530ms url8.tld
800ms url3.tld
...
2300ms urlN.tld
...
30120ms urlM.tld
It seems that there is a limit in concurrency. When I execute
$ ps axo nlwp,cmd | grep node
The result is:
6 node agent.js
There are 6 threads to manage all concurrent connections. I found an evn variable to control concurrency in node: UV_THREADPOOL_SIZE
$ UV_THREADPOOL_SIZE=300 node agent.js
200ms url1.tld
210ms url4.tld
220ms url2.tld
240ms url8.tld
400ms url3.tld
...
800ms urlN.tld
...
1010ms urlM.tld
The problem is still there, but the results are much better. With the ps command:
$ ps axo nlwp,cmd | grep node
132 node agent.js
Next step: Looking in the source code of node, I've found a constant in deps/uv/src/unix/threadpool.c:
#define MAX_THREADPOOL_SIZE 128
Ok. I've changed that value to 2048, compiled and installed node and run once the command
$ UV_THREADPOOL_SIZE=300 node agent.js
All seems ok. Response times are not incrementing gradually. But when I try with a bigger concurrency number the problema appears. But this time it's not related to the number of threads, because with the ps command I see there are enough of them.
I tried to write the same application in golang, but the results are the same. The time is increasing gradually.
So, my question is: Where is the concurrence limit? memory and cpu load and bandwith are not out of bounds. And I tuned sysctl.conf and limits.conf to avoid some limits (files, ports, memory, ...).
You may be throttled by http.globalAgent's maxSockets. Depending on whether you're using http or https, see if this fixes your problem:
require('http').globalAgent.maxSockets = Infinity;
require('https').globalAgent.maxSockets = Infinity;
If you're using request or request-promise you can set the pool size:
request({
url: url,
json: true,
pool: {maxSockets: Infinity},
timeout: 2000
})
More info here: https://github.com/request/request
So I am using node.js and socket.io. I have this little program that takes the contents of a text box and sends it to the node.js server. Then, the server relays it back to other connected clients. Kind of like a chat service but not exactly.
Anyway, what if the user were to type 2-10k worth of text and try to send that? I know I could just try it out and see for myself but I'm looking for a practical, best practice limit on how much data I can do through an emit.
As of v3, socket.io has a default message limit of 1 MB. If a message is larger than that, the connection will be killed.
You can change this default by specifying the maxHttpBufferSize option, but consider the following (which was originally written over a decade ago, but is still relevant):
Node and socket.io don't have any built-in limits. What you do have to worry about is the relationship between the size of the message, number of messages being send per second, number of connected clients, and bandwidth available to your server – in other words, there's no easy answer.
Let's consider a 10 kB message. When there are 10 clients connected, that amounts to 100 kB of data that your server has to push out, which is entirely reasonable. Add in more clients, and things quickly become more demanding: 10 kB * 5,000 clients = 50 MB.
Of course, you'll also have to consider the amount of protocol overhead: per packet, TCP adds ~20 bytes, IP adds 20 bytes, and Ethernet adds 14 bytes, totaling 54 bytes. Assuming a MTU of 1500 bytes, you're looking at 8 packets per client (disregarding retransmits). This means you'll send 8*54=432 bytes of overhead + 10 kB payload = 10,672 bytes per client over the wire.
10.4 kB * 5000 clients = 50.8 MB.
On a 100 Mbps link, you're looking at a theoretical minimum of 4.3 seconds to deliver a 10 kB message to 5,000 clients if you're able to saturate the link. Of course, in the real world of dropped packets and corrupted data requiring retransmits, it will take longer.
Even with a very conservative estimate of 8 seconds to send 10 kB to 5,000 clients, that's probably fine in chat room where a message comes in every 10-20 seconds.
So really, it comes down to a few questions, in order of importance:
How much bandwidth will your server(s) have available?
How many users will be simultaneously connected?
How many messages will be sent per minute?
With those questions answered, you can determine the maximum size of a message that your infrastructure will support.
Limit = 1M (By Default)
Use this example config to specify your custom limit for maxHttpBufferSize:
const io = require("socket.io")(server, {
maxHttpBufferSize: 1e8, pingTimeout: 60000
});
1e8 = 100,000,000 : that can be good for any large scale response/emit
pingTimeout : When the emit was large then it take time and you need increase pingtime too
Read more from Socket.IO Docs
After these setting, if your problem is still remaining then you can check related proxy web server configs, like client_max_body_size, limit_rate in
nginx (if u have related http proxy to socketIO app) or client/server Firewall rules.
2-10k is fine, there arn't any enforced limits or anything, it just comes down to bandwidth and practicality.. 10k is small though in the grand scheme of things so you should be fine if that's somewhat of an upper bound for you.
I need to test a web form that takes a file upload.
The filesize in each upload will be about 10 MB.
I want to test if the server can handle over 100 simultaneous uploads, and still remain
responsive for the rest of the site.
Repeated form submissions from our office will be limited by our local DSL line.
The server is offsite with higher bandwidth.
Answers based on experience would be great, but any suggestions are welcome.
Use the ab (ApacheBench) command-line tool that is bundled with Apache
(I have just discovered this great little tool). Unlike cURL or wget,
ApacheBench was designed for performing stress tests on web servers (any type of web server!).
It generates plenty statistics too. The following command will send a
HTTP POST request including the file test.jpg to http://localhost/
100 times, with up to 4 concurrent requests.
ab -n 100 -c 4 -p test.jpg http://localhost/
It produces output like this:
Server Software:
Server Hostname: localhost
Server Port: 80
Document Path: /
Document Length: 0 bytes
Concurrency Level: 4
Time taken for tests: 0.78125 seconds
Complete requests: 100
Failed requests: 0
Write errors: 0
Non-2xx responses: 100
Total transferred: 2600 bytes
HTML transferred: 0 bytes
Requests per second: 1280.00 [#/sec] (mean)
Time per request: 3.125 [ms] (mean)
Time per request: 0.781 [ms] (mean, across all concurrent requests)
Transfer rate: 25.60 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 2.6 0 15
Processing: 0 2 5.5 0 15
Waiting: 0 1 4.8 0 15
Total: 0 2 6.0 0 15
Percentage of the requests served within a certain time (ms)
50% 0
66% 0
75% 0
80% 0
90% 15
95% 15
98% 15
99% 15
100% 15 (longest request)
Automate Selenium RC using your favorite language. Start 100 Threads of Selenium,each typing a path of the file in the input and clicking submit.
You could generate 100 sequentially named files to make looping over them easyily, or just use the same file over and over again
I would perhaps guide you towards using cURL and submitting just random stuff (like, read 10MB out of /dev/urandom and encode it into base32), through a POST-request and manually fabricate the body to be a file upload (it's not rocket science).
Fork that script 100 times, perhaps over a few servers. Just make sure that sysadmins don't think you are doing a DDoS, or something :)
Unfortunately, this answer remains a bit vague, but hopefully it helps you by nudging you in the right track.
Continued as per Liam's comment:
If the server receiving the uploads is not in the same LAN as the clients connecting to it, it would be better to get as remote nodes as possible for stress testing, if only to simulate behavior as authentic as possible. But if you don't have access to computers outside the local LAN, the local LAN is always better than nothing.
Stress testing from inside the same hardware would be not a good idea, as you would do double load on the server: Figuring out the random data, packing it, sending it through the TCP/IP stack (although probably not over Ethernet), and only then can the server do its magic. If the sending part is outsourced, you get double (taken with an arbitrary sized grain of salt) performance by the receiving end.