golang を使用して mysql に接続する場合、接続リソースを節約するために、接続が使用された後、指定された期間使用されなくなった後に接続が自動的に閉じられることが望まれます。
このとき、SetConnMaxLifetime()
最大接続有効時間の設定や、最大アイドル接続時間の設定
によく使用されます。SetConnMaxIdleTime()
これら 2 つの関数の機能は似ており、理論的には同じ効果を実現できます。
しかし、実際に使ってみると、ちょっと予想外のことが起こります。
まずテスト コードを見てみましょう。次のコードでは、
最大アイドル時間を受信パラメータ値として設定し、
最大ライフタイムを受信パラメータ値として設定し、
最大オープン接続を 1 に設定し、
最大アイドル接続を 1 に設定します。
package main
import (
"database/sql"
"log"
"fmt"
"os"
"strconv"
"time"
_ "github.com/go-sql-driver/mysql"
)
var dataBase = "root:xxxx@tcp(127.0.0.1:3306)/mysql?timeout=2s&readTimeout=6s&interpolateParams=true"
func getVar(name string) int {
val := os.Getenv(name)
if len(val) == 0 {
panic(fmt.Sprintf("error getting: %v", name))
}
v, err := strconv.Atoi(val)
if err != nil {
panic(fmt.Sprintf("error parsing %v %v", name, err))
}
return v
}
func main() {
db, err :=sql.Open("mysql", dataBase) // connect to the db of your choice.
if err != nil {
panic(err)
}
defer db.Close()
db.SetConnMaxIdleTime(time.Second * time.Duration(getVar("MAXIDLE")))
db.SetConnMaxLifetime(time.Second * time.Duration(getVar("MAXLIFE")))
db.SetMaxIdleConns(1)
db.SetMaxOpenConns(1)
sleep := time.Second*time.Duration(getVar("SLEEP"))
for i := 0; i < 10; i++ {
err = db.Ping()
if err != nil {
log.Fatalln("ping db fail:", err)
}
time.Sleep(sleep)
print("\r", i)
}
fmt.Printf("\n%+v\n", db.Stats())
}
テスト1
MAXIDLE=1 MAXLIFE=0 SLEEP=5 go run .
最大アイドル時間を 1 秒に設定し、最大ライフタイムを 0 秒に設定します。これは期限切れにならないことを意味し、ライフタイムを設定しないことと同じです。
接続するたびに 5 秒間スリープします。
期待される結果: 10 回ループし、そのたびに新しい接続が開かれ、アイドル時間の満了により古い接続が自動的に閉じられます。
1.15.15に行く
出力
9
{MaxOpenConnections:1 OpenConnections:1 InUse:0 Idle:1 WaitCount:0 WaitDuration:0s MaxIdleClosed:0 MaxIdleTimeClosed:0 MaxLifetimeClosed:0}
実際の結果は、新しい接続が 1 つだけ作成され、接続は閉じられずに使用されています。
つまり、最大アイドル時間の設定は有効になりません。
1.17.12に行く
9
{MaxOpenConnections:1 OpenConnections:0 InUse:0 Idle:0 WaitCount:0 WaitDuration:0s MaxIdleClosed:0 MaxIdleTimeClosed:10 MaxLifetimeClosed:0}
実際の結果は期待と一致しました。
テスト2
MAXIDLE=1 MAXLIFE=2 SLEEP=5 go run .
最大アイドル時間を 1 秒、最大ライフタイムを 2 秒に設定します。つまり、アイドル時間が最初に期限切れになり、
各接続後に 5 秒スリープします。
予想される結果は、10 回ループした後、そのたびに新しい接続が開かれ、アイドル時間の満了により古い接続が自動的に閉じられることです。
1.15.15に行く
出力
9
{MaxOpenConnections:1 OpenConnections:0 InUse:0 Idle:0 WaitCount:0 WaitDuration:0s MaxIdleClosed:0 MaxIdleTimeClosed:10 MaxLifetimeClosed:0}
実際の結果は期待と一致しました。
1.17.12に行く
出力
9
{MaxOpenConnections:1 OpenConnections:0 InUse:0 Idle:0 WaitCount:0 WaitDuration:0s MaxIdleClosed:0 MaxIdleTimeClosed:10 MaxLifetimeClosed:0}
実際の結果は期待と一致しました。
上記のテスト結果をまとめると、次の表のようになります。
行くバージョン | 最大アイドル時間かどうか | 最大寿命かどうか | アイドル接続のリサイクルは効果的ですか? |
---|---|---|---|
1.15.15に行く | Y | N | N |
1.15.15に行く | Y | Y | Y |
1.17.12に行く | Y | N | Y |
1.17.12に行く | Y | Y | Y |
go バージョン 1.15.15 または他の同様のバージョンでは、最大アイドル時間のみが設定され、アイドル接続を自動的にリサイクルすることはできません。
具体的な理由については、問題を確認するか、go のソース コードを具体的に確認してください。これはバグであるはずです。
参考
データベース/SQL: SetConnMaxLifetime を使用しない SetConnMaxIdleTime は効果がありません #41114