Go, tcp too many open files debug

新手上路,请多包涵

这是一个简单的 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()
}

如果我在 Ubuntu 中运行它,我会得到:

panic: Get http://127.0.0.1:33202: dial tcp 127.0.0.1:33202: too many open files

其他帖子说要确保 Close 连接,我在这里都这样做了。和其他人说增加最大连接的限制 ulimit 或尝试 sudo sysctl -w fs.inotify.max_user_watches=100000 但仍然不起作用。

如何在单个服务器中运行数百万个 tcp 连接 goroutine?它仅在 2,000 个连接时崩溃。

谢谢,

原文由 user4211028 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 563
2 个回答

我认为您需要更改最大文件描述符。我之前在我的一个开发虚拟机上遇到过同样的问题,需要更改文件描述符最大值,而不是任何带有 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

\*\* 不要掉进 Praveen 做的陷阱 **

注意 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

原文由 sberry 发布,翻译遵循 CC BY-SA 4.0 许可协议

Go 的 http 包默认不指定请求超时。您应该始终在服务中包含超时。如果客户没有关闭他们的会话怎么办?您的进程将使达到 ulimits 的旧会话保持活动状态。坏人可能会故意打开数以千计的会话,对您的服务器进行 DOS 攻击。重载服务也应该调整 ulimits,但要调整 backstop 超时。

确保指定超时:

 http.DefaultClient.Timeout = time.Minute * 10

您可以通过监控进程打开的文件来验证之前和之后:

 lsof -p [PID_ID]

原文由 PodTech.io 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题