频繁发起HTTP请求会报『read: connection reset by peer』

1,681 views
Skip to first unread message

御弟

unread,
Dec 7, 2015, 2:26:26 AM12/7/15
to golang...@googlegroups.com
在用http库模拟大量请求时,发现起的goroutine一多,就会报类似:Get http://127.0.0.1:63245: read tcp 127.0.0.1:63280->127.0.0.1:63245: read: connection reset by peer这样的错;

开始猜测会不会是系统设置影响,但用wrk测试,设置上千的connection,妥妥的没有失败的;

精简一下我的模拟场景是这样的:
import (
"flag"
"fmt"
"io"
"io/ioutil"
"net/http"
"net/http/httptest"
"time"
)

var (
Requests    int
Connections int
)

func init() {
flag.IntVar(&Connections, "connections", 100, "设置连接数")
flag.IntVar(&Requests, "requests", 100, "每个连接发送请求数")
}

func main() {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Hello, client")
}))
defer ts.Close()

flag.Parse()
fmt.Printf("%d connections and per %d requests\n", Connections, Requests)

result := make(chan time.Duration, Connections)
client := &http.Client{}
for i := 0; i < Connections; i++ {
go func() {
start := time.Now()

for j := 0; j < Requests; j++ {
resp, err := client.Get(ts.URL)
if err != nil {
fmt.Println("err:", err)
continue
}
io.Copy(ioutil.Discard, resp.Body)
resp.Body.Close()
}

result <- time.Since(start)
}()
}

var total int64
for i := 0; i < Connections; i++ {
total += int64(<-result)
}
latency := time.Duration(total / int64(Connections) / int64(Requests))
fmt.Printf("Latency: %s\n", latency)
}

系统OSX 10.11.1;golang 1.5.1;i7 2.2GHz  16G内存

我设置100个connection没有问题,超过200就会有reset by peer了

是我client没有用对吗?还是别的什么问题?求助。

多谢!


--
Yudi(ZhangXinyu)
From:Suzhou, China
Email:smartzxy AT gmail DOT com
QQ: зlббqßοбб

王志刚

unread,
Dec 7, 2015, 3:53:08 AM12/7/15
to golang...@googlegroups.com
猜测是对方的服务器限制了最大的并发连接数。
wrk也用在底层用连接池,复用了TCP连接,所以没有出问题。

要确定这个问题,你可以试试写个测试程序,单纯的和你的服务器做TCP连接。看看到多少个连接会出现reset by peer.

--
--
官网: http://golang-china.org/
IRC: irc.freenode.net #golang-china
@golangchina
---
您收到此邮件是因为您订阅了Google网上论坛上的“Golang-China”群组。
要退订此群组并停止接收此群组的电子邮件,请发送电子邮件到golang-china...@googlegroups.com
要在网络上查看此讨论,请访问https://groups.google.com/d/msgid/golang-china/CAFGOC9ZUqbXk8piiAZpy0fnOxNZ1LxhChqqU8SeDoSWHsR5trg%40mail.gmail.com
要查看更多选项,请访问https://groups.google.com/d/optout



--
--
         Thanks!
王志刚

御弟

unread,
Dec 7, 2015, 5:25:47 AM12/7/15
to golang...@googlegroups.com
服务应该没有限制,因为就是我自己写的(基于golang的echo框架),同样部署在本机上;

我贴的示例程序在我的环境下就可以重现这个问题,另外我这么用http.Client理论上就应该复用了TCP连接的;

我试过慢慢提高goroutine数和总请求数,服务端的成功响应数会增多;保持goroutine数和总请求数不变,成功响应也并不是每次都一样;

我待会去找台阿里云的linux虚机试试,不知道有没有这样的问题。

Larry Li

unread,
Dec 7, 2015, 7:06:57 AM12/7/15
to golang...@googlegroups.com
大并发测试,客户端和服务端都要先设置 ulimit 才行。
OS X 尤其坑,默认才 256,Linux 下好歹还有 1024。

import "syscall"
func setRlimitNOFile(nofile uint64) error {
	if nofile == 0 {
		return nil
	}
	var lim syscall.Rlimit
	if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &lim); err != nil {
		return err
	}
	if nofile <= lim.Cur {
		return nil
	}
	lim.Cur = nofile
	lim.Max = nofile
	return syscall.Setrlimit(syscall.RLIMIT_NOFILE, &lim)
}

御弟

unread,
Dec 7, 2015, 7:58:55 AM12/7/15
to golang...@googlegroups.com
感觉不是这个问题吧,我已经手动把两端都调到10000了,再大好像系统不让了。我发起的总连接数远没到10000,而且还复用了连接,何况也没有报too many open files;

御弟

unread,
Dec 7, 2015, 8:18:06 AM12/7/15
to golang...@googlegroups.com
刚通过boot2docker跑了个golang的镜像测试,虚机默认ulimit -n是1048576,就可以挺好几千的连接,看来真是系统的问题。多谢@Larry Li

对于golang程序,有什么方法可以大致计算发起某一体量的请求,或者接受某一体量的访问,需要怎样的系统设置吗?

Larry Li

unread,
Dec 7, 2015, 8:18:28 AM12/7/15
to golang...@googlegroups.com

Larry Li

unread,
Dec 7, 2015, 8:21:57 AM12/7/15
to golang...@googlegroups.com
你的代码里面可能没有正确释放 conn,导致连接数过多(超过你预期的最大连接数设置)。
建议 defer log 看看。

Reply all
Reply to author
Forward
0 new messages