JedisPool-Java.net.SocketException:壊れたパイプ(書き込みに失敗しました)

I.はじめに

JedisPollマルチスレッド書き込みを使用する場合、パイプの破損が定期的に報告され、再起動後のタスクは正常であり、しばらくするとエラーが再び発生します。

JedisPoolは次のように構成されています。

  val config = new JedisPoolConfig
  config.setMaxIdle(20)
  config.setMinIdle(20)
  config.setNumTestsPerEvictionRun(-2)
  config.setTimeBetweenEvictionRunsMillis(30000)
  config.setSoftMinEvictableIdleTimeMillis(3600000)
  config.setMinEvictableIdleTimeMillis(-1)
  config.setTestOnBorrow(false)
  config.setTestOnReturn(false)
  config.setTestWhileIdle(false)

2.問題の分析と解決策

1.問題のシナリオ

タスクは非常に単純です。JedisPoolを使用してクラスター内の複数のスレッドにデータを書き込むと、タスクが一定期間実行された後にエラーがスローされます。Trycatchを実行した後、タスクが時折エラーになることがわかりました。すべての書き込みが失敗するわけではありません。エラーが報告されます。予備的な分析では、getResourceメソッドが無効な接続を取得し、書き込みが失敗することがあります。また、開始したばかりのタスクによって取得されたredis接続が有効であり、パイプが壊れていないため、タスクは再起動後に正常に実行されます。

2.問題解決

構成を通じて、次の3つのパラメーター設定がすべてfalseであることがわかります。

  config.setTestOnBorrow(false)
  config.setTestOnReturn(false)
  config.setTestWhileIdle(false)

TestOnBorrowをtrueに設定するか、testWhileIdleをtrueに設定します。それでも機能しない場合は、両方をtrueに設定します。

 

3.パラメータの意味

・setTestOnBorrow

借用とは、JedisPool接続プールから接続を取得することです。このパラメーターは、redis接続を取得するときの接続の有効性を制御します。リンクが無効であることが確認された場合、リンクはクリーンアップされ、新しい接続のために再取得されます。ここでは、ソースコードでgetResourceメソッドを参照できます。このメソッドは、プールからborrowObjectメソッドを実行して接続を取得します。このクラスの場所はredis.client.util.Poolであり、基盤となる実装はorg.apacheを参照します。 .commons.pool2.impl.GenericObjectPool。

  public T getResource() {
    try {
      return internalPool.borrowObject();
    } catch (Exception e) {
      throw new JedisConnectionException("Could not get a resource from the pool", e);
    }
  }

このパラメーターを構成した後、新しい接続を取得するためにborrow呼び出しを行うと、接続が失敗すると、activeObjectメソッドが呼び出され、接続の内部状態がリセットされます。これは、新しい接続を取得することと同じです。

    try {
        this.factory.activateObject(p);
    } catch (Exception var15) {
        try {
            this.destroy(p);
        } catch (Exception var14) {
        }

        p = null;
        if (create) {
            NoSuchElementException nsee = new NoSuchElementException("Unable to activate object");
            nsee.initCause(var15);
            throw nsee;
        }
    }

 

・SetTestOnReturn

returnは、returnResourceを呼び出すときに設定されるパラメータです。このパラメータは、リソース接続が接続プールに返されるときの接続の有効性を制御します。接続が無効な場合、接続はクリーンアップされます。このメソッドは、プールからreturnResourceObjectメソッドを実行します。このクラスの場所はredis.client.util.poolであり、基礎となる実装もGenericObjectPoolを参照します。

  public void returnResourceObject(final T resource) {
    if (resource == null) {
      return;
    }
    try {
      internalPool.returnObject(resource);
    } catch (Exception e) {
      throw new JedisException("Could not return the resource to the pool", e);
    }
  }

このパラメーターが構成されている場合、コードは接続でValidateObjectメソッドを呼び出して、ObjectResourceを返すときに有効性を判断し、無効な場合は以下を破棄します。

        if (this.getTestOnReturn() && !this.factory.validateObject(p)) {
            try {
                this.destroy(p);
            } catch (Exception var10) {
                this.swallowException(var10);
            }

            try {
                this.ensureIdle(1, false);
            } catch (Exception var9) {
                this.swallowException(var9);
            }

            this.updateStatsReturn(activeTime);
        }

・SetTestWhileIdle

このパラメーターは、アイドル状態の接続のテストを制御します。このパラメーターは、config.setTimeBetweenEvictionRunsMillis(30000)に対応します。ここで、アイドル判定は、このパラメーターで設定されたミリ秒の時間に基づいています。ここでアイドル接続の有効性がチェックされ、evictメソッドが実際にクリーンアップを実行します。

    public void evict() throws Exception {
        this.assertOpen();
        if (this.idleObjects.size() > 0) {
            PooledObject<T> underTest = null;
            EvictionPolicy<T> evictionPolicy = this.getEvictionPolicy();
            synchronized(this.evictionLock) {
                EvictionConfig evictionConfig = new EvictionConfig(this.getMinEvictableIdleTimeMillis(), this.getSoftMinEvictableIdleTimeMillis(), this.getMinIdle());
                boolean testWhileIdle = this.getTestWhileIdle();
                int i = 0;
                int m = this.getNumTests();

                while(true) ...

ここの7行目には、MinEvictableIdleTimeMillisとSoftMinEvictableIdleTimeMillisの2つの時間パラメーターも含まれています。これには、スレッドプールidleEvictTimeの選択が含まれます。前者が最初に読み取られます。前者が負の場合、デフォルトはmaxLongです。前者が構成されていない場合、後者が読み取られます。 、したがって、スレッドプール-1、-2のいくつかの構成パラメーターが表示され、実際には-1ミリ秒の時間はありません。

    public EvictionConfig(long poolIdleEvictTime, long poolIdleSoftEvictTime, int minIdle) {
        if (poolIdleEvictTime > 0L) {
            this.idleEvictTime = poolIdleEvictTime;
        } else {
            this.idleEvictTime = 9223372036854775807L;
        }

        if (poolIdleSoftEvictTime > 0L) {
            this.idleSoftEvictTime = poolIdleSoftEvictTime;
        } else {
            this.idleSoftEvictTime = 9223372036854775807L;
        }

        this.minIdle = minIdle;
    }

evictロジックの実行を開始するための実際の判断は、次の関数にあります。

    public boolean evict(EvictionConfig config, PooledObject<T> underTest, int idleCount) {
        return config.getIdleSoftEvictTime() < underTest.getIdleTimeMillis() && config.getMinIdle() < idleCount || config.getIdleEvictTime() < underTest.getIdleTimeMillis();
    }

次の条件のいずれかが満たされた場合、立ち退きが実行されます。

A.接続のアイドル時間がsoftMinEvictableIdleTimeMillisより長く、接続プールのアイドル数がEvictionConfigの3番目のパラメーターであるminIdleNum未満です。

B.接続のアイドル時間がminEvictableIdleTimeMillisより大きい 

もちろん、削除されるだけではありません。ある程度、スレッドプールはensureIdleを実行して新しい接続を作成し、スレッドプールで十分な接続が使用可能であることを確認します。

3.まとめ

上記のエラーレポートとシーン設定TestOnBorrow=trueおよびTestWhileIdle=trueは完全に解決されますが、パフォーマンスが低下することもあります。自分のシーンに合わせて調整できます。通常、TestOnBorrowのみをオンにできます。

おすすめ

転載: blog.csdn.net/BIT_666/article/details/123499279