Open Alexey-T opened 3 years ago
Yes of course. As soon as there is more free time and when the design of the project becomes stable
I am writing my comments here to address your "the project becomes stable". I have now spent a day working through the nice looking source code. While testing, I noticed several things that are not technically well implemented. In Linux, "top" shows a constant low CPU load although the server has nothing to do. Since the code is quite complex, I can't suggest any improvements now. In any case, the implementation of "epoll" cannot be intended in this way and looks a bit like copying from the "lnet" project, which implemented it just as badly. Epoll is called again and again with an extremely short waiting time in the main thread. This also causes the load at rest. The poor design has a significant impact on performance. A small test with me under Linux: First the "nghttpd" a Github project in c.
h2load -n 1000 -c 10 https://test.datiscum.com/ starting benchmark... spawning thread #0: 10 total client(s). 1000 total requests TLS Protocol: TLSv1.3 Cipher: TLS_AES_256_GCM_SHA384 Server Temp Key: ECDH P-256 256 bits Application protocol: h2
finished in 33.68ms, 26.65MB/s requests: 1000 total, 1000 started, 1000 done, 1000 succeeded, 0 failed, 0 errored, 0 timeout status codes: 1000 2xx, 0 3xx, 0 4xx, 0 5xx traffic: 918.99KB (941050) total, 11.53KB (11810) headers (space savings 93.29%), 889.65KB (911000) data req/s (min/max/mean) : 2993.31 3084.86 3042.43
Now with "wchttp" Server: wchttp h2load -n 1000 -c 10 https://test.datiscum.com/ starting benchmark... spawning thread #0: 10 total client(s). 1000 total requests TLS Protocol: TLSv1.2 Cipher: ECDHE-RSA-AES256-GCM-SHA384 Server Temp Key: X25519 253 bits Application protocol: h2
finished in 7.46s, 129.28KB/s requests: 1000 total, 1000 started, 1000 done, 1000 succeeded, 0 failed, 0 errored, 0 timeout status codes: 1000 2xx, 0 3xx, 0 4xx, 0 5xx traffic: 964.15KB (987285) total, 56.57KB (57925) headers (space savings 64.02%), 889.65KB (911000) data req/s (min/max/mean) : 13.42 15.72 14.81
As you can see, the difference is so big that you can hardly believe it. To compare it with another Lazarus project I tested the "httpsserver" from the Synapse package with "ApacheBench". It does not support Http2 and "h2load" shows this as an error. The values of "ab" look like this: Server Software: Synapse Server Hostname: test.datiscum.com SSL/TLS Protocol: TLSv1.2,ECDHE-RSA-AES256-GCM-SHA384,2048,256 Server Temp Key: X25519 253 bits TLS Server Name: test.datiscum.com Concurrency Level: 10 Time taken for tests: 0.455 seconds Complete requests: 1000 Failed requests: 0 Total transferred: 391000 bytes HTML transferred: 237000 bytes Requests per second: 2199.13 [#/sec] (mean) Time per request: 4.547 [ms] (mean) Time per request: 0.455 [ms] (mean, across all concurrent requests)
The "requests per second" show that an HTTPS server in Lazarus can also deliver good values. Synapse = 2.199 (mean) compared to nghttpd = 3.042. But only 15 from wchttpd is absolutely unacceptable. In the Lazarus forum I saw a test of yours that comes to 60, but that doesn't change much either.
Are you still working on it or do you need help ?
Thank you for your interest in the project. Indeed - I encountered this problem - but the speed of work suited me so far and I was in no hurry to correct this shortcoming. It is difficult for me to determine what is reason. Most likely this is caused by a large number of competing threads, as well as overheating from the epoll. Try in the settings (server.cfg) to reduce the number of threads that process incoming connections ("PreThreadsCnt":2) and the number of worker threads ("MainThreadsCnt":2). In addition - the server can work in REST and RPC mode. In RPC mode, the server may slow down when there are many hits without a fixed cookie CID value. If there are constructive suggestions to improve the quality of the server, I will gladly try to implement them.
A number of improvements have been made to the code. Due to which the productivity has increased. Here are the new results of testing by the h2load utility:
> h2load -n 1000 -c 10 https://localhost:8080/test.json
starting benchmark...
spawning thread #0: 10 total client(s). 1000 total requests
TLS Protocol: TLSv1.3
Cipher: TLS_AES_256_GCM_SHA384
Server Temp Key: X25519 253 bits
Application protocol: h2
progress: 100% done
finished in 672.72ms, 1486.51 req/s, 70.41KB/s
requests: 1000 total, 1000 started, 1000 done, 1000 succeeded, 0 failed, 0 errored, 0 timeout
status codes: 1000 2xx, 0 3xx, 0 4xx, 0 5xx
traffic: 47.36KB (48500) total, 3.07KB (3140) headers (space savings 93.32%), 26.37KB (27000) data
min max mean sd +/- sd
time for request: 1.09ms 20.38ms 6.11ms 1.44ms 82.40%
time for connect: 16.41ms 37.75ms 30.23ms 7.04ms 70.00%
time to 1st byte: 36.82ms 41.08ms 39.04ms 1.20ms 80.00%
req/s : 148.75 163.79 155.50 5.48 50.00%
> h2load -n 1000 -c 10 -m 10 -t 10 https://localhost:8080/test.json
-t: warning: the number of threads is greater than hardware cores.
starting benchmark...
spawning thread #0: 1 total client(s). 100 total requests
spawning thread #1: 1 total client(s). 100 total requests
spawning thread #2: 1 total client(s). 100 total requests
spawning thread #3: 1 total client(s). 100 total requests
spawning thread #4: 1 total client(s). 100 total requests
spawning thread #5: 1 total client(s). 100 total requests
spawning thread #6: 1 total client(s). 100 total requests
spawning thread #7: 1 total client(s). 100 total requests
spawning thread #8: 1 total client(s). 100 total requests
spawning thread #9: 1 total client(s). 100 total requests
TLS Protocol: TLSv1.3
Cipher: TLS_AES_256_GCM_SHA384
Server Temp Key: X25519 253 bits
Application protocol: h2
progress: 100% done
finished in 584.63ms, 1710.49 req/s, 81.01KB/s
requests: 1000 total, 1000 started, 1000 done, 1000 succeeded, 0 failed, 0 errored, 0 timeout
status codes: 1000 2xx, 0 3xx, 0 4xx, 0 5xx
traffic: 47.36KB (48500) total, 3.07KB (3140) headers (space savings 93.32%), 26.37KB (27000) data
min max mean sd +/- sd
time for request: 14.76ms 94.85ms 51.92ms 10.56ms 77.00%
time for connect: 19.70ms 33.39ms 27.28ms 5.10ms 60.00%
time to 1st byte: 47.81ms 59.60ms 53.17ms 4.99ms 60.00%
req/s : 171.17 228.34 181.51 17.09 90.00%
For comparison, I will give the old results obtained on the same hardware.
> h2load -n 1000 -c 10 https://localhost:8080/test.json
starting benchmark...
spawning thread #0: 10 total client(s). 1000 total requests
TLS Protocol: TLSv1.3
Cipher: TLS_AES_256_GCM_SHA384
Server Temp Key: X25519 253 bits
Application protocol: h2
progress: 100% done
finished in 3.38s, 295.64 req/s, 14.00KB/s
requests: 1000 total, 1000 started, 1000 done, 1000 succeeded, 0 failed, 0 errored, 0 timeout
status codes: 1000 2xx, 0 3xx, 0 4xx, 0 5xx
traffic: 47.36KB (48500) total, 3.07KB (3140) headers (space savings 93.32%), 26.37KB (27000) data
min max mean sd +/- sd
time for request: 7.35ms 55.31ms 22.78ms 5.00ms 81.60%
time for connect: 12.28ms 1.07s 435.62ms 540.18ms 60.00%
time to 1st byte: 29.47ms 1.09s 460.16ms 538.93ms 60.00%
req/s : 29.57 43.93 37.96 6.82 60.00%
5 times more requests within one working day. I would have liked to test it again, but apparently something is wrong with the "ifdef".
{$IFDEF SERVER_RPC_MODE} {$UNDEF SERVER_REST_MODE} {$ELSE} {$DEFINE SERVER_REST_MODE} {$ENDIF}
The demo project can no longer be compiled, I may have time to take a closer look tomorrow.
My problem started with the following in line 4541: "WCGetGetRemoteAddress" in "wcapplication.pas". But I didn't notice that with the "GetGet". Then in the definitions "-dSERVER_RPC_MODE" "-dWC_WEB_SOCKETS" individually, which then led to new problems. It is sufficient to change "WCGetGetRemoteAddress" to "WCGetEemoteAddress". But the fact that you can select the defines yourself should also work.
I did not quite understand - if you change GetGet to Get in the source code, everything starts working? Could it be compiled with additional definitions? Unfortunately, I can't check it right now - as soon as I get to my computer, I'll try to compile a demo. Also, please open a new issue so we can work together to find the right build strategy and not clutter up Alex's mail :)
I changed your new "GetGet" to "Get"
can you write the detailed page for wiki? you can do it in Ru, I will translate it to En. you can write it here in GH. I will post the wiki.
example- https://wiki.freepascal.org/ATSynEdit