Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is my webserver in golang not handling concurrent requests?

Tags:

go

This simple HTTP server contains a call to time.Sleep() that makes each request take five seconds. When I try quickly loading multiple tabs in a browser, it is obvious that each request is queued and handled sequentially. How can I make it handle concurrent requests?

package main

import (
   "fmt"
   "net/http"
   "time"
)

func serve(w http.ResponseWriter, r *http.Request) {
   fmt.Fprintln(w, "Hello, world.")
   time.Sleep(5 * time.Second)
}

func main() {
   http.HandleFunc("/", serve)
   http.ListenAndServe(":1234", nil) 
}

Actually, I just found the answer to this after writing the question, and it is very subtle. I am posting it anyway, because I couldn't find the answer on Google. Can you see what I am doing wrong?

like image 874
Steve Hanov Avatar asked May 23 '12 13:05

Steve Hanov


People also ask

How many concurrent requests can a web server handle Golang?

With a single CPU core, a web server can handle around 250 concurrent requests at one time, so with 2 CPU cores, your server can handle 500 visitors at the same time.

How many requests can a go server handle?

Hello, After some research, and benchmarks (here) , it seemed to me that Go would be the best solution for implementing our server, being able to handle a large amount of requests per second before requiring scaling solutions (be it horizontal or vertical).

Is Go http concurrent?

Go's built-in net/http package is convenient, solid and performant, making it easy to write production-grade web servers. To be performant, net/http automatically employs concurrency; while this is great for high loads, it can also lead to some gotchas.


2 Answers

Your program already handles the requests concurrently. You can test it with ab, a benchmark tool which is shipped with Apache 2:

ab -c 500 -n 500 http://localhost:1234/

On my system, the benchmark takes a total of 5043ms to serve all 500 concurrent requests. It's just your browser which limits the number of connections per website.

Benchmarking Go programs isn't that easy by the way, because you need to make sure that your benchmark tool isn't the bottleneck and that it is also able to handle that many concurrent connections. Therefore, it's a good idea to use a couple of dedicated computers to generate load.

like image 138
tux21b Avatar answered Oct 18 '22 11:10

tux21b


From Server.go , the go routine is spawned in the Serve function when a connection is accepted. Below is the snippet, :-

// Serve accepts incoming connections on the Listener l, creating a 
// new service goroutine for each.  The service goroutines read requests and
// then call srv.Handler to reply to them.
func (srv *Server) Serve(l net.Listener) error {
        for {
            rw, e := l.Accept()
               if e != nil {
......
            c, err := srv.newConn(rw)
            if err != nil {
                continue
            }
            c.setState(c.rwc, StateNew) // before Serve can return
            go c.serve()
        }
}
like image 44
factotum Avatar answered Oct 18 '22 10:10

factotum