SQL продолжает открывать сокет, что приводит к ошибке слишком большого количества открытых файлов. Есть ли лучший способ обработки SQL-соединений в GO?

# #go #go-echo

Вопрос:

У меня есть API в GO, использующий echo и SQL Server в качестве базы данных.

Я использую db.Ping() в начале каждой конечной точки, чтобы проверить, подключена ли бд по-прежнему или нет, это продолжает открывать новые подключения к бд с новыми сокетами, что в конечном итоге приводит к ошибке открытия слишком большого количества файлов.

db.Stats() возвращает это {"MaxOpenConnections":0,"OpenConnections":413,"InUse":413,"Idle":0,"WaitCount":0,"WaitDuration":0,"MaxIdleClosed":2,"MaxIdleTimeClosed":62,"MaxLifetimeClosed":0}

Количество открытых соединений продолжает увеличиваться, даже несмотря на то, что количество активных запросов намного меньше этого.

Вот пример фрагмента:

 package main

import (
    "database/sql"

    "github.com/labstack/echo/v4"

    _ "github.com/denisenkom/go-mssqldb"
)

var db *sql.DB

func main () {
    db, err = sql.Open("sqlserver", "sqlserver://username:passwrod@[server]?database=[db]amp;connection timeout=1000")
    if err != nil {
        log.Fatal(err)
    }
    db.SetConnMaxLifetime(10 * time.Minute)
    db.SetConnMaxIdleTime(15 * time.Second)
    e := echo.New()
    e.GET("/", func(c echo.Context) error {
        err := db.Ping()
        if err != nil {
            return echo.NewHTTPError(500, err)
        }
        var name string
        err = db.QueryRow("select top 1 name from Test_Table;").Scan(amp;name)
        if err != nil {
            return echo.NewHTTPError(500, err)
        }
        return c.HTML(http.StatusOK, name)
    })
    e.Logger.Fatal(e.Start(":4000"))
}
 

Комментарии:

1. Это все ваше приложение? Если это так, то с кодом проблем нет. Возможно, проблема с водителем. Но если это не все ваше приложение и есть другие места, где db оно используется, то у нас нет возможности точно узнать, что не так. Однако распространенной проблемой является отсутствие закрытия *sql.Rows или других ресурсов, связанных с БД.

2. Это может произойти, если вы не закрываете ресурсы dl (в основном *sql.Rows, как упоминалось @mkopriva). Это также может произойти, если серверу БД требуется слишком много времени для отправки ответа, а клиент ожидает этих ответов. Если вы хотите, вы можете использовать db.SetMaxOpenConnections (), чтобы ограничить количество сокетов для сервера бд.

3. @mkopriva Должен ли я позвонить defer rows.Close() после Query() , чтобы закрыть его, или мне следует закрыть его после того, как я просмотрю все необходимые строки?

4. После того, как вы вызовете запрос и подтвердите, что значение ошибки равно нулю.