15

Web ベースのデータ サービス用の MySQL 接続のプールがあります。リクエストの処理を開始すると、使用するプールからの接続が必要になります。問題は、その特定の接続が使用されてからかなりの一時停止があった場合、サーバーがタイムアウトして終了した可能性があることです。プール管理コードでこれを検出できるようにしたいと思います。

秘訣は次のとおりです。私がコーディングしている環境では、接続への非常に抽象的な API しか提供されません。基本的にSQL文しか実行できません。実際のソケットにアクセスしたり、MySQL クライアント API に直接アクセスしたりすることはできません。

問題は、接続が機能しているかどうかを判断するために接続で実行できる最も安価な MySQL ステートメントは何かということです。たとえば、SELECT 1;うまくいくはずですが、もっと安いものがあるのだろうか?おそらく、ネットワークを経由することさえありませんが、MySQL クライアント ライブラリで処理され、同じ質問に効果的に答えるものでしょうか?

明確化: MySQL サーバーが実行されているかどうか、またはデータベース構成がクエリに応答するのに十分であるかどうかを確認することについては心配していません。それらがダウンしている場合、サービスが実行する後続の SQL は、適切なエラーを取得して処理します。私が本当に気にかけているのは、TCP 接続が開いているかどうかだけです。サーバーが接続を閉じた場合、Web サービスの SQL は「再接続してもう一度やり直してください」という意味のエラーを受け取ります。サービスコードのくず。

クロージャ:ハック/* ping */はまさに​​私が探していたものですが、残念ながら JDBC 経由でしか利用できません。そのハックのドキュメントを読むと、私が欲しかったのとまったく同じ理由でそこに置かれたことは明らかです. 興味深いことに、私はHDBCHDBC-mysqlを使用してHaskelで作業しています。HDBC-mysql の作成者に、直接または同様のハックを介して呼び出す方法を追加するよう依頼するつもりです。mysql_ping()

Vlad のDO 1ものも私が求めていたものでした。他のハックは JDBC 以外では利用できないため、私はそれを使用します。

素晴らしい議論、特に @Vlad に感謝します!

4

3 に答える 3

18

有線を経由しないと接続の実際の状態を知ることはできずSELECT 1、十分な候補です(おそらく、解析にかかる時間が短い短いコマンドを思い付くことができますが、ネットワークやループバックの遅延と比較しても、これらの節約は重要ではありません。)

そうは言っても、プールからチェックアウトする前に接続にpingを実行するのは最善の方法ではないと私は主張します。

サーバーによって切断されないように、接続プールマネージャーに独自のキープアライブ(タイムアウト)ポリシーを適用させる必要があります(とにかく通常の操作の途中でスマックに影響を与える可能性のある、より深刻な接続の問題が発生する場合を除きます-そして、接続プールマネージャーはとにかく助けることができないでしょう)、そしてデータベースを不必要に占有しないようにするために(ファイルハンドルとメモリ使用量を考えてください)。

したがって、私の意見では、プールから接続をチェックアウトする前に接続状態をテストする価値が実際にどのようなものであるかは疑問です。接続がプールにチェックインされる前に接続ステータスをテストする価値があるかもしれませんが、SQLハードエラー(または同等の例外)が発生したときに接続をダーティとしてマークするだけで暗黙的に行うことができます(すでに使用しているAPIを除く)のis-badような呼び出しを公開します。)

したがって、私はお勧めします:

  • クライアント側の維持ポリシーの実装
  • プールから接続をチェックアウトするときにチェックを実行しない
  • 接続がプールに返される前にダーティチェックを実行する
  • アプリケーションコードに他の(タイムアウトではない)例外的な接続条件を処理させます

アップデート

コメントから、本当に接続にpingを実行したいように見えますこれは、MySQLサーバーまたはプロキシなどの介在するネットワーク機器のタイムアウト特性を完全に制御または認識していないためだと思います)。

この場合、 ;DO 1の代わりに使用できます。わずかにSELECT 1高速です。解析が短く、実際のデータは返されません(ただし、TCP取得するため、接続がまだ確立されていることを検証するラウンドトリップを実行します)。ack

更新2

Joshuaの投稿に関して、さまざまなシナリオのパケットキャプチャトレースを次に示します。

SELECT 1;
13:51:01.463112 IP client.45893 > server.mysql: P 2270604498:2270604511(13) ack 2531191393 win 1460 <nop,nop,timestamp 2983462950 59680547>
13:51:01.463682 IP server.mysql > client.45893: P 1:57(56) ack 13 win 65306 <nop,nop,timestamp 59680938 2983462950>
13:51:01.463698 IP client.45893 > server.mysql: . ack 57 win 1460 <nop,nop,timestamp 2983462951 59680938>

DO 1;
13:51:27.415520 IP client.45893 > server.mysql: P 13:22(9) ack 57 win 1460 <nop,nop,timestamp 2983488906 59680938>
13:51:27.415931 IP server.mysql > client.45893: P 57:68(11) ack 22 win 65297 <nop,nop,timestamp 59681197 2983488906>
13:51:27.415948 IP client.45893 > server.mysql: . ack 68 win 1460 <nop,nop,timestamp 2983488907 59681197>

mysql_ping
14:54:05.545860 IP client.46156 > server.mysql: P 69:74(5) ack 78 win 1460 <nop,nop,timestamp 2987247459 59718745>
14:54:05.546076 IP server.mysql > client.46156: P 78:89(11) ack 74 win 65462 <nop,nop,timestamp 59718776 2987247459>
14:54:05.546092 IP client.46156 > server.mysql: . ack 89 win 1460 <nop,nop,timestamp 2987247459 59718776>

ご覧のとおり、mysql_pingパケットがDO 1;9バイトではなく5バイトであるという事実を除けば、ラウンドトリップの数(およびその結果としてネットワークに起因する遅延)はまったく同じです。DO 1とは対照的に、あなたが支払っている唯一の追加費用mysql_pingは、の解析ですDO 1。これは些細なことです。

于 2010-03-30T16:38:39.640 に答える
6

現在使用している API (または言語) はわかりませんが、Java の場合、JDBC ドライバーが実行できる特別なトリックがあります。

標準のテスト クエリは次のとおりです。

select 1

あなたが示したように。次のように変更した場合:

/* ping */ select 1

JDBC ドライバーはこれを認識し、単一のパケットのみを MySQL サーバーに送信して応答を取得します。

これについては、Sun の「Deep Dive」エピソードで、MySQL Tips for Java Developers With Mark Matthewsというタイトルで学びました。

Java を使用していない場合でも、これと同じトリックが他の mysql ドライバーに実装されているのではないでしょうか? サーバーは、応答を送信できるように、この特別なパケットを認識する必要があると思います...

于 2010-03-30T23:38:03.237 に答える
1

この場合の「接続」には複数の意味があります。MySQL は、ネットワーク レベルの「接続」であるソケットをリッスンします。MySQL は、クエリ実行のコンテキストやその他のオーバーヘッドを含む「データベース接続」を維持します。

サービスがリッスンしているかどうかだけを知りたい場合は、ネットワークレベルの呼び出しを実行して、ポート (デフォルトが何であるかは不明) がターゲット IP でリッスンしているかどうかを確認できるはずです。MySQLエンジンを応答させたい場合、あなたのSELECT 1アイデアは良いと思います.データベースから実際にデータを取得するのではなく、エンジンがスピンアップして応答していることを確認します.

于 2010-03-30T16:35:45.607 に答える