golang mysql unexpected EOF(invalid connection)
1.質問
調べたところ、無効な接続の使用によるものです.
基本シーンは次のとおりです.クライアントはMySQLに接続し、SQLを実行した後、すぐに接続を閉じません.クライアントは接続プールに接続を保持します. その後、MySQLサービスが再起動されたり、最大時間(wait_timeoutで定義され、一般的には8時間)以上接続されたりして、MySQLサービス側は接続を閉じました. 次回クライアントでSQLを実行し、接続プールから無効な接続を取得すると、上記のエラーが報告されます.
問題の検証
検証コードの操作手順は次のとおりです.まず、SQLを実行します. 続いて、sleep 60 s. その間、MySQLサービスを再起動します. プログラムsleep後、再度SQLを実行します.
コードは次のとおりです.
プログラム出力を見てください.
テストの結果、MySQLサービスが再起動されると、元の接続が無効になり、再使用されるとエラーが表示されます.
go-sql-driver/mysqlここでの実装では、問題の接続を接続プールから削除したり、接続エラーを報告したりして自動的に再接続することはありません.
2.ソリューション
シナリオ1アップグレードmysql driver
テスト結果は次のように出力されます.
つまり、無効な接続が発生すると自動的に再接続されます.
関連するバグfixレコード、Bugfixesを参照:
シナリオ2接続多重時間の設定
接続の多重化時間は、接続がどのくらい使用されるかを示し、自動的に閉じます.
接続が使用中の場合、接続の多重化時間を超えてもすぐに閉じるのではなく、接続が使用されなくなってから閉じることに注意してください.
たとえば、接続多重化時間を60 sに設定します.
どのくらいの時間を設定するかは、自分のシーンの必要に応じて設定する必要があります.
また、
このような設定では、SQLを実行するたびに新しい接続が確立されます.
3.参考
packets.go:36: unexpected EOF (Invalid Connection)
MaxOpenConns,MaxIdleConns,ConnMaxLifetimeの理解とチューニングConfiguring sql.DB for Better Performance
go-sql-driver changelog
go-sql-driver/mysql
を使用してMySQLサービスに接続する過程で、しばらくの間、MySQL接続エラーが報告されます.[mysql] 2020/05/09 02:02:01 packets.go:36: unexpected EOF
2020-05-09 02:02:01 ERROR goroutine 59835131 invalid connection
調べたところ、無効な接続の使用によるものです.
基本シーンは次のとおりです.
問題の検証
検証コードの操作手順は次のとおりです.
コードは次のとおりです.
import (
"database/sql"
"log"
"time"
_ "github.com/go-sql-driver/mysql"
)
var DB *sql.DB
var dataBase = "root:Aa123456@tcp(192.168.1.101:3306)/?loc=Local&parseTime=true"
func mysqlInit() {
var err error
DB, err = sql.Open("mysql", dataBase)
if err != nil {
log.Fatalln("open db fail:", err)
}
err = DB.Ping()
if err != nil {
log.Fatalln("ping db fail:", err)
}
}
func main() {
mysqlInit()
for {
execSql()
time.Sleep(60*time.Second)
}
}
func execSql() {
_, err := DB.Exec("select 1")
if err != nil {
log.Println("exec sql failed:", err)
return
}
log.Println("success")
}
プログラム出力を見てください.
2020/05/24 12:00:49 success
[mysql] 2020/05/24 12:01:49 packets.go:36: unexpected EOF
2020/05/24 12:01:49 exec sql failed: invalid connection
2020/05/24 12:02:49 success
テストの結果、MySQLサービスが再起動されると、元の接続が無効になり、再使用されるとエラーが表示されます.
go-sql-driver/mysqlここでの実装では、問題の接続を接続プールから削除したり、接続エラーを報告したりして自動的に再接続することはありません.
2.ソリューション
シナリオ1アップグレードmysql driver
go-mysql-driver
をVersion 1.5(2020-01-07)にアップグレードします.テスト結果は次のように出力されます.
2020/05/24 15:11:33 success
[mysql] 2020/05/24 15:12:33 packets.go:123: closing bad idle connection: EOF
2020/05/24 15:12:33 success
2020/05/24 15:13:33 success
つまり、無効な接続が発生すると自動的に再接続されます.
関連するバグfixレコード、Bugfixesを参照:
Mark connections as bad on error during ping (#875)
Mark connections as bad on error during dial (#867)
シナリオ2接続多重時間の設定
go-mysql-driver
を一時的にアップグレードできない場合は、SetConnMaxLifetime()
で接続の多重化時間を設定できます.接続のデフォルトは永続的に多重化されます.接続の多重化時間は、接続がどのくらい使用されるかを示し、自動的に閉じます.
接続が使用中の場合、接続の多重化時間を超えてもすぐに閉じるのではなく、接続が使用されなくなってから閉じることに注意してください.
たとえば、接続多重化時間を60 sに設定します.
db.SetConnMaxLifetime(60 * time.Second)
どのくらいの時間を設定するかは、自分のシーンの必要に応じて設定する必要があります.
また、
SetMaxIdleConns()
を使用してidle接続を0に設定することを推奨する箇所もありますが、これは推奨されません.このような設定では、SQLを実行するたびに新しい接続が確立されます.
3.参考
packets.go:36: unexpected EOF (Invalid Connection)
MaxOpenConns,MaxIdleConns,ConnMaxLifetimeの理解とチューニングConfiguring sql.DB for Better Performance
go-sql-driver changelog