Hikariデータベース接続プールの内部ソースコードの実装の詳細

Hikariはデフォルトでいくつかのタイムアウト設定を行います

接続作成タイムアウト期間30秒
private static final long CONNECTION_TIMEOUT = SECONDS.toMillis(30);

接続存続検証時間は5秒で、この時間は検証中のsocketTimeoutであり、検証後に0に復元され
ますが、データが照会されるとデフォルトは0になります。つまり、タイムアウトになることはありません。
private static final long VALIDATION_TIMEOUT = SECONDS.toMillis(5);

接続アイドル時間10分
private static final long IDLE_TIMEOUT = MINUTES.toMillis(10);

最大接続生存時間30分
private static final long MAX_LIFETIME = MINUTES.toMillis(30);

Hikari接続プールのデフォルトの接続数は10です。

デフォルトの最小接続数は最大数に等しく、同じものは10ではありません
private static final int DEFAULT_POOL_SIZE = 10;

Hikariは、CopyOnWriteArrayListを介してすべての接続を保存します

com.zaxxer.hikari.util.ConcurrentBag#sharedList

スレッドが接続を取得できない場合、SynchronousQueueを介して公平なブロッキング待機が実現されます

接続のプールが使い果たされると、HikariSynchronousQueueはスレッドを実装してブロックして待機し、フェアロックを使用します。
ソースコード参照com.zaxxer.hikari.util.ConcurrentBag#handoffQueuecom.zaxxer.hikari.util.ConcurrentBag#ConcurrentBag構築方法

Hikari内には3つのシングルスレッドスレッドプールオブジェクトがあります

  • houseKeepingExecutorServiceaddConnectionExecutorcloseConnectionExecutorそれぞれ、スレッドプール、酸味のスレッドを1つだけ持っています:com.zaxxer.hikari.pool.HikariPool
  • houseKeepingExecutorServiceあるScheduledExecutorServiceオブジェクトが。プールで接続が作成されるたびに、接続はPoolEntryオブジェクトにカプセル化され、タイミングタスクに配置され、タイミング時間が設定されmax-lifetimeます。この時間に達するとすぐに、ソフトエビクションによってプールから削除されます。
  • 加えて、houseKeepingExecutorServiceさらに一旦空きプールに接続されているすべての30秒、呼び出すことによって、最大の接続を確認するように構成された异步创建连接异步销毁连接プールの方法で接続の数のバランスを維持します。

ソフトエビクションとは

  • 接続が使用されている場合、接続はすぐには閉じられませんが、PoolEntryオブジェクトのprivate volatile booleanevict;フィールドは閉じる必要があるとマークされます。次にこの接続を取得するスレッドがあるときに、evict = trueが見つかった場合、非同期のcloseメソッドが呼び出されます。プール内の他の接続を再取得します。
  • この接続が使用されていない場合、接続を非同期的に閉じるメソッドがすぐに呼び出されます。

プール内の接続の作成と終了は非同期ですが、初期化中に同期的に作成されるのは1つだけです。

  • 创建连接それはによって行われますaddConnectionExecutorThreadPoolExecutor)、およびそれが行われている关闭连接ことにより、closeConnectionExecutorThreadPoolExecutor)。
    これらの2つのスレッド・プールのそれぞれは、スレッドが1つしかありません。さらにhouseKeepingExecutorService、ひかり接続プールは3つのスレッドを作成します!

  • 起動パラメータ-Dcom.zaxxer.hikari.blockUntilFilledInitializationFailTimeout単位msを使用して、Hikariが起動時に最小数の接続が作成されるのを待機させることができます。デフォルトはfalseです

接続は本質的にソケット接続です

接続プールでは、接続接続の数は、サーバーに接続されているソケットオブジェクトの数に対応します。

HikariはThreadLocalを使用して接続をスレッドにバインドします

プールから接続を取得するパフォーマンスを向上させるために、HikariはThreadLocalを使用してリソースの競合を回避します。1つの接続は複数のスレッドに対応でき、1つのスレッドは複数の接続をバインドできます。ソースコードについては、ConcurrentBagクラスのメンバー変数を参照してください。 。private final ThreadLocal<List<Object>> threadList;

ThreadLocal List <Object>のジェネリックはなぜですか?

接続は異なる時間に複数のスレッドで使用できるため、別のスレッドでバインドされた接続が他のスレッドで使用されている場合は、他の未使用の接続を選択する必要があります。また、新しく選択した接続もこの1つのスレッドにバインドする必要があります。したがって、リストを使用して保存します。ソースコードを参照してください。com.zaxxer.hikari.util.ConcurrentBag#borrow

接続をThreadLocalに保存するのはいつですか?

接続プール内の接続が呼び出されてリソースが解放されると、再利用されます。ここでの接続は、実際にはHikariによって実装されたプロキシクラス(ProxyConnection)であり、JDBC接続をカプセル化します。
ソースコードを参照してください。com.zaxxer.hikari.pool.ProxyConnection#close

ひかりはどのように接続リサイクルを行うのですか

ProxyConnectionプロキシクラスを介して達成します。ソースコードを参照してください。com.zaxxer.hikari.pool.ProxyConnection#close

Hikariは、CASオプティミスティックロックを使用して接続の現在の状態を制御します

Hikariは、次の列挙値を介して接続の現在の状態をPoolEntryカプセル化Connectionしてprivate volatile int state記録し、CASオプティミスティックロックを介してこれらの状態を維持して、複数のスレッド間の接続を取得するパフォーマンスを向上させます。

public interface IConcurrentBagEntry{
    
    
  int STATE_NOT_IN_USE = 0;
  int STATE_IN_USE = 1;
  int STATE_REMOVED = -1;
  int STATE_RESERVED = -2;

  boolean compareAndSet(int expectState, int newState);
  void setState(int newState);
  int getState();
}

接続を取得し、検証接続の可用性を最適化します

プールから接続が取得されるたびに、接続の最終アクセス時間と現在の時間の差が最初に判断されます。500ミリ秒未満の場合、接続は直接使用可能であると見なされ、検証済みのSQLステートメントの送信を回避します。サーバーに接続し、接続プールのパフォーマンスを向上させます。ソースコードを参照してください。com.zaxxer.hikari.pool.HikariPool#getConnection(long hardTimeout)

 if (poolEntry.isMarkedEvicted() || (elapsedMillis(poolEntry.lastAccessed, now) > aliveBypassWindowMs && !isConnectionAlive(poolEntry.connection))) {
    
    
    closeConnection(poolEntry, poolEntry.isMarkedEvicted() ? EVICTED_CONNECTION_MESSAGE : DEAD_CONNECTION_MESSAGE);
    timeout = hardTimeout - elapsedMillis(startTime);
 }

それ以外の場合は、接続の可用性を確認する必要があります。
構成されているconnection-test-query場合は、構成SQL検証を使用します。それ以外の場合は、データベースドライバーによって実装されたjava.sql.Connection#isValid(int timeout)メソッド検証を使用しますソースcom.zaxxer.hikari.pool.PoolBase#isConnectionAlive参照:

接続できない場合は、警告ログが出力されます

接続の可用性を確認するプロセス、データベースのwait_timeoutタイムアウトが原因でサーバーによって接続が閉じられた場合、またはネットワークが異常な場合は、次の警告ログが表示されます。

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

解決策については、他のブログ参照してください接続の検証に失敗しましたcom.mysql.cj.jdbc.ConnectionImplトラブルシューティング

おすすめ

転載: blog.csdn.net/u013202238/article/details/115034155
おすすめ