我有一个Go程序,可以从多个goroutine生成很多HTTP请求。运行一段时间后,程序将显示错误消息:connect:无法分配请求的地址。
与进行检查时netstat,发现中有大量连接(28229)TIME_WAIT。
netstat
TIME_WAIT
TIME_WAIT当goroutine的数量为3时,会发生大量套接字,当套接字数量为5时,严重程度足以导致崩溃。
我在docker下运行Ubuntu 14.4并运行1.7版
这是Go程序。
package main import ( "io/ioutil" "log" "net/http" "sync" ) var wg sync.WaitGroup var url="http://172.17.0.9:3000/"; const num_coroutines=5; const num_request_per_coroutine=100000 func get_page(){ response, err := http.Get(url) if err != nil { log.Fatal(err) } else { defer response.Body.Close() _, err =ioutil.ReadAll(response.Body) if err != nil { log.Fatal(err) } } } func get_pages(){ defer wg.Done() for i := 0; i < num_request_per_coroutine; i++{ get_page(); } } func main() { for i:=0;i<num_coroutines;i++{ wg.Add(1) go get_pages() } wg.Wait() }
这是服务器程序:
package main import ( "fmt" "net/http" "log" ) var count int; func sayhelloName(w http.ResponseWriter, r *http.Request) { count++; fmt.Fprintf(w,"Hello World, count is %d",count) // send data to client side } func main() { http.HandleFunc("/", sayhelloName) // set router err := http.ListenAndServe(":3000", nil) // set listen port if err != nil { log.Fatal("ListenAndServe: ", err) } }
默认的http.Transport打开和关闭连接的速度过快。由于所有连接都连接到相同的host:port组合,因此您需要增加MaxIdleConnsPerHost以匹配的值num_coroutines。否则,运输工具将频繁关闭额外的连接,只是立即将它们重新打开。
MaxIdleConnsPerHost
num_coroutines
您可以在默认传输方式上进行全局设置:
http.DefaultTransport.(*http.Transport).MaxIdleConnsPerHost = numCoroutines
或者在创建自己的交通工具时
t := &http.Transport{ Proxy: http.ProxyFromEnvironment, DialContext: (&net.Dialer{ Timeout: 30 * time.Second, KeepAlive: 30 * time.Second, }).DialContext, MaxIdleConnsPerHost: numCoroutines, MaxIdleConns: 100, IdleConnTimeout: 90 * time.Second, TLSHandshakeTimeout: 10 * time.Second, ExpectContinueTimeout: 1 * time.Second, }