Sockets 去,tcp打开的文件太多调试

Sockets 去,tcp打开的文件太多调试,sockets,tcp,go,goroutine,Sockets,Tcp,Go,Goroutine,下面是一个简单的Go http(tcp)连接测试脚本 func main() { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { fmt.Fprintln(w, "Hello, client") })) defer ts.Close() var wg sync.WaitGroup for i := 0; i &l

下面是一个简单的Go http(tcp)连接测试脚本

func main() {
    ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintln(w, "Hello, client")
    }))
    defer ts.Close()
    var wg sync.WaitGroup
    for i := 0; i < 2000; i++ {
        wg.Add(1)
        go func(i int) {
            defer wg.Done()
            resp, err := http.Get(ts.URL)
            if err != nil {
                panic(err)
            }
            greeting, err := ioutil.ReadAll(resp.Body)
            resp.Body.Close()
            if err != nil {
                panic(err)
            }
            fmt.Printf("%s", i, greeting)
        }(i)
    }
    wg.Wait()
}
func main(){
ts:=httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter,r*http.Request){
fmt.Fprintln(w,“你好,客户”)
}))
延迟ts关闭()
var wg sync.WaitGroup
对于i:=0;i<2000;i++{
工作组.添加(1)
go func(i int){
推迟工作组完成()
resp,err:=http.Get(ts.URL)
如果错误!=零{
恐慌(错误)
}
问候语,err:=ioutil.ReadAll(resp.Body)
各自主体关闭()
如果错误!=零{
恐慌(错误)
}
fmt.Printf(“%s”,i,问候语)
}(一)
}
wg.Wait()
}
如果我在Ubuntu中运行它,我会得到:

panic:Gethttp://127.0.0.1:33202: 拨打tcp 127.0.0.1:33202:打开的文件太多

其他帖子说要确保
关闭
连接,我在这里就是这么做的。
还有人说要增加与ulimit的最大连接限制,或者尝试使用sudo sysctl-w fs.inotify.max_user_watches=100000,但仍然不起作用

如何在一台服务器上运行数百万个tcp连接goroutine? 只有2000个连接才会崩溃


谢谢,

我认为您需要更改max文件描述符。我以前在一个开发虚拟机上遇到过同样的问题,需要更改文件描述符max,而不是使用inotify设置

FWIW,你的程序在我的虚拟机上运行良好

·> ulimit -n
120000
但我跑完之后

·> ulimit -n 500
·> ulimit -n
500
我得到:

panic: Get http://127.0.0.1:51227: dial tcp 127.0.0.1:51227: socket: too many open files
**不要落入普拉文所设的陷阱**

注意
ulimit
!=<代码>ulimit-n

➜  cmd git:(wip-poop) ✗ ulimit -a
-t: cpu time (seconds)              unlimited
-f: file size (blocks)              unlimited
-d: data seg size (kbytes)          unlimited
-s: stack size (kbytes)             8192
-c: core file size (blocks)         0
-v: address space (kbytes)          unlimited
-l: locked-in-memory size (kbytes)  unlimited
-u: processes                       1418
-n: file descriptors                4864

我还必须手动设置close connection头以避免文件描述符问题:

r, _ := http.NewRequest(http.MethodDelete, url, nil)
r.Close = true
res, err := c.Do(r)
res.Body.Close();

如果没有r.Close=true和res.Body.Close(),我达到了文件描述符的限制。使用这两种方法,我可以根据需要启动任意多个文件。

更改ulimit以避免出现“打开的文件太多”的错误 默认情况下,linux的最大ulimit为4096,mac为1024, 您可以通过键入将ulimit更改为4096 ulimit-N4096 对于beyond 4096,您需要修改linux的etc/security文件夹中的limits.conf,并通过添加此行“*hard core 100000”将硬限制设置为100000

我通过添加req.Close=true和req.Header.Set(“连接”,“关闭”)解决了这个问题。我觉得这比换一个ulimit好


来源:

如果你想运行数百万个go例程来打开/读取/关闭一个套接字,那么你最好升级你的ulimit,或者打开/读取/关闭套接字并将读取的值传递给go例程,但是我会使用一个缓冲通道来控制你想要打开的文件描述符的数量

const (
    // this is where you can specify how many maxFileDescriptors
    // you want to allow open
    maxFileDescriptors = 100
)

func main() {
    ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintln(w, "Hello, client")
    }))
    defer ts.Close()
    var wg sync.WaitGroup
    maxChan := make(chan bool, maxFileDescriptors)
    for i := 0; i < 1000; i++ {
        maxChan <- true
        wg.Add(1)
        go func(url string, i int, maxChan chan bool, wg *sync.WaitGroup) {
            defer wg.Done()
            defer func(maxChan chan bool) { <-maxChan }(maxChan)
            resp, err := http.Get(url)
            if err != nil {
                panic(err)
            }
            greeting, err := ioutil.ReadAll(resp.Body)
            if err != nil {
                panic(err)
            }
            err = resp.Body.Close()
            if err != nil {
                panic(err)
            }
            fmt.Printf("%d: %s", i, string(greeting))
        }(ts.URL, i, maxChan, &wg)
    }
    wg.Wait()
}
const(
//在这里可以指定MaxFileDescriptor的数量
//您想允许打开吗
maxFileDescriptors=100
)
func main(){
ts:=httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter,r*http.Request){
fmt.Fprintln(w,“你好,客户”)
}))
延迟ts关闭()
var wg sync.WaitGroup
maxChan:=make(chan bool,maxFileDescriptor)
对于i:=0;i<1000;i++{

默认情况下,maxChanGo的http包不指定请求超时。您应该始终在服务中包含超时。如果客户端不关闭其会话,该怎么办?您的进程将保持命中ulimit的旧会话的活动状态。一个不好的参与者可能会故意打开数千个会话,从而影响服务器。重载服务应该进行调整乌利米特也是,但后援暂停

确保指定超时:

http.DefaultClient.Timeout = time.Minute * 10
您可以通过监视流程打开的文件来验证之前和之后:

lsof -p [PID_ID]

如果你增加你的ulimit,你最终还是会用完文件描述符。尝试使用缓冲通道,并将打开文件的go例程数量限制在ulimit以下。一次打开1000个文件就足够了……太好了,这正是我所寻求的实用智慧。我相信这有一个好处(非常不可能,但可能)竞态条件错误-您应该
wg.Add(1)
go func(…){…}
之外和之前添加(1)
。否则,如果第一个
n
goroutine在
n+1
第个goroutine开始之前完成(这也是极不可能的),那么
wg.Wait()
命令实际上可能在运行
n+1
th和其余goroutine之前终止。(它们仍然会运行,但下游代码不会等待它。)
lsof -p [PID_ID]