JuliaWeb / HttpServer.jl

DEPRECATED! Basic, non-blocking HTTP server in Julia.

Home Page:https://github.com/JuliaWeb/HTTP.jl

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Performance issue without keep-alive

opened this issue · comments

Here is a simple server

using HttpServer

gc_enable(false)

const Z = "HELLO WORLD"

http = HttpHandler() do req::Request, res::Response
    r = Response(Z)
    r
end

server = Server( http )
@profile run( server, 8000 )

And here are three ab tests:
NO KEEPALIVE 15k:

$ ab -n15000  'http://localhost:8000/'
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking localhost (be patient)
Completed 1500 requests
Completed 3000 requests
Completed 4500 requests
Completed 6000 requests
Completed 7500 requests
Completed 9000 requests
Completed 10500 requests
Completed 12000 requests
Completed 13500 requests
Completed 15000 requests
Finished 15000 requests


Server Software:        Julia/0.4.0
Server Hostname:        localhost
Server Port:            8000

Document Path:          /
Document Length:        11 bytes

Concurrency Level:      1
Time taken for tests:   9.492 seconds
Complete requests:      15000
Failed requests:        0
Write errors:           0
Total transferred:      2505000 bytes
HTML transferred:       165000 bytes
Requests per second:    1580.27 [#/sec] (mean)
Time per request:       0.633 [ms] (mean)
Time per request:       0.633 [ms] (mean, across all concurrent requests)
Transfer rate:          257.72 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.0      0       1
Processing:     0    1   2.3      0     276
Waiting:        0    0   0.2      0      23
Total:          0    1   2.3      1     276

Percentage of the requests served within a certain time (ms)
  50%      1
  66%      1
  75%      1
  80%      1
  90%      1
  95%      1
  98%      1
  99%      1
 100%    276 (longest request)

NO KEEPALIVE 20k:

$ ab -n20000  'http://localhost:8000/'
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking localhost (be patient)
Completed 2000 requests
Completed 4000 requests
Completed 6000 requests
Completed 8000 requests
Completed 10000 requests
Completed 12000 requests
Completed 14000 requests
Completed 16000 requests
apr_socket_recv: Operation timed out (60)
Total of 16351 requests completed

WITH KEEPALIVE 20k:

$ ab -n20000 -k 'http://localhost:8000/'
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking localhost (be patient)
Completed 2000 requests
Completed 4000 requests
Completed 6000 requests
Completed 8000 requests
Completed 10000 requests
Completed 12000 requests
Completed 14000 requests
Completed 16000 requests
Completed 18000 requests
Completed 20000 requests
Finished 20000 requests


Server Software:        Julia/0.4.0
Server Hostname:        localhost
Server Port:            8000

Document Path:          /
Document Length:        11 bytes

Concurrency Level:      1
Time taken for tests:   8.167 seconds
Complete requests:      20000
Failed requests:        0
Write errors:           0
Keep-Alive requests:    20000
Total transferred:      3820000 bytes
HTML transferred:       220000 bytes
Requests per second:    2448.94 [#/sec] (mean)
Time per request:       0.408 [ms] (mean)
Time per request:       0.408 [ms] (mean, across all concurrent requests)
Transfer rate:          456.78 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.0      0       0
Processing:     0    0   0.1      0       3
Waiting:        0    0   0.1      0       3
Total:          0    0   0.1      0       3

Percentage of the requests served within a certain time (ms)
  50%      0
  66%      0
  75%      0
  80%      0
  90%      1
  95%      1
  98%      1
  99%      1
 100%      3 (longest request)

As can be seen, HttpServer has a good performance, however after some number of requests it temporarily hangs somewhere. It is still operational after the hang has passed.

Tests were done with Julia 0.4.0 on MacOS 10.9.5 with standard ab

I can reproduce this on my own 10.9 system.

It's possible this is related to JuliaWeb/Requests.jl#61 and might be a pretty low-level issue with the Julia/libuv interaction.

I installed Julia 0.4.0 on Monday and checked out the master branch of HttpServer.jl.
I did the following, hope it helps:

ab -n20000 'http://localhost:8000/' gave the following output:

Benchmarking localhost (be patient)...apr_socket_recv: Connection refused (111)

ab -n20 'http://127.0.0.1:8000/' and ab -n20 'http://0.0.0.0:8000/' worked without any problems.

EDIT: Those last 2 commands should have -n20000, not -n20.

As an additional data point, and to rule out any weirdness with ab, I also did the following:

In one terminal:

using HttpServer

function app(req::Request, res::Response)
    Response("Hello world")
end

server = Server(app)
run(server, 8000)

In another terminal:

using Requests

function bench(n)
    total = 0
    for i = 1:n
        res = get("http://0.0.0.0:8000/")
        total += res.status
    end
    total
end

Then:
julia> @time bench(2) # Warm up
0.831835 seconds (1.07 k allocations: 310.297 KB)
400

julia> @time bench(2)
0.002535 seconds (1.13 k allocations: 439.906 KB)
400

julia> @time bench(100)
0.100428 seconds (58.56 k allocations: 21.174 MB, 5.83% gc time)
20000

julia> @time bench(1000)
0.489691 seconds (582.08 k allocations: 213.469 MB, 4.22% gc time)
200000

julia> @time bench(10000)
4.210345 seconds (5.89 M allocations: 2.092 GB, 3.36% gc time)
2000000

julia> @time bench(16000)
6.730394 seconds (9.35 M allocations: 3.338 GB, 3.33% gc time)
3200000

julia> @time bench(17000)
ERROR: connect: address not available (EADDRNOTAVAIL)
in connect! at socket.jl:646
in connect at socket.jl:669
in open_stream at /home/jock/.julia/v0.4/Requests/src/streaming.jl:162
in do_stream_request at /home/jock/.julia/v0.4/Requests/src/Requests.jl:282
in do_request at /home/jock/.julia/v0.4/Requests/src/Requests.jl:229
in get at /home/jock/.julia/v0.4/Requests/src/Requests.jl:344
in get at /home/jock/.julia/v0.4/Requests/src/Requests.jl:343
in bench at none:4

Then after waiting 30 seconds or so, the server becomes available again:
julia> @time bench(10)
0.016493 seconds (5.79 k allocations: 2.153 MB)
2000

julia> @time bench(17000)
7.156743 seconds (9.91 M allocations: 3.555 GB, 3.31% gc time)
3400000

julia> @time bench(20000)
8.326596 seconds (11.71 M allocations: 4.189 GB, 3.32% gc time)
4000000

Well, I am quite embarrassed and sorry for all the fuss. Thank you @JockLawrie for the error code.
It turns out the problem is with the benchmarking, please take a look: http://danielmendel.github.io/blog/2013/04/07/benchmarkers-beware-the-ephemeral-port-limit/
Well, I learned something new

Mmm, I didn't about that phenomenon either. So this has been a good
learning experience for all of us.

On Fri, Oct 30, 2015 at 7:22 PM Nikolay Markov notifications@github.com
wrote:

Well, I am quite embarrassed and sorry for all the fuss. Thank you
@JockLawrie https://github.com/JockLawrie for the error code.
It turns out the problem is with the benchmarking, please take a look:
http://danielmendel.github.io/blog/2013/04/07/benchmarkers-beware-the-ephemeral-port-limit/
Well, I learned something new


Reply to this email directly or view it on GitHub
#78 (comment)
.

It's news to me too. Thanks for the link to the explanation @inwit-info.