How would Go do as a high performance server?

3,713 views
Skip to first unread message

david.harris.uk

unread,
Mar 28, 2011, 5:23:10 PM3/28/11
to golan...@googlegroups.com
I've a need to write a server for my company that will handle very large numbers of concurrent connections (10/20k or more) and I'm looking at languages to do it in. I've been experimenting with Stackless python which does non blocking synchronous IO, & looking at Erlang, which can handle such a demand. I've toyed a little bit with Go but would it be up to this?

Brad Fitzpatrick

unread,
Mar 28, 2011, 6:16:34 PM3/28/11
to golan...@googlegroups.com, david.harris.uk
Yes, Go handles this sort of task with ease. 


For instance, here's a little echo server:

package main

import (
        "bufio"
        "log"
        "net"
)

func main() {
        ln, err := net.Listen("tcp", ":2020")
        if err != nil {
                log.Fatalf("listen error: %v", err)
        }
        accepted := 0
        for {   
                conn, err := ln.Accept()
                if err != nil {
                        log.Fatalf("accept error: %v", err)
                }
                accepted++
                go serve(conn)
                log.Printf("Accepted %d", accepted)
        }
}

func serve(conn net.Conn) {
        bufr := bufio.NewReader(conn)
        for {   
                line, err := bufr.ReadString('\n')
                if err != nil {
                        return
                }
                conn.Write([]byte(line))
        }
}


And here's a client to open 20,000 connection to that machine from a different machine, and then wait doing nothing ("select {}") until you kill it:

package main

import (
        "log"
        "net"
)

func main() {
        var conns []net.Conn
        for i := 0; i < 20000; i++ {
                c, err := net.Dial("tcp", "", "10.0.0.15:2020")
                if err != nil {
                        log.Fatalf("dial error: %v", err)
                }
                conns = append(conns, c)
        }
        select {}
}

Run that client and note the server's output:

...
2011/03/28 15:11:29 Accepted 19997
2011/03/28 15:11:29 Accepted 19998
2011/03/28 15:11:29 Accepted 19999
2011/03/28 15:11:29 Accepted 20000

And memory usage:

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND                                                                                              
32232 bradfitz  20   0  240m 199m  840 S    0  3.3   0:05.78 20k                                                                                                   

Looks like 10 kB / connection.

And you can telnet to it and verify it's working:

$ telnet 10.0.0.15 2020
Trying 10.0.0.15...
Connected to 10.0.0.15.
Escape character is '^]'.
Hello!
Hello!

Fabio Kaminski

unread,
Mar 28, 2011, 7:49:07 PM3/28/11
to Brad Fitzpatrick, golan...@googlegroups.com, david.harris.uk
> I've been experimenting with Stackless python which does non blocking synchronous IO, & looking at Erlang, which can handle such a demand

i think if you can choose the language you are going to use (something that i have done either sometime ago)
there' s a trade between performance and easy of use/development..

Python its the easiest, and maybe the most productive between 3 languages.. (its in the script language nature)

Erlang is very (maybe the most) fun, its FP, but has its costs... immutability could be a burden, its very difficult when you need to handle state, and you throw much of the datastructures algorithms(among others)  known in the computer science in the garbage.. obligating you to implement okasaki 's functional data structures.. (at least there's some solution :))

(think in a simple graph, where you have to mark that graph as visited.. :s)

second Erlang and Python are know to not be very fast (something that is acceptable since they have dinamic types).. but theres a lot of work happening trying to change that.

In my opinion, Go its the most balanced between productivity and efficience (faster than python and erlang, and in pair with java, sometimes faster),
it has low memory footprint , and high implicit paralellism... 

if you like the actors model from erlang, you would love Go channels (something that helps a lot , both with productivity and paralellism)
it has the good parts of OOP, as when you are creating big pieces of software, you can have the level of abstraction that big software needs without to memorize all the design patterns book, and stop solving your real problems, to solve OOP design issues problems.. 

As you can see with Brad example.. its very easy programming a server, and looks like dinamic typing..  the way that the language was conceived, it can produce very efficient and fast binary, and even been very young its in the top faster languages in the computer language benchmark game: 

under the hoods, Go uses non-blocking io to.. so its very efficient in latency...

of course this is only my subjective point of view.. 

Andrew Gerrand

unread,
Mar 28, 2011, 7:57:23 PM3/28/11
to Fabio Kaminski, Brad Fitzpatrick, golan...@googlegroups.com, david.harris.uk
On 29 March 2011 10:49, Fabio Kaminski <fabiok...@gmail.com> wrote:
> there' s a trade between performance and easy of use/development..
> Python its the easiest, and maybe the most productive between 3 languages..
> (its in the script language nature)

IMO this is a myth. Python's dynamic typing causes more problems than
it solves. Runtime errors suck, and tracking them down is a huge
productivity drain in my experience. (Not to mention the reliability
issues in production environments.)

Of course, I'm more than a little biased. ;-)

Andrew

Fabio Kaminski

unread,
Mar 28, 2011, 8:45:39 PM3/28/11
to Andrew Gerrand, Brad Fitzpatrick, golan...@googlegroups.com, david.harris.uk
>IMO this is a myth. Python's dynamic typing causes more problems than
>it solves. Runtime errors suck, and tracking them down is a huge
>productivity drain in my experience. (Not to mention the reliability
>issues in production environments.)

i think what you are saying is very valid. one thing is LOC something that python is very good at,
but real productivity in Big software its very hard to mesure.. for example.. as you pointed out.. how many hours did you lost 
finding bugs, or testing .. effective modularity (wich is a huge win only experienced in long term)..

Chip Camden

unread,
Mar 28, 2011, 9:00:41 PM3/28/11
to golan...@googlegroups.com
Quoth Fabio Kaminski on Monday, 28 March 2011:

> >IMO this is a myth. Python's dynamic typing causes more problems than
> >it solves. Runtime errors suck, and tracking them down is a huge
> >productivity drain in my experience. (Not to mention the reliability
> >issues in production environments.)
>
> i think what you are saying is very valid. one thing is LOC something that
> python is very good at,
> but real productivity in Big software its very hard to mesure.. for
> example.. as you pointed out.. how many hours did you lost
> finding bugs, or testing .. effective modularity (wich is a huge win only
> experienced in long term)..
>
> On Mon, Mar 28, 2011 at 8:57 PM, Andrew Gerrand <a...@golang.org> wrote:
>

IMO it has a lot less to do with the tools than with how they are used.
You can certainly stumble into monkey-patch hell with any number of
dynamic languages, or use pointer arithmetic to load the Russian Roulette
pistol with five bullets in C. Conversely, you can use those very
facilities to construct expressive, understandable code if you know what
you're doing and make it clear to the next person who comes along.

Choosing a language is more about the ability to express your solution to
a problem than it is about preventing bugs. Some problems are better
expressed in languages that can modify themselves. Some benefit from
abstractions that are more oriented towards process control. The list
goes on. That's why there are n languages, with n^n evangelists.

--
.o. | Sterling (Chip) Camden | http://camdensoftware.com
..o | ster...@camdensoftware.com | http://chipsquips.com
ooo | 2048R/D6DBAF91 | http://chipstips.com

Eleanor McHugh

unread,
Mar 29, 2011, 7:40:34 AM3/29/11
to golang-nuts

Ragging on python is too easy ;)

If high performance is the overriding requirement then Go is a very good choice, and the productivity loss compared to dynamic languages is only marginal - by the time you factor in writing tests etc. Go is competitive with both Python and Ruby for any problem that's not heavily based in dynamic typing. And even then you lose a lot less productivity than would be the case in Java or C++.


Ellie

Eleanor McHugh
Games With Brains
http://feyeleanor.tel
----
if _, ok := reality.(Reasonable); !ok { panic(reality) }

Charles Thompson

unread,
Mar 29, 2011, 5:52:16 PM3/29/11
to golang-nuts
+1 for Go.

Go's http lib makes it trivial to write servers because it abstracts
out the mechanics of handling http request/responses, thus enabling
you to focus on your business logic. It feels similar to Ruby Sinatra.

Go's type inference and lightning fast compile times makes me feel as
productive as I am when using a dynamically typed language with a
REPL.

And having the compiler find errors before running the code?
Priceless.

BTW, if you end up using Erlang to write your server, check out
Basho's Webmachine.

Charles
> <david.harris...@gmail.com>wrote:

luisbebop

unread,
Mar 29, 2011, 8:04:31 PM3/29/11
to golang-nuts
Hi Brad.

I've tried your code but i got the error:

"
2011/03/29 20:50:36 Accepted 247
2011/03/29 20:50:36 Accepted 248
2011/03/29 20:50:36 accept error: accept tcp 0.0.0.0:2020: too many
open files
"

I'm using Macosx 10.6 and latest release version.
> <david.harris...@gmail.com>wrote:

Brian Ketelsen

unread,
Mar 29, 2011, 8:14:41 PM3/29/11
to luisbebop, golang-nuts


On Mar 29, 2011, at 8:04 PM, luisbebop <luis...@gmail.com> wrote:

> Hi Brad.
>
> I've tried your code but i got the error:
>
> "
> 2011/03/29 20:50:36 Accepted 247
> 2011/03/29 20:50:36 Accepted 248
> 2011/03/29 20:50:36 accept error: accept tcp 0.0.0.0:2020: too many
> open files
> "

You need to raise your ulimit which isn't straightforward on a Mac. See
http://joerg.delker.de/blog/?tag=ulimit

Brian


>

Brad Fitzpatrick

unread,
Mar 30, 2011, 12:16:31 AM3/30/11
to Brian Ketelsen, luisbebop, golang-nuts
Yeah, just crank it up to 65k or something.

I thought Debian's old 1024 default was silly.  OS X apparently beats even that!

Johann Höchtl

unread,
Mar 30, 2011, 3:46:07 AM3/30/11
to golang-nuts


On Mar 30, 6:16 am, Brad Fitzpatrick <bradf...@google.com> wrote:
> Yeah, just crank it up to 65k or something.
>
> I thought Debian's old 1024 default was silly.  OS X apparently beats even
> that!
>
Another Bug which was closed recently would have prevented creating
more threads anyway:
http://code.google.com/p/go/source/detail?r=085423df5c7fbb6a7561db8b022f13d3398c2a9c

>
>
> On Tue, Mar 29, 2011 at 5:14 PM, Brian Ketelsen <bketel...@gmail.com> wrote:

Joseph Poirier

unread,
Mar 30, 2011, 4:52:04 AM3/30/11
to Brad Fitzpatrick, Brian Ketelsen, luisbebop, golang-nuts

Windows users should be able to regedit this registry key

outbound concurrent connections for each IP Address
[HKEY_LOCAL_MACHINE \System \CurrentControlSet \Services
\Tcpip\Parameters] MaxUserPort = 5000 (Default = 5000, Max = 65534)

-joe

Aleksandar Radulovic

unread,
Mar 30, 2011, 6:25:59 AM3/30/11
to golan...@googlegroups.com
Hi,

If you're into experimenting, you might want to check out node.js
(http://nodejs.org/) as it uses async event driven model and can
handle massive amounts of connections.

In the Python world, there are many frameworks that can handle such
numbers of concurrent connections: Twisted, Tornado, gevent, etc.
There's even a WSGI server called Gunicorn which is compatible with
most python web frameworks and offers features you need.

Twisted is suitable for much more than just web app server
implementation but it has a bit of a steep learning curve. Tornado
looks pretty impressive and I would definitely give it a shot if I
were you.

In my experiments, I used gunicorn with gevent worker (with nginx in
front of it all) and having recommended number of workers (2 *
num_cores) + 1 and was able to reach thousands of connections on my
moderate test hardware.

There was someone on the list recently who wrote a benchmark for Go
and Python, you might want to check that out as well.

As for me, it would be a close match between Erlang and Go, depending
very much on what kind of server you're trying to implement (if it's
not a http server).

-alex.

--
a lex 13 x
http://www.a13x.info

Brad Fitzpatrick

unread,
Mar 30, 2011, 10:04:28 AM3/30/11
to Johann Höchtl, golang-nuts
On Wed, Mar 30, 2011 at 12:46 AM, Johann Höchtl <johann....@gmail.com> wrote:


On Mar 30, 6:16 am, Brad Fitzpatrick <bradf...@google.com> wrote:
> Yeah, just crank it up to 65k or something.
>
> I thought Debian's old 1024 default was silly.  OS X apparently beats even
> that!
>
Another Bug which was closed recently would have prevented creating
more threads anyway:
http://code.google.com/p/go/source/detail?r=085423df5c7fbb6a7561db8b022f13d3398c2a9c


Well, that's about threads, not goroutines.

A goroutine doesn't get assigned to a thread until it needs to run or do something blocking in the kernel.

The 20,000 connections in my example should all be sitting idle inside an epoll_wait/kevent thingy and only briefly going into the kernel to read what you just typed at it and echo it back.

William Waites

unread,
Mar 30, 2011, 10:19:01 AM3/30/11
to Andrew Gerrand, Fabio Kaminski, Brad Fitzpatrick, golan...@googlegroups.com, david.harris.uk
* [2011-03-29 10:57:23 +1100] Andrew Gerrand <a...@golang.org> �crit:

] IMO this is a myth. Python's dynamic typing causes more problems than


] it solves. Runtime errors suck, and tracking them down is a huge
] productivity drain in my experience. (Not to mention the reliability
] issues in production environments.)

I've just written about this in a little more depth in the
first section of

http://eris.okfn.org/ww/2011/03/gockan

the problem you speak of is compounded, in my experience, by
eventually requiring a bloated test suite to check for what
amount to type errors. And the larger the test suite, the
longer it takes to run and the less productive Python becomes.

Cheers,
-w

--
William Waites <mailto:w...@styx.org>
http://river.styx.org/ww/ <sip:w...@styx.org>
F4B3 39BF E775 CF42 0BAB 3DF0 BE40 A6DF B06F FD45

Reply all
Reply to author
Forward
0 new messages