Mysql: 切断された接続での奇妙なエラー

作成日 2013年12月05日  ·  25コメント  ·  ソース: go-sql-driver/mysql

クエリが長時間実行されている接続を強制終了すると、次のようなメッセージが表示されます。

[MySQL] 2013/12/05 22:17:19 packets.go:30: EOF
[MySQL] 2013/12/05 22:17:19 statement.go:24: Invalid Connection
[MySQL] 2013/12/05 22:17:27 packets.go:30: EOF
[MySQL] 2013/12/05 22:17:27 statement.go:24: Invalid Connection
[MySQL] 2013/12/05 22:17:39 packets.go:30: EOF
[MySQL] 2013/12/05 22:17:39 statement.go:24: Invalid Connection

私はこのエラーを見るのに慣れています:

2013 (HY000) at line 1: Lost connection to MySQL server during query

私の知る限り、そのエラーは実際にはネットワーク接続を介して、強制終了されたクライアントに返送されます。 これはドライバーまたはデータベース/ SQLでマスクされていますか、それとも私が思うようにプロトコルを介して送信されたエラーではありませんか? どういうわけか、何が起こっているのかをより明確にすることができますか?

bug thinking

最も参考になるコメント

私はこれが問題だと思います:

package main

import (
    "database/sql"

    _ "github.com/go-sql-driver/mysql"
)

func main() {
    db, _ := sql.Open("mysql", "/")
    defer db.Close()
    tx, err := db.Begin()
    if err != nil {
        panic(err)
    }
    defer tx.Commit()
    stmt1, err := tx.Prepare("SELECT 1")
    if err != nil {
        panic(err)
    }
    rows1, err := stmt1.Query()
    if err != nil {
        panic(err)
    }
    stmt2, err := tx.Prepare("SELECT 2")
    if err != nil {
        // rows1 is not closed -> triggers busy buffer because transaction is on one connection
        // and stmt1, stmt2 use the same one.
        // Move rows1.Close() in front of tx.Prepare and it disappears
        panic(err)
    }
    rows2, err := stmt2.Query()
    if err != nil {
        panic(err)
    }
    rows1.Close()
    rows2.Close()
    stmt1.Close()
    stmt2.Close()
}

全てのコメント25件

いいえ、エラーは送信されません。 エラーは、実際には何も受信できないことです:wink:
ただし、 EOFよりも説明的なエラーメッセージを出力することをお勧めします。

statement.go:24: Invalid Connectionエラーはhttp://golang.org/issue/5718の結果だと思い
自動再接続ロジックがdatabase / sqlパッケージで修正されると、これらのエラーは消えるはずです。

EOFio.EOFだけですが、これをフィルタリングして置き換える必要があるかどうかはわかりません。 このような場合に使用するのは一種のGoイディオムです(たとえば、このエラーが発生するネットパッケージの場合など)。 しかし、少なくともその意味はどこかに文書化されるべきです。

あなたの意見は何ですか?

@gkristicがこれについて

私はdatabase / sqlのコードに従いました。 statement.go:24: Invalid Connectionエラーはhttp://golang.org/issue/5718の結果ではありませんが、パッケージが再試行する必要があるという点で@julienschmidtに同意します。 DBレベルで実行した場合、 Query()およびExec()呼び出しは最大10回試行されますが、Stmtレシーバーを使用した場合は試行されません。

「無効な接続」 @xaprbが見たのは、プリペアドステートメントに対してClose()が呼び出されたときに、MySQL接続が使用できなくなったためです。つまり、 stmt.mc.netConnここではnilErrBadConnが返されるとすぐに、database / sqlでの接続が閉じられるためです。

しかし、私が見た可能性はそれだけではありません。 database / sql(Go 1.2)には同時実行性の問題があり、そのメッセージも表示される可能性があります。 (データベース/ SQL)ステートメントがドライバー接続で使用されているときに閉じられた場合、ドライバーステートメントは次のputConn()noteUnusedDriverStatement()によって閉じられるようにスケジュールされます。 ただし、 putConn()は、 removeOpenStmt()が呼び出される前に実行される可能性があります( (*Stmt) finalClose() )。 保留中のonPut関数を呼び出した後、アイドル接続制限のために接続自体が閉じられた場合、パッケージはステートメントを再度閉じようとし、メッセージが表示されます。 これも無害ですが、それでも迷惑です。

IMHOGoのデータベース/ SQLは注意深く再検討する必要があります...

@gkristicドライバーの変更を提案しますか?

database / sqlパッケージにはいくつかの欠陥があります。Go1.3用にいくつかの改善を加えたいと思います。 依存関係の管理を再検討することは、私のリストの1つの項目です。

このような問題を発見した場合は、 https://code.google.com/p/go/issues/listで報告して

これらの条件(つまり、接続が失われたか、database / sqlによって二重に閉じられた)が無害であることを考えると、「無効な接続」メッセージを出力する代わりに、ドライバーがそれらを黙ってスキップすることを期待します。 私の意見では、後者は次のいずれかになります。無害であることがわからない場合は怖い。 一度やると迷惑です。 しかし、おそらく誤解を招く可能性があります。同じメッセージが別の場所に印刷されている場合(行番号を除いてあります)、簡単にスキップできる実際の警告を隠します。 ステートメントClose()関数でstmt.mcまたはstmt.mc.netConnいずれかがゼロの場合、それ以上ログを記録せずに戻ることをお勧めします。 また、そこにdriver.ErrBadConnを返すこと(4d3764bbcb17c31575642626baeab1bcdc30c301で導入されたように)はまったく効果がないことに注意してください。database/ sqlはステートメントcloseの戻りコードをチェックしません。

ちなみに、ロガーを微調整する機能を追加したいと思います。 現在、 errLogはパッケージ内で初期化され、プライベートです。 使用できる場合とできない場合がある標準エラーに出力されます。 つまり、プロセスは他の理由で記述子を閉じることを選択する場合があります。 しかし、そうでない場合でも、ユーザーはロギングについて別の考えを持っている可能性があります(ファイル、syslogなどを考えてください)。 ドライバーはこのデフォルトのロガーを提供できますが、ユーザーが別のロガーを設定できるようにすることもできます。

暇があればすぐに、前に述べた問題の小さな例を用意して、レポートを作成します。

ありがとう!

ロガーに関する@ gkristic - https://github.com/go-sql-driver/mysql/pull/182 (1週間前にマスターにマージされた)のようなものを意味しますか?

@arnehormannああ、男...まさにそれ。 私はv1.1で作業しています。 投稿する前にマスターで他のものもチェックしましたが、ロギングをチェックするのを忘れました。 申し訳ありませんが、ありがとうございます!

@gkristicはまったく問題ありません:

次のリリースの前に行う必要のある変更はありますか? PRは大歓迎です:)

こんにちは、go-sql-driverの新しいユーザーです。 私は同様の問題に気づいていますが、誰かが原因が同じであることを確認するのを手伝ってくれるかどうか疑問に思っていましたか? goroutineを利用する長期実行のcronでは、次の情報を定期的に受け取っています。

[MySQL] 2014/05/14 20:33:05 packets.go:356: Busy buffer
[MySQL] 2014/05/14 20:33:05 packets.go:73: EOF
[MySQL] 2014/05/14 20:33:05 statement.go:24: Invalid Connection
[MySQL] 2014/05/14 20:33:05 connection.go:206: Invalid Connection

私はここで手を汚したいと思っています。問題に取り組む方法についてのガイダンスを探しているだけです。 この「無効な接続」エラーは、特定の状況で無視しても安全ですか? これが検出された場合に別の接続を自動的に取得する方法はありますか?

ええと、ああ...私が見た今、私は先週の金曜日からの@julienschmidtによるコメントを逃しました。 (ジュリアンに謝罪します。) @ rmulley 、あなたは私が上で説明したのと同じ問題にぶつかったようです。 このコメントを見てください。 statement.go:24の「無効な接続」は無害です。 ドライバーは、別の接続を選択して適切なことを行う必要があります。 「ビジーバッファ」についてはよくわかりません。 それを見たのを覚えていません。 このコードをチェックしてからかなり時間が経ちました。 少し時間を取って、もう一度見て、私が助けることができるかどうかを確認します。 残念ながら、それは来週の終わりまでには起こり得ません。 しかし、私はそれまでにあなたに返事をします。

@rmulley :私には、これはこの問題とは無関係のようです。
go get (古いバージョン)によってインストールされたバージョンを使用した場合は、現在のgitマスターバージョンでこのエラーを再現してみてください。
その後、新しい号を開いてください。 このエラーをトリガーする最小限のコードサンプルは間違いなく役立ちます。

(b *buffer) takeBuffernil返すようです。 これは、 b.length > 0場合にのみ発生するようです。 これは、何らかの理由でバッファに未読データがあることを意味します。
私はこれまでこのエラーを見たことがなく、安全性を高めるためにこれらの追加のチェックを実装しただけです。 私は、このエラーを実際には信じられなかったでしょう。

#206によると、goをチップから実行すると、このエラーは実際にはなくなります。 実際にはそうではありませんか?

まず、休暇中に応答が遅れて申し訳ありませんでしたが、フォローアップを忘れていました。 MySQLドライバーの最新バージョンを使用していることを確認し、現在Go1.3でテストしています。 エラーメッセージに詳細が表示されているようです。

[MySQL] 2014/06/23 11:46:04 packets.go:356: Busy buffer
[MySQL] 2014/06/23 11:46:04 packets.go:73: read tcp xxx.xxx.xxx.xx:3306: connection reset by peer

これは私の側のMySQLの問題ですか? (この問題を解決する方法について、オンラインで役立つものは何も見つかりませんでした)
それとも、これをチェックして、コードで再接続できるものですか?

rmulleyが説明したのと同じ問題が発生しました。 異なる点は、「ビジーバッファ」が非常に短いクエリ(1クエリ+ 2 Exec)で表示されたことです。

問題は準備されたステートメントに関連していると思います。 トランザクションでステートメントを準備した場合、次のようになります。

 stmt, err = tx.Prepare("SELECT ...")

別のステートメントを準備する前に、このstmtを閉じる必要があります。そうしないと、毎回「ビジーバッファ」が発生します。 プリペアドステートメントを使用しない場合、たとえば、次のようにtxに直接実行する

 tx.Query("...")

または

tx.Exec("...")

、大丈夫でした。

そして、ステートメントを準備してから、他のQueryまたはExecの他のものを実行する場合、それも問題ありません...前のステートメントを閉じずに別のステートメントを準備しないでください。問題ないように見えます。

それが本当に問題がある場所であることを願っています。

ありがとう。

エラーを再現できる小さなGoプログラムを作成できますか?
これは間違いなくドライバーのバグのようですが、ここで報告された元の問題とは関係ありません。
その後、新しい問題を作成してください。

私はこれが問題だと思います:

package main

import (
    "database/sql"

    _ "github.com/go-sql-driver/mysql"
)

func main() {
    db, _ := sql.Open("mysql", "/")
    defer db.Close()
    tx, err := db.Begin()
    if err != nil {
        panic(err)
    }
    defer tx.Commit()
    stmt1, err := tx.Prepare("SELECT 1")
    if err != nil {
        panic(err)
    }
    rows1, err := stmt1.Query()
    if err != nil {
        panic(err)
    }
    stmt2, err := tx.Prepare("SELECT 2")
    if err != nil {
        // rows1 is not closed -> triggers busy buffer because transaction is on one connection
        // and stmt1, stmt2 use the same one.
        // Move rows1.Close() in front of tx.Prepare and it disappears
        panic(err)
    }
    rows2, err := stmt2.Query()
    if err != nil {
        panic(err)
    }
    rows1.Close()
    rows2.Close()
    stmt1.Close()
    stmt2.Close()
}

同様のビジーバッファの問題が発生し、 @ arnehormannが正しいように見えることを確認できます。 この問題は、行オブジェクトがまだ開いているときに複数のクエリに同じトランザクションを使用しようとすると発生します

こんにちはみんな、これが何らかの方法で解決されたかどうかはわかりません。 この問題は、「Exec」で実行された短い挿入で発生しています->

var sql = "テーブル(f1、f2 ... f25)の値(?、?、...?)に挿入"
_、err:= db.Exec(sql、...)

約4000回後、5000回挿入すると「予期しないEOF」と「ビジーバッファ」が発生することがあります。
挿入は(forループで)タイトですが、それぞれの間にREST要求があるため、それほど急速な発火ではありません。 同じ接続参照。 これはGo1.3です。

ありがとう、
サル

@ Sal -go 1.4を使用するとどうなりますか?

22:11の水曜日、2014年12月31日には、サルA. Magnone [email protected]
書きました:

こんにちはみんな、これが何らかの方法で解決されたかどうかはわかりません。 私はこれを見ています
「Exec」で実行される短い挿入の問題->

var sql = "テーブル(f1、f2 ... f25)の値(?、?、...?)に挿入"
_、err:= db.Exec(sql、...)

約4000回後、5000回の挿入で「予期しないEOF」と「ビジー」が発生することがあります
バッファ"。
挿入はタイトです(forループ内)が、間にREST要求があります
それぞれ、そう、それほど急速な火ではありません。 同じ接続参照。 これはGo1.3です。

ありがとう、
サル


このメールに直接返信するか、GitHubで表示してください
https://github.com/go-sql-driver/mysql/issues/185#issuecomment-68479413

お返事をありがとうございます。

1.4 –同じエラー。 約50分で4205インサートで死亡しました(各インサート間にネットとスクリーンI / Oがあります)。

コードをリファクタリングして、オプションで前回中断したところから再開しました。 したがって、このアプリにとっては重要ではありませんが、これが累積的なリクエストの問題である場合、このプロジェクトの他のアプリにとっては重要になる可能性があります。

-サル

差出人:カルボカチオン[mailto:[email protected]]
送信日:2015年1月4日日曜日午前9時50分
宛先:go-sql-driver / mysql
Cc:Sal A. Magnone
件名:Re:[mysql]切断された接続での奇妙なエラー(#185)

@ Sal -go 1.4を使用するとどうなりますか?

22:11の水曜日、2014年12月31日には、サルA. Magnone < [email protected] [email protected] >
書きました:

こんにちはみんな、これが何らかの方法で解決されたかどうかはわかりません。 私はこれを見ています
「Exec」で実行される短い挿入の問題->

var sql = "テーブル(f1、f2 ... f25)の値(?、?、...?)に挿入"
_、err:= db.Exec(sql、...)

約4000回後、5000回の挿入で「予期しないEOF」と「ビジー」が発生することがあります
バッファ"。
挿入はタイトです(forループ内)が、間にREST要求があります
それぞれ、そう、それほど急速な火ではありません。 同じ接続参照。 これはGo1.3です。

ありがとう、
サル


このメールに直接返信するか、GitHubで表示してください
https://github.com/go-sql-driver/mysql/issues/185#issuecomment-68479413


このメールに直接返信するか、GitHub https://github.com/go-sql-driver/mysql/issues/185#issuecomment-68635254で表示してhttps://github.com/notifications/beacon/AA4DdvfCFMdiqPlTZITEs9VrxyyJqqFQks5neUqigaJpZM4BSM1b.gif

このスレッドは今、いくつかのスレッドになっていますか? 最新のコメントを新しい問題に入れて、これを閉じる必要がありますか?

@xaprb同意します。現在、いくつかのスレッドが進行中であると思います。 おそらくこれを閉じて、 https: //github.com/go-sql-driver/mysql/issues/185#issuecomment-68479413から新しい問題に取り入れることができ

このページは役に立ちましたか?
0 / 5 - 0 評価