Go服务器中并发(同时)HTTP连接的理论最大数量是多少?

时间:2011-12-27 14:40:28

标签: http concurrency go

Go中实现的非常简单的服务器可以处理的并发HTTP连接数的上限是多少?

1 个答案:

答案 0 :(得分:12)

并发HTTP连接数受可用内存和操作系统限制的限制。

在Linux中,可以使用ulimit打印和更改软操作系统限制(例如最大打开文件数)。

就内存而言,在32位Linux上运行的最小Go HTTP服务器中的每个HTTP连接消耗 21 KiB 内存(此服务器的源代码,可与Go版本2013-03一起使用) -23,在下面)。在64位Linux上,内存消耗可能会更高。

在服务器可用1GB内存的32位系统上,21 KiB意味着可以同时进行 50,000 连接。这 not 包含Linux内核消耗的内存。

package main

import (
    "flag"
    "fmt"
    "net/http"
    "os"
    "runtime"
    "sync"
)

var isClient = flag.Bool("client", false, "Whether to start the HTTP server or the HTTP client")
var N = flag.Int("n", 1000, "Number of concurrent HTTP requests")

var wait = make(chan byte)
var counter = 0
var reachedN = make(chan byte)

func handler(w http.ResponseWriter, req *http.Request) {
    fmt.Fprintf(w, "some text")
    counter++
    if counter == *N {
        reachedN <- 0
    }
    <-wait // Block this goroutine
}

func main() {
    flag.Parse()
    if *N <= 0 {
        fmt.Fprintf(os.Stderr, "invalid number of goroutines")
        os.Exit(1)
    }

    if *isClient {
        // Initiate N http connections
        var wg sync.WaitGroup
        for i := 0; i < *N; i++ {
            wg.Add(1)
            go func(ii int) {
                _, err := http.Get("http://127.0.0.1:12345")
                if err != nil {
                    fmt.Fprintf(os.Stderr, "client %d: %s\n", ii, err)
                    os.Exit(1)
                }
                wg.Done()
            }(i)
        }
        wg.Wait()
    } else {
        runtime.GOMAXPROCS(1) // No concurrency

        // Read MemStats
        var m0 runtime.MemStats
        runtime.ReadMemStats(&m0)

        go func() {
            <-reachedN // Wait until there are *N concurrent requests

            // Read MemStats
            var m1 runtime.MemStats
            runtime.ReadMemStats(&m1)

            fmt.Printf("Number of HTTP connections:        %d\n", *N)
            fmt.Printf("Memory consumption per connection: %.2f bytes\n", float64(m1.Sys-m0.Sys)/float64(*N))
            os.Exit(1)
        }()

        http.HandleFunc("/", handler)
        err := http.ListenAndServe(":12345", nil)
        if err != nil {
        fmt.Fprintf(os.Stderr, "server: %s\n", err)
            os.Exit(1)
        }
    }
}