iLya2IK / wchttpserver

HTTP/2+HTTP/1.1+WebSocket server written with Lazarus (Free Pascal)
GNU Lesser General Public License v2.1
57 stars 18 forks source link

info for FPC wiki? #6

Open Alexey-T opened 3 years ago

Alexey-T commented 3 years ago

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

iLya2IK commented 3 years ago

Yes of course. As soon as there is more free time and when the design of the project becomes stable

datiscum commented 2 years ago

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 ?

iLya2IK commented 2 years ago

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.

iLya2IK commented 2 years ago

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%
datiscum commented 2 years ago

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.

datiscum commented 2 years ago

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.

iLya2IK commented 2 years ago

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 :)

datiscum commented 2 years ago

I changed your new "GetGet" to "Get"