golang http连接池失效的几种情况及具体原因分析
2018-03-24 01:40
381 查看
开发十年,就只剩下这套Java开发体系了 >>>
首先,连接池失效,问题产生背景是高频agent,agent 会发起大量的http 请求,但是,本想net/http 是支持长连接的,但是,几种情况,都产生了大量的time_wait,这里予以总结。
该文章后续仍在不断的更新修改中, 请移步到原文地址http://dmwan.cc
第一种情况是误用transport ,为了设置代理,为每个请求,都new 了一个transport 。
client := &http.Client{ CheckRedirect: redirectPolicyFunc, Timeout: time.Duration(10)*time.Second,//设置超时 } client.Transport = &http.Transport{ Proxy: http.ProxyURL(proxyUrl), } //设置代理ip
失效的原因,是client 是线程安全的,golang连接池的维度是transport, 在transport 里面维护了两个map,暂存连接。
第二种情况是没设置 MaxIdleConnsPerHost, 和连接的timeout, 一旦高频的连接超过MaxIdleConnsPerHost 的数目,同时超过超时,连接就会释放。正确的设置是实例化transport 的时候,评估好 connsPerHost, 如下:
var DefaultTransport RoundTripper = &Transport{ ... MaxIdleConnsPerHost: 1000, IdleConnTimeout: 90 * time.Second, ... }
第三种情况是resp.body 忘了读取,直接导致新请求会直接新建连接。其实可以理解,没read body 的socket, 如果直接复用,会产生什么样后果?所有使用这个套接字的连接都会错乱。 示例如下,
package main import ( "fmt" "html" "log" "net" "net/http" "time" ) func startWebserver() { http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.Path)) }) go http.ListenAndServe(":8080", nil) } func startLoadTest() { count := 0 for { resp, err := http.Get("http://localhost:8080/") if err != nil { panic(fmt.Sprintf("Got error: %v", err)) } resp.Body.Close() log.Printf("Finished GET request #%v", count) count += 1 } } func main() { // start a webserver in a goroutine startWebserver() startLoadTest() }
这里可以使用ss -s 查看连接数,如果不关心返回body ,可以直接丢弃
io.Copy(ioutil.Discard, resp.Body) //Discard 是一个 io.Writer,对它进行的任何 Write 调用都将无条件成功
阅读更多
相关文章推荐
- [置顶] Mysql索引会失效的几种情况分析
- Mysql索引会失效的几种情况分析
- Mysql索引会失效的几种情况分析
- Mysql索引会失效的几种情况分析(转)
- Mysql索引会失效的几种情况分析
- Mysql索引会失效的几种情况分析
- Mysql索引会失效的几种情况分析
- Mysql索引会失效的几种情况分析
- Mysql索引会失效的几种情况分析
- Mysql索引会失效的几种情况分析
- Mysql索引会失效的几种情况分析
- Win8.1系统Hosts文件失效的具体原因分析
- Mysql索引会失效的几种情况分析
- Mysql索引会失效的几种情况分析
- 在使用 ADO.NET Entity Framework 时生成的实体类个数少于数据表个数的几种情况及原因分析
- Mysql索引会失效的几种情况分析
- Mysql索引会失效的几种情况分析
- Mysql索引会失效的几种情况分析
- Mysql索引会失效的几种情况分析
- SpringMVC控制器设值原理分析(ModelAndView的值通过HttpServletRequest直接取到的原因)