Closed schamberg97 closed 3 years ago
Hi @schamberg97, the value of this contribution is huge!!!
Just a minor request from my side: It would be great to document how v3.0 compares to v.2x in relation to performance (reqs/sec), this would be a good addition to the README. I am curious if there is any performance degradation...
Many thanks.
Hi @schamberg97, the value of this contribution is huge!!!
Just a minor request from my side: It would be great to document how v3.0 compares to v.2x in relation to performance (reqs/sec), this would be a good addition to the README. I am curious if there is any performance degradation...
Many thanks.
I don’t think there’s any severe performance degradation, but you are correct - this needs to be done. I will make the commit soon
@jkyberneees There is in fact one change that creates a performance degradation and you were wise to ask about this. It is caused by this piece that is responsible for populating req.socket
: https://github.com/jkyberneees/low-http-server/blob/1ab0a9c0ecfc257d86d2a8081982306e4e369307/src/server.js#L37-L46. This functionality isn't strictly required to use any framework, but it helps populate req.ip
in fastify
and similar frameworks.
According to wrk
, it reduces the number of req/s from 56k to 51k per second (around 9-15% loss), when low-http-server
is used without frameworks. With this piece of code removed, I couldn't reliably establish that low-http-server
has become faster or slower, thus the performance has probably remained the same.
The real question is whether to go ahead with this code or remove it. I am in favour of removing it and documenting how to get remote client's IP. The third alternative is to let an end user choose, whether he needs this functionality, which will allow users to relatively painlessly migrate to low-http-server
, if they need to, without sacrificing performance for the rest of users.
P.S. avoiding getter by doing:
{
remoteAddress: ArrayBufferDecoder.decode(resWrapper.res.getRemoteAddressAsText())
}
is even worse in terms of performance.
P.P.S. If remoteAddress functionality is retained, it needs to be rewritten, as I've found a better way to do it
I believe I've been able to eliminate the reason for performance regression by moving res.socket
into a separate class and module.
Using ./demos/0http-basic.js
under low-http-server
2.1.3 (only port number was changed):
schamberg@Nikolays-MacBook-Pro ~> wrk -t8 -c64 -d15s "http://localhost:3001/hi"
Running 15s test @ http://localhost:3001/hi
8 threads and 64 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 1.07ms 194.20us 5.09ms 91.39%
Req/Sec 7.48k 358.95 8.00k 76.41%
899661 requests in 15.10s, 84.94MB read
Requests/sec: 59578.98
Transfer/sec: 5.63MB
Using ./demos/0http-basic.js
under low-http-server
3.0.0:
schamberg@Nikolays-MacBook-Pro ~> wrk -t8 -c64 -d15s "http://localhost:3000/hi"
Running 15s test @ http://localhost:3000/hi
8 threads and 64 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 1.09ms 198.44us 5.63ms 91.24%
Req/Sec 7.35k 398.61 8.73k 73.57%
882232 requests in 15.10s, 83.29MB read
Requests/sec: 58424.85
Transfer/sec: 5.52MB
The difference between two versions now is only 2% in favour of the previous version. However, 3.0.0 has the benefit of doubt in my mind, as this could have been caused by some thermal issues with my current MacBook Pro (might need to take it to service, I think there's dust build-up). Regardless, I'll look into more ways to increase performance.
Hi @schamberg97, thanks for iterating on this PR. As I see it, any optional functionality that degrades performance should be disabled by default. However, as you are boosting compatibility with little impact on performance, I am fine for a first release.
New abilities
low-http-server
now inherits fromEventEmitter
, so that frameworks relying on HTTP server beingEventEmitter
can now uselow-http-server
as backend.net.socket.remoteAddress
(viaHttpResponse.getRemoteAddressAsText()
from uWebSockets.js)http.ServerResponse.hasHeader
http.ServerResponse.req