在Golang中使用WebSocket服务器时出现了”too many open files”错误。

huangapple go评论88阅读模式
英文:

too many open files error with websocket server in golang

问题

我实际上是在使用gorilla包将我的WebSocket服务器放在Golang中。
如果我让服务器保持开启状态,大约每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

这个错误相当难以理解,我不明白,因为我在中断或错误的情况下正确关闭了套接字,并且服务器正在生产中,但在测试阶段只有4-5个用户关闭,所以不是因为限制问题。

有人能告诉我这个错误是从哪里来的吗?

英文:

I'm actually using gorilla package to put my websocket server in golang.
If I leave my server on, I have this error every 10 days or so.

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

this is my code :

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

    if user.GetUserByToken() == false {

        errors := api.Error{}
        socket.Close()
        errors.ListErrors = append(errors.ListErrors, &quot;Session doesn&#39;t exist&quot;)
	    writer.Header().Set(&quot;Content-Type&quot;, &quot;application/json&quot;)
	    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 := &lt;- err
        if len(tmp) &gt; 0 {
            break
        }
    }
   socket.Close()
}

my ulimit configuration :

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

The error is rather incomprehensible, I don't understand, because I close the socket well in case of break or error and server is in production but in beta close with 4-5 users, so it's not about limit.

Can someone tell me where the error comes from?

答案1

得分: 4

如果你已经关闭了所有的body reader并排除了其他可能的原因,如果你的流量很大,可能是ulimit的问题。但通常情况下,即使你不是root用户,你也可以增加ulimit的值,因为有两种类型的限制,硬限制即最大值和软限制。你可以在Linux中使用以下命令来检查它们:

# ulimit -Sn

# ulimit -Hn

如果软限制(Sn)低于硬限制(Hn)(默认或由管理员设置),你可以将其增加到硬限制。在我所有的CentOS安装中,我可以看到软限制(Sn)的默认值是1024,硬限制(Hn)的默认值是4096,所以你可以轻松将软限制(Sn)增加到4096,不需要root用户的参与。

如果可能的话,这个函数将最大化打开文件的数量。复制/粘贴并在main函数的开头调用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进程的限制。

英文:

If you have closed all body readeres and covered all other possible reasons, it might be the ulimit problem if you have hight traffic. But usually you can increase that even if you are not the root users since there are two types of limits, hard limit ie. the max, and soft limit. You can check both of them in Linux using:

# ulimit -Sn

# ulimit -Hn

If soft limit (Sn) is lower than hard limit (Hn) (default or set by the admin) you can make it higher up to the hard limit. On all my CentOS installs, as I can see the default is 1024 for Sn and 4096 for Hn, so you can easily max out Sn to 4096, no root user involved.

This function will max out the number of open files if it is possible. Copy/paste and call the maxOpenFile() at the begining of main func and see does it help.

import &quot;syscall&quot;

func maxOpenFiles() {
	var rLimit syscall.Rlimit

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

    if rLimit.Cur &lt; rLimit.Max {
	    rLimit.Cur = rLimit.Max
	    err = syscall.Setrlimit(syscall.RLIMIT_NOFILE, &amp;rLimit)
	    if err != nil {
		    log.Println(&quot;Error Setting Rlimit &quot;, err)
	    }
    }
}

Code is simple, first we read current settings for number of files and if Cur is less than Max, we max it out. This func will set the file limits only to the current app/linux process.

huangapple
  • 本文由 发表于 2016年11月29日 02:53:29
  • 转载请务必保留本文链接:https://go.coder-hub.com/40851437.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定