Golang http server is ridiculously slow

9,451 views
Skip to first unread message

denis.ch...@gmail.com

unread,
Mar 5, 2012, 5:19:03 PM3/5/12
to golan...@googlegroups.com
Hello!
I wonder why the go http server is SO slow? In fact, it's more than twice slower than python version that uses gevent.
I tried both weekly and release compilers, but nothing changed, they both are slow.
In perflog.log result of gevent at the top then golang server one at the bottom. The python version is twice faster.
a.go
a.py
perflog.log

Rémy Oudompheng

unread,
Mar 5, 2012, 6:03:00 PM3/5/12
to denis.ch...@gmail.com, golan...@googlegroups.com

I wouldn't call 6k requests per second "ridiculously slow".
Did you try latest weekly releases? Improvements may have appeared in
the past 6 months.
Also, did you try setting GOMAXPROCS to something > 1? It's not clear
the python version scales so well.

--
Rémy.

Brad Fitzpatrick

unread,
Mar 5, 2012, 6:17:56 PM3/5/12
to denis.ch...@gmail.com, golan...@googlegroups.com
You should try setting the Content-Length & Content-Type in the Go version, like you are in the Python version.  Then you avoid chunking and sniffing, respectively.  Also, have both send the same output.  Also, verify they're both sending the same headers.  Go sends some HTTP headers that are "SHOULDs" but you can turn off if you really care about bandwidth.

Also, use a recent weekly release.  The last "release" version of Go was a long time ago and much has been improved.

denis.ch...@gmail.com

unread,
Mar 5, 2012, 6:52:40 PM3/5/12
to golan...@googlegroups.com, denis.ch...@gmail.com
Thank you Brad, this sounds very reasonable. But how can I do this? I tried to add headers via Headers().Set("Content-Type", …), etc, but nothing has changed, the server still returns chunked data.

func HelloServer(c http.ResponseWriter, req *http.Request) {
    result := "hello, world!\n"
    io.WriteString(c, result)
    c.Header().Set("Content-Type", "text/plain")
    c.Header().Set("Content-Length", string(len(result)))
}


вторник, 6 марта 2012 г. 3:17:56 UTC+4 пользователь Brad Fitzpatrick написал:

John Barham

unread,
Mar 5, 2012, 7:24:33 PM3/5/12
to denis.ch...@gmail.com, Brad Fitzpatrick, golan...@googlegroups.com

Set the headers and turn on GOMAXPROCS and Go is faster:

$ cat a.py
#!/usr/bin/python2.7

from gevent import http

def callback(request):
body = '<b>hello world</b>'
request.add_output_header('Content-Type', 'text/html')
request.add_output_header('Content-Length', str(len(body)))
request.send_reply(200, "OK", body)

print 'Serving on 8088...'
http.HTTPServer(('0.0.0.0', 8088), callback).serve_forever()
$ python2.7 a.py &
$ ab -q -c 50 -n 100000 http://127.0.0.1:8088/ | grep "Requests per second"
Requests per second: 14557.18 [#/sec] (mean)
$ go version
go version weekly.2012-03-04 +f4470a54e6db
$ cat a.go
package main

import (
"io"
"net/http"
"strconv"
)

func HelloServer(c http.ResponseWriter, req *http.Request) {

body := "<b>hello world</b>"
c.Header().Add("Content-Type", "text/html")
c.Header().Add("Content-Length", strconv.Itoa(len(body)))
io.WriteString(c, body)
}

func main() {
http.Handle("/", http.HandlerFunc(HelloServer))
http.ListenAndServe(":8080", nil)
}
$ GOMAXPROCS=4 go run a.go &
$ ab -q -c 50 -n 100000 http://127.0.0.1:8080/ | grep "Requests per second"
Requests per second: 20152.81 [#/sec] (mean)

That's running on a 2.67 GHz i5 in 386 mode. The amd64 Go version
would likely be even faster.

FWIW the gevent library is a 3rd party extension to Python whereas the
Go version is all standard library.

John

David Symonds

unread,
Mar 5, 2012, 7:26:14 PM3/5/12
to denis.ch...@gmail.com, golan...@googlegroups.com
On Tue, Mar 6, 2012 at 10:52 AM, <denis.ch...@gmail.com> wrote:

> Thank you Brad, this sounds very reasonable. But how can I do this? I tried
> to add headers via Headers().Set("Content-Type", …), etc, but nothing has
> changed, the server still returns chunked data.
>
> func HelloServer(c http.ResponseWriter, req *http.Request) {
>     result := "hello, world!\n"
>     io.WriteString(c, result)
>     c.Header().Set("Content-Type", "text/plain")
>     c.Header().Set("Content-Length", string(len(result)))
> }

You need to set the headers *before* writing the body.

Nigel Tao

unread,
Mar 5, 2012, 7:53:04 PM3/5/12
to denis.ch...@gmail.com, golan...@googlegroups.com
On 6 March 2012 10:52, <denis.ch...@gmail.com> wrote:
>     c.Header().Set("Content-Length", string(len(result)))

In case it wasn't obvious in John's response... in Go, string(65) is
"A", not "65". Use strconv.Itoa(len(result)).

denis.ch...@gmail.com

unread,
Mar 6, 2012, 2:20:50 AM3/6/12
to golan...@googlegroups.com, denis.ch...@gmail.com, Brad Fitzpatrick
With Content-Length set properly and 4 cores used (GOMAXPROCS=4, at core 2 quad q6600) I only could match the gevent speed:

ab -c 50 -n 100000 http://127.0.0.1:8080/ | grep -i requests
Requests per second:    12514.18 [#/sec] (mean)

At the single core it's not any faster than chunked version. Disappointing result, I hoped to see equal performance at least.
Ubuntu 11.04 x64 with 2.6.38 x64 kernel, Core 2 Quad Q6600.


вторник, 6 марта 2012 г. 4:24:33 UTC+4 пользователь John Barham написал:

Alex

unread,
Mar 6, 2012, 3:21:32 AM3/6/12
to golan...@googlegroups.com
I tested your python version vs my go version on my machine and got:
For python:
> ab -c 50 -n 100000 http://127.0.0.1:8080/|grep 'Requests per second'
.......
Finished 100000 requests
Requests per second: 17805.53 [#/sec] (mean)

For go:
> ab -c 50 -n 100000 http://127.0.0.1:8088/|grep 'Requests per second'
.......
Finished 100000 requests
Requests per second: 19514.37 [#/sec] (mean)

My code in go:
package main

import (
"net/http"
"io"
"strconv"
)

func HelloServer(c http.ResponseWriter, req *http.Request) {

result := "hello, world!\n"

c.Header().Set("Content-Type", "text/plain")

c.Header().Set("Content-Length", strconv.Itoa(len(result)))
io.WriteString(c, "hello, world!\n");
}

func main() {
http.Handle("/", http.HandlerFunc(HelloServer));

http.ListenAndServe(":8080", nil);
}

I used export GOMAXPROCS=8 and Go built from today's tip.

So I don't think that Go version is so slow.

Thanks,
Alex

Patrick Mylund Nielsen

unread,
Mar 6, 2012, 3:27:08 AM3/6/12
to Alex, golan...@googlegroups.com
This is also kind of a pointless test. Async vs. SMP -- try doing some
work in those requests and I'm sure the difference will be clear.

roger peppe

unread,
Mar 6, 2012, 5:52:59 AM3/6/12
to denis.ch...@gmail.com, golan...@googlegroups.com
it's possible that the benchmarking software itself (ab) is interfering
with the performance of the server.

i'd be interested to see the results when the benchmark client
is run on another machine on the local network.

Graham Anderson

unread,
Mar 6, 2012, 6:01:26 AM3/6/12
to golan...@googlegroups.com
On Tuesday 06 Mar 2012 10:52:59 roger peppe wrote:
> it's possible that the benchmarking software itself (ab) is interfering
> with the performance of the server.
>
> i'd be interested to see the results when the benchmark client
> is run on another machine on the local network.

I've also noticed a few people complain that ab2 results seem a bit skewed,
it's probably a safer bet to test with siege.

Graham Anderson

unread,
Mar 6, 2012, 6:11:09 AM3/6/12
to golan...@googlegroups.com

siege -r 10000 -b -c 10 http://localhost:8080/
** SIEGE 2.70
** Preparing 10 concurrent users for battle.
The server is now under siege.. done.
Transactions: 100000 hits
Availability: 100.00 %
Elapsed time: 4.92 secs
Data transferred: 1.72 MB
Response time: 0.00 secs
Transaction rate: 20325.20 trans/sec
Throughput: 0.35 MB/sec
Concurrency: 9.69
Successful transactions: 100000
Failed transactions: 0
Longest transaction: 0.01
Shortest transaction: 0.00

ab2 -c 10 -n 100000 http://localhost:8080/
This is ApacheBench, Version 2.3
Concurrency Level: 10
Time taken for tests: 6.113 seconds
Complete requests: 100000
Failed requests: 0
Write errors: 0
Total transferred: 11900000 bytes
HTML transferred: 1800000 bytes
Requests per second: 16359.38 [#/sec] (mean)
Time per request: 0.611 [ms] (mean)
Time per request: 0.061 [ms] (mean, across all concurrent requests)
Transfer rate: 1901.14 [Kbytes/sec] received

André Moraes

unread,
Mar 6, 2012, 6:59:52 AM3/6/12
to golan...@googlegroups.com
What are the performance differences when using ngnix or another web server?

If you want to see "raw" speed those should be the target of the benchmark.

--
André Moraes
http://andredevchannel.blogspot.com/

Reply all
Reply to author
Forward
0 new messages