使用Golang编写的WebSocket服务器出现“too many open files”错误

4

我实际上使用Gorilla软件包将我的Golang Websocket服务器放置在其中。如果我让服务器保持运行状态,大约每10天就会出现此错误。

2016/11/28 19:22:49 http: Accept error: accept tcp [::]:9001: accept4: too many open files; retrying in 1s
2016/11/28 19:22:50 http: Accept error: accept tcp [::]:9001: accept4: too many open files; retrying in 1s
2016/11/28 19:22:51 http: Accept error: accept tcp [::]:9001: accept4: too many open files; retrying in 1s
2016/11/28 19:22:52 http: Accept error: accept tcp [::]:9001: accept4: too many open files; retrying in 1s
2016/11/28 19:22:53 http: Accept error: accept tcp [::]:9001: accept4: too many open files; retrying in 1s
2016/11/28 19:22:54 http: Accept error: accept tcp [::]:9001: accept4: too many open files; retrying in 1s

这是我的代码:

func websocketHandler(writer http.ResponseWriter, request *http.Request){
    var socket *websocket.Conn
    user := new(user.User)
    user.Token = getParamURI(request.URL.RequestURI(), "token")

    if user.GetUserByToken() == false {

        errors := api.Error{}
        socket.Close()
        errors.ListErrors = append(errors.ListErrors, "Session doesn't exist")
        writer.Header().Set("Content-Type", "application/json")
        writer.WriteHeader(http.StatusNotAcceptable)
        json.NewEncoder(writer).Encode(errors)
        return

    }

    socket, _ = upgrader.Upgrade(writer, request, nil)

    err := make(chan string)

    go pingSocket(socket, err)
    go handleChangeNotification(socket, user.Id, err)
    go handleChangeMessage(socket, user.Id, err)
    for {
       tmp := <- err
        if len(tmp) > 0 {
            break
        }
    }
   socket.Close()
}

我的ulimit配置:

core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 7902
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 7902
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

错误非常难以理解,我不明白,因为我在出现中断或错误的情况下正确关闭了套接字,并且服务器处于生产环境,但是在 beta 版本关闭时只有 4-5 个用户,所以这与限制无关。能有人告诉我错误来自哪里吗?

你确定 websocketHandler 在所有情况下都会返回吗?你的程序打开了哪些文件描述符?堆栈跟踪显示程序正在如何处理文件描述符? - JimB
展示从套接字读取数据的代码和发送到错误通道的代码。 - Charlie Tumahai
2
运行 netstat 命令以查看打开的网络连接,以确定问题是否出在其他地方(例如打开但未关闭数据库连接)。 - Charlie Tumahai
1个回答

4
如果您已经关闭了所有的body readeres并覆盖了所有其他可能的原因,但如果您的流量很高,则可能是ulimit问题。但通常情况下,即使您不是root用户,也可以增加它,因为有两种类型的限制,硬限制即最大值和软限制。您可以在Linux中使用以下命令检查它们:
# ulimit -Sn
# ulimit -Hn
如果软限制(Sn)低于硬限制(Hn)(默认或由管理员设置),则可以将其提高到硬限制。在我所有的CentOS安装中,我可以看到默认值为Sn 1024和Hn 4096,因此您可以轻松地将Sn最大化到4096,无需root用户参与。
如果可能,此函数将最大化打开文件的数量。复制/粘贴并在主函数开始处调用maxOpenFile(),看看是否有帮助。
import "syscall"

func maxOpenFiles() {
    var rLimit syscall.Rlimit

    err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rLimit)
    if err != nil {
        log.Println("Error Getting Rlimit ", err)
    }

    if rLimit.Cur < rLimit.Max {
        rLimit.Cur = rLimit.Max
        err = syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rLimit)
        if err != nil {
            log.Println("Error Setting Rlimit ", err)
        }
    }
}

代码很简单,首先我们读取当前文件数的设置,如果当前值小于最大值,就将其设置为最大值。这个函数只会将文件限制设置到当前应用程序/ Linux 进程中。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接