【问题标题】:Too many open files WebsocketWebsocket 打开的文件太多
【发布时间】:2020-10-09 16:06:12
【问题描述】:

进程留下太多打开的文件描述符。 当我这样做时:lsof -p $pid,大部分结果是(大约 80%):

points2 28360 根 911u 袜子 0,9 0t0 42082509 协议:TCPv6

在 FD Type 变为 'sock' 之前,它会保持 CLOSE_WAIT 一段时间。我注意到的是,其中一些“袜子”FD 消失了,有些则永远存在

打开文件的数量逐渐增加,波动很小,直到没有达到最大值1024。目前我将允许的最大打开文件数量设置为4096,以使进程工作更长时间。

srvTLS := &http.Server{
    Addr:         utils.PortSocketTLS,
    ReadTimeout:  10 * time.Second,
    WriteTimeout: 15 * time.Second,
}
srvTLS.SetKeepAlivesEnabled(false)

处理程序:

func WsRoom(w http.ResponseWriter, r *http.Request) {
ws, err := websocket.Upgrade(w, r, nil, 1024, 1024)
if _, ok := err.(websocket.HandshakeError); ok {
    http.Error(w, "Not a websocket handshake", 400)
    return
} else if err != nil {
    return
}
...other stuff
}

作家到conn

func PlayerWriter(pc *model.PlayerConn) {
ticker := time.NewTicker(utils.PingPeriod)
defer func() {
    ticker.Stop()
    pc.WS.Close()
}()
for {
    select {
    case message, ok := <-pc.Ch:
        pc.WS.SetWriteDeadline(time.Now().Add(utils.WriteWait))
        if !ok {
            pc.WS.WriteMessage(websocket.CloseMessage, []byte{})
            return
        }

        err := pc.WS.WriteMessage(websocket.TextMessage, message)
        if err != nil {
            return
        }
        inst := &model.PlayerLeftInstruction{}
        _ = json.Unmarshal(message, inst)

        if inst.Instruction == utils.UtilAFK || inst.Instruction == utils.RoomMoneyLess {
            return
        }
        break
    case <-ticker.C:
        pc.WS.SetWriteDeadline(time.Now().Add(utils.WriteWait))
        if err := pc.WS.WriteMessage(websocket.PingMessage, nil); err != nil {
            return
        }
        break
    }
}}

Conn 监听器:

func PlayerListener(pc *model.PlayerConn) {
defer func() {
    if r := recover(); r != nil {
    }
    close(pc.Ch)
    pc.Room.Leave <- pc
    pc.WS.Close()
}()

pc.WS.SetReadLimit(utils.MaxMessageSize)
pc.WS.SetReadDeadline(time.Now().Add(utils.PongWait))
pc.WS.SetPongHandler(func(string) error { pc.WS.SetReadDeadline(time.Now().Add(utils.PongWait)); return nil })

for {
    _, command, err := pc.WS.ReadMessage()
    if err != nil {
        break
    }
    si := model.StatusInstruction{}
    json.Unmarshal(command, &si)
    z := make([]byte, len(command))
    copy(z, command)
    switch si.Status {
    case utils.PlayerLeft:
        goto Exit
    case utils.MoveTurn, utils.LocalTurn, utils.LocalBetFold, utils.LocalBet, utils.MoveTurnBet:
        pc.Room.RoomData.GameBridger.InstCh <- z
        break
    ...some stuff
    default:
        log.Printf("Unexpected command is responsed it is: %s", string(command))
        goto Exit
    }
}
Exit:
}

如果需要,我可以分享更多代码。我认为超时问题和一些与此有关的问题,但我不完全知道我在哪里失踪

【问题讨论】:

  • 你使用的是什么 websocket 库?
  • 应用程序对每个连接的客户端使用一个文件描述符。你有那么多连接的客户吗?如果不是,则应用程序正在泄漏连接。在两次调用pc.WS.Close() 之前添加日志语句,以确认应用程序正在关闭连接。应用程序可能没有关闭连接,因为 goroutine 被阻塞了。另外,运行race detector 来检查数据竞争。
  • @DeanElbaz Websocket 这个库:github.com/gorilla/websocket

标签: go websocket


【解决方案1】:

在 lsof 中,TYPE 'sock' 通常意味着:没有收到任何内容的套接字连接。 由于在某些情况下未关闭已建立的 websocket 连接,我的代码中出现了逻辑错误。 我也有 goroutine 泄漏(但它不影响 lsof 数量),pprof 帮助检测泄漏。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-05-09
    • 2011-07-18
    • 2019-10-30
    • 2011-01-03
    • 2011-08-05
    • 2014-03-31
    • 2017-03-03
    相关资源
    最近更新 更多