HikariCP 接続プール: より短い maxLifetime 値の使用を検討してください。

エラー分析と位置特定

プロジェクトでデータベースクラスタを使用しています。使用中、プロジェクトが実行中であり、一定期間データベースが操作されていないことがわかりました。一定期間後に再度データベースを操作すると、以下のエラーが発生します。コンソールに表示されます。
ここに画像の説明を挿入します
ここに画像の説明を挿入します

Failed to validate connection com.mysql.cj.jdbc.ConnectionImpl@de1855 (No operations allowed after connection closed.). Possibly consider using a shorter maxLifetime value.

プロジェクトが mysql クラスターを統合する場合、Baomidou が開発した動的データ ソース ツールを使用します。

		<!--动态数据源,提供@DS注解方便使用动态数据源-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
            <version>2.5.4</version>
        </dependency>

ログを見ると、おそらく接続プールのエラーで、hikariデータベースの接続プールが使用されていることが分かります。以前は Druid だけを知っていましたが、Hikari については知りませんでした。動的データ ソース ツールを統合するときに、関連する接続プールを構成しませんでした。エラーの内容は、より小さい maxLifetime 値を使用することを示唆しているため、このエラーの理由は、接続プールのパラメータ maxLifetime がデータベースの接続有効期間よりも大きいことが考えられます。接続プール内の接続は期限切れになっていませんが、データベースの有効期限が切れた後、接続が閉じられた後の操作。

mysql接続タイムアウトパラメータ

Mysql には接続タイムアウトに関連する 2 つのパラメータがあり、1 つはinteractive_timeout、もう 1 つは wait_timeout で、単位は s です。
表示するには次のステートメントを使用します。

show variables like '%timeout%';

ここに画像の説明を挿入します
両方のパラメータのデフォルトは 28800 秒 (8 時間)、
interactive_timeout は、mysql が対話型接続を閉じる前に待機する秒数を指し、wait_timeout は、mysql が非対話型接続を閉じる前に待機する秒数を指します。mysql クライアントを介したデータベースへの接続は対話型接続であり、jdbc を介したデータベースへの接続は非対話型接続です。

光CP接続タイムアウトパラメータ

Druid と HikariCP はアクティブなデータベース接続プールであり、よりシンプルで高速であると言われています。ただし、この記事では接続タイムアウト パラメーターに焦点を当てます。
ここに画像の説明を挿入します


ソース コードと公式ドキュメント
を見ると、 CONNECTION_TIMEOUT はプールからの接続を待機する最大ミリ秒数であり、デフォルトは 30000ms (30 秒) であることがわかりました。少なくとも 250 ミリ秒。
IDLE_TIMEOUT は、プール内で接続がアイドル状態になれる最大時間です。デフォルトは 600000 ミリ秒、つまり 10 分です。この値は少なくとも 10 秒で、0 は無限を意味します。この値は、minimumIdle が設定されている場合にのみ有効です。
MAX_LIFETIME は、プール内の接続の最大ライフ サイクルです。デフォルトは 1800000 ミリ秒、つまり 30 分です。この値は少なくとも 30 秒で、0 は無制限を意味します。
これらの値は mysql の 8 時間よりもはるかに小さいです

公式ドキュメントにはmaxlifetimeについて言及されています

この値を設定することを強くお勧めします。この値は、データベースやインフラストラクチャに課される接続時間制限よりも数秒短くする必要があります。

この値をデータベース接続タイムアウトの値よりも数秒短く設定することを強くお勧めします。

タイムアウトメカニズム

接続が長期間使用されなかった場合、接続は Mysql によって閉じられます (ただし、null ではありません)。このとき、Connection を呼び出すと例外がスローされます。
ただし、論理的に言えば、mysql の有効期限が 8 時間で、データベース接続プールの有効期限が 30 分であれば、この問題は発生しないはずであり、この問題は数十秒以内に発生します。

コマンドを使用して現在の接続を表示します

SHOW PROCESSLIST;

ここに画像の説明を挿入します
約 30 ~ 40 個の大量の接続が残っていることが判明しました。これは、前回のプログラム起動時に残った接続であるはずです。MySQL は接続を閉じませんでした。これは接続プールに問題がありました。

これは依然として hikari 構成の問題であるため、プロンプトに従って max-lifetime を変更する必要があります。
ダイナミック リンク ライブラリを使用しない場合は、その構成を使用できます。

spring:
  datasource:
    hikari:
        max-lifetime: 300000

ダイナミックリンクライブラリを使用するため、その構成でこのhikariを設定する必要があります。

spring:
  datasource:
    dynamic:
    	datasource:
			hikari:
		    	max-lifetime: 300000

800000 に変更し、5 分間アイドル状態になった後にリクエストを送信すると、安定してエラーが発生します。30000 に設定すると、エラーは発生しなくなります。この時点では、mysql データベースの wait_timeout はまだ 8 時間です。
wait_timeout を 300 秒、つまり上記の変更と同じ 5 分に変更します。変更後、大量の接続が消えました。プロジェクトを再起動すると、起動時に 4 つの接続が存在していました。最大時間値は 300 を超えません。超えた場合は 0 からカウントされます。この値はmax-lifetime によって制限され、後続のリクエスト数が増加するにつれて接続数は増加しますが、最終的には 10 接続で固定されます。この 10 個の接続は、hikari の最大スレッド数によって制限されており、アイドル待ち時間とアイドル スレッド数が設定されていないため、このプログラムの実行中にはおそらく 10 個の接続があり、プログラムを終了すると時間が 300 を超えています。接続は直接消滅し、0 からカウントを開始しなくなります。

ここで非常に紛らわしい点の 1 つは、wait_timeout と interactive_timeout です。
MySQL には 2 つのレベルの構成があり、1 つはセッション、もう 1 つはグローバルです。ヌードルを購入するための以下のステートメントは、デフォルトでセッション レベルになります。

show variables like '%timeout%';

mysql のグローバル レベルを表示したい場合は、global パラメータを追加する必要があります。

show global variables like '%timeout%';

これら 2 つのレベルの下には 4 つのパラメータがあります。

  • グローバルレベルのinteractive_timeout
  • グローバルレベルのwait_timeout
  • セッションレベルのinteractive_timeout
  • セッションレベルのwait_timeout

各パラメータの詳細な実験プロセスについては、この投稿を読むことができますが、本当に目まぐるしくなります。ここで要約しますが、注意する必要があることがいくつかあります。

  1. インタラクティブモードでは、セッションレベルのinteractive_timeoutはグローバルレベルのinteractive_timeoutを継承します。
  2. インタラクティブ モードでは、接続時間は interactive_timeout の影響を受けます。
  3. 非対話型モードでは、セッション レベルの wait_timeout はグローバル レベルの wait_timeout を継承します。
  4. 非対話型モードでは、接続時間は wait_timeout の影響を受けます。
  5. インタラクティブ モードでは、セッション レベルの wait_timeout はグローバル レベルの interactive_timeout を継承します。
  6. グローバル レベルでの値の変更は後続の接続に対して有効であり、セッション レベルでの値は現在の接続に対して有効です。
  7. 同じレベルのパラメータは相互に影響しません。

第 5 条に基づいて、誰かが次の結論に達しました。wait_timeout を変更するには、グローバル レベルの interactive_timeout も同時に変更する必要があります。
その理由は、常にセッション レベルの構成を表示および変更するためですが、これはこの記事では重要ではありません。
私たちの目的は、接続プール (非対話モード) の後続の接続のタイムアウト時間を変更することです。つまり、後続のセッション レベルの wait_timeout の値が設定した値になることを望みます。3 番目のルールによれば、この時点ではグローバル レベルの wait_timeout を設定しただけであることがわかります。

set global wait_timeout=300;

mysql のタイムアウト メカニズムを理解すると、グローバル レベルの wait_timeout が maxlifetime に対応することを理解するのは難しくありません。maxlifetime が期限切れになっていないときにネットワーク遅延によってリクエストが送信されるのを防ぐために、mysql に到達した時点で wait_timeout が期限切れになります。したがって、maxlifetime は maxlifetime. 秒よりも小さく設定する必要があります。先ほどの wait_timeout の 8 時間と maxlifetime の 30 分が 5 分ほどで接続が切れてしまう理由については、ちょっとまだ理解できないので、まずはこのように設定してみます。

おすすめ

転載: blog.csdn.net/weixin_45654405/article/details/126426078