Слишком много открытых файлов Websocket - PullRequest
3 голосов
/ 19 июня 2020

Процесс оставляет слишком много открытых файловых дескрипторов. Когда я делаю: lsof -p $ pid, большинство результатов (около 80%):

points2 28360 root 911u sock 0,9 0t0 42082509 протокол: TCPv6

Перед тем, как FD Type изменится на «sock», он некоторое время остается как CLOSE_WAIT. Я заметил, что некоторые из этих «носков» FD исчезают, некоторые остаются навсегда. 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
}

Writer to 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 Listener:

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:
}

Если нужно, я могу поделитесь большим количеством кода. Я думаю, проблема с таймаутами и что-то относилось к этому, но я точно не знаю, где мне не хватает

1 Ответ

0 голосов
/ 25 июня 2020

В lsof ТИП 'sock' обычно означает: соединение сокета, которое ничего не получило. У меня была логическая ошибка в моем коде, я НЕ закрыл в некоторых случаях установленное соединение с веб-сокетом. Также у меня были утечки горутины (однако это не повлияло на номер lsof), pprof помог обнаружить утечки.

...