JavaプログラミングRetry再試行メカニズムの例を詳しく説明する。


本論文の研究は主にJavaプログラミングRetry再試行機構の実例を詳しく説明し、関連コードの例を共有しました。
1、業務シーン
アプリケーションでは、リモートストレージサービスにデータをアップロードし、リターン処理が成功した場合に別の操作を行う機能が必要です。この機能は複雑ではなく、2つのステップに分けられます。第1ステップはリモートのRestサービス論理パッケージを起動して処理方法に処理結果を返します。第二ステップは第一ステップの結果を取得するか、例外を獲得します。もしエラーが発生したり、異常が発生したら、アップロードロジックを再試行します。そうでなければ、論理操作を続けます。
2、従来の解決策の進化
1)try-catch-redo簡単再試験モード:
パッケージ正常アップロードロジックに基づいて、復帰結果または異常決定を監督することにより、再試行するかどうかを判断し、同時に即時再試行の無効な実行を解決するため(異常に外部実行不安定があると仮定して)、スリープ一定の遅延時間で機能論理を再実行する。

public void commonRetry(Map<String, Object> dataMap) throws InterruptedException { 
    Map<String, Object> paramMap = Maps.newHashMap(); 
    paramMap.put("tableName", "creativeTable"); 
    paramMap.put("ds", "20160220"); 
    paramMap.put("dataMap", dataMap); 
    boolean result = false; 
    try { 
      result = uploadToOdps(paramMap); 
      if (!result) { 
        Thread.sleep(1000); 
        uploadToOdps(paramMap); //     
      } 
    } catch (Exception e) { 
      Thread.sleep(1000); 
      uploadToOdps(paramMap);//     
    } 
  } 
2)try-catch-redo-retry strategy戦略再試行モード:
上記の方案はまだ再試行が無効になる可能性があります。この問題を解決して再試行回数retrycountと再試行間隔周期intervalを増加させ、再試行の有効性を高める可能性があります。

public void commonRetry(Map<String, Object> dataMap) throws InterruptedException { 
    Map<String, Object> paramMap = Maps.newHashMap(); 
    paramMap.put("tableName", "creativeTable"); 
    paramMap.put("ds", "20160220"); 
    paramMap.put("dataMap", dataMap); 
    boolean result = false; 
    try { 
      result = uploadToOdps(paramMap); 
      if (!result) { 
        reuploadToOdps(paramMap,1000L,10);//       
      } 
    } catch (Exception e) { 
      reuploadToOdps(paramMap,1000L,10);//       
    } 
  } 
シナリオ1とシナリオ2には問題があります。通常の論理と再試行論理が強く結合し、再試行論理は正常な論理の実行結果に非常に依存しています。通常の論理予測結果に対して受動的再試行トリガが発生します。再試行根源についてはしばしば論理が複雑で埋没してしまいます。正しい性を再試行するのは保証が難しく、そして維持にも不利です。原因は正常な論理異常または元の推測に依存する設計を再試行することです。
3、優雅な再試行の試み:
それは参照できるソリューションが正常な論理と再試行論理の結合を実現していますか?それはプロキシ設計モードに基づく再試行ツールであり、これらのシーンを再現するために相応のツールを使用することを試みた。
1)アプリケーション命令設計モードのデカップリングが正常で、リトライロジック:
命令設計モードの具体的な定義は展開しないで詳しく述べて、主要なこの案は命令モードがオブジェクトを実行することによってインターフェースの操作ロジックを完成することができます。同時に内部パッケージ処理の再試行ロジックは、詳細を暴露しないでください。クラス図構成)

IREETryはアップロードと再テストインターフェースを約束しましたが、実際にはOdpsRetryパッケージにODPSアップロードロジックを実装し、同時に再試行機構と再試行戦略を実装します。同時にrecover方法を使用して、終了時に回復操作を行います。
また、Retryerは再試行ロジックに応答と処理を行う必要があります。Retryerは具体的な再試行処理を本当のItrryインターフェースの実現に任せます。コマンドモードを採用することにより、正常な論理と再試行論理の分離を実現し、同時に再試行者の役割を構築することにより、正常な論理と再試行論理の分離を実現し、再試行をより良い拡張性が得られます。
2)spring-retry規範正常と再試験ロジック
spring-retryはオープンソースのツールバッグで、現在利用可能なバージョンは1.1.22.RELEASEです。このツールはリトライ操作のテンプレートをカスタマイズして、リトライポリシーとリターンポリシーを設定できます。同時に再試行を実行すると、スレッドの安全を保証します。具体的なシーンの操作例は以下の通りです。

public void upload(final Map<String, Object> map) throws Exception { 
    //          
    RetryTemplate retryTemplate = new RetryTemplate(); 
    //       ,         
    SimpleRetryPolicy policy = new SimpleRetryPolicy(3, Collections.<Class<? extends Throwable>, Boolean> singletonMap(Exception.class, true)); 
    //           ,           
    FixedBackOffPolicy fixedBackOffPolicy = new FixedBackOffPolicy(); 
    fixedBackOffPolicy.setBackOffPeriod(100); 
    retryTemplate.setRetryPolicy(policy); 
    retryTemplate.setBackOffPolicy(fixedBackOffPolicy); 
    //   RetryCallback               ,                    
    final RetryCallback<Object, Exception> retryCallback = new RetryCallback<Object, Exception>() { 
      //RetryContext          ,  spring-try    
      public Object doWithRetry(RetryContext context) throws Exception { 
        System.out.println("do some thing"); 
        Exception e = uploadToOdps(map); 
        System.out.println(context.getRetryCount()); 
        throw e;//       ,       Exception   
      } 
    }; 
    //   RecoveryCallback                            
    final RecoveryCallback<Object> recoveryCallback = new RecoveryCallback<Object>() { 
      public Object recover(RetryContext context) throws Exception { 
        System.out.println("do recory operation"); 
        return null; 
      } 
    }; 
    try { 
      //  retryTemplate   execute         
      retryTemplate.execute(retryCallback, recoveryCallback); 
    } catch (Exception e) { 
      e.printStackTrace(); 
    } 
  } 
簡単に判例コードを解析して、RetryTemplateは再試行実行者の役割を担っています。SimpleRetryPolicyを設定できます。RetryTemplateはexecuteによって実行操作を提出するために、RetryCallbackとRecoveryCallbackの2つの種類のインスタンスを用意する必要があります。前者が対応するのは、再試行バック論理の例であり、パッケージが正常な機能動作であり、RecoveryCallbackが実現するのは、全体の実行動作が終了した回復動作例です。
RetryTemplateのexecuteはスレッドセキュリティであり、論理がThreadLocalを使用して各実行例のRetryContectを保存してコンテキストを実行することを実現する。
Spring-retryツールは優雅に再試験を行うことができますが、二つの友好的ではない設計があります。一つは再試験エンティティがThrowableサブクラスに限定されています。再試行対象は捕捉可能な機能異常を設計前提としていると説明していますが、あるデータオブジェクトエンティティに依存して再試験エンティティとしたいです。もう一つは、再試行の根源である断言対象は、ドWithRetryのException異常事例であり、正常内部では断言できないリターン設計である。
Spring Retryは、注釈で方法を再試行し、再試行ロジックは同期して実行することを提唱しています。再試行の「失敗」は、Throwableに対して、戻り値のある状態で再試行が必要かどうかを判定するなら、自分で判断して戻り値を表示して異常を出すしかないかもしれません。
SpringのRetryの抽象
「抽象」は各プログラマに必要な素質です。資質が平凡な私にとって、模倣と理解の優れたソースコードほど進歩的な道はないでしょう。そのために、その核心論理をもう一度書き直しました。ここでは、Spring Retryの「やり直し」の抽象を見てみます。

Spring retry関連インターフェース.jpg
  • RetryCallback:再試行が必要なトラフィックロジックをパッケージ化する
  • RecoverCallback:複数の再試行が失敗した後に実装する必要がある業務ロジック(上記のdosthWhenStill Fail)
  • RetryContext:再試行された文脈は、複数のRetryまたはRetryとRecoverの間でパラメータまたは状態を伝達するために使用されてもよい(複数のdoSthまたはdoSthとdoSthWhenStill Failの間でパラメータを伝達するために)
  • RetryOperations:再試行の基本的な枠組み(テンプレート)を定義し、RetryCallbackに入ることを要求し、任意でRecoveryCallbackに入ることができる。
  • RetryListener:典型的な「傍受者」は、再試験の異なる段階で「傍受者」(例えば、doSth、waitなどの段階で通知)
  • に通知する。
  • RetryPolicy:再試行のポリシーまたは条件は、簡単に複数回の再試行ができ、タイムアウト時間を指定して再試行することができます。
  • BackOffPolicy:再試行の返金策は、業務ロジックの実行に異常が発生した場合。再試行が必要なら、しばらく待つ必要があるかもしれません。(サーバーが忙しすぎるかもしれません。ずっと間隔をあけずに再試行すれば、サーバーを壊すかもしれません。)もちろん、この時間は0でもいいです。固定でもいいです。ランダムでもいいです。後退策は上記でwait()として表されている。
  • RetryTemplate:RetryOperationsの具体的な実装は、RetryListener、BackOffPolicy、RetryPolicyを組み合わせたものです。
  • 3)Guava-retryer分離正常と再試験ロジック
    Gava retryerツールはspring-retryと同様に、再試行者の役割を定義して正常な論理再試験を包装するものですが、Guava retryerはより優れた策略定義があり、再試行回数と再試行頻度制御をサポートする上で、複数の異常またはカスタマイズされた被験者をサポートする再試行ソース定義に対応でき、再試行機能により多くの柔軟性があります。Gava Retryerもスレッドセキュリティであり、入り口呼出しロジックはJava.util.co ncurrent.Clableのコール方法を採用しています。コード例は以下の通りです。
    
    public void uploadOdps(final Map<String, Object> map) { 
        // RetryerBuilder        retryer,                 ,               ,             
        Retryer<Boolean> retryer = RetryerBuilder.<Boolean> newBuilder() 
            .retryIfException().//        
            retryIfResult(new Predicate<Boolean>() {//          , 
          @Override 
          public boolean apply(Boolean state) {//    :  apply  true      ,            
            return true; 
          } 
        }) 
        .withStopStrategy(StopStrategies.stopAfterAttempt(5))//    5 ,             
        .withWaitStrategy(WaitStrategies.fixedWait(100L, TimeUnit.MILLISECONDS)).build();//         
     
        try { 
          //      call  ,   java.util.concurrent.Callable<V> call  ,           
          boolean result = retryer.call(new Callable<Boolean>() {  
            @Override 
            public Boolean call() throws Exception { 
              try { 
                //    :  false      ,  true         
                return uploadToOdps(map); 
              } catch (Exception e) { 
                throw new Exception(e); 
              } 
            } 
          }); 
     
        } catch (ExecutionException e) { 
        } catch (RetryException ex) { 
        } 
      } 
    コードの原理解析例:
    Retryer Buiderはfactoryの作成者であり、再試行ソースをカスタマイズして設定することができ、複数の再試行ソースをサポートすることができ、再試行回数または再試行のタイムアウト時間を設定することができ、待ち時間間隔を設定して再試行者Retryerのインスタンスを作成することができます。
    Retryer Buiderの再試行ソースは、Exceptionの異常オブジェクトとカスタムの断言オブジェクトをサポートし、retryIfExceptionとretryIfResult設定により、複数の対応と互換性があります。
    Retryer Buiderの待ち時間と再試行制限構成は、異なるポリシークラスで実装され、待ち時間特性に対しては、無間隔および固定間隔方式がサポートされる。
    Retryerは再試行者の例であり、再試行ソース動作をカプセル化しながら、call方式により動作ロジックを実行する。
    優雅な再試行の共通性と原理
    正常と再試行の優雅なデカップリングは、条件インスタンスまたは論理異常の例が両者のコミュニケーションの媒体であると再試行する。
    再試行間隔、差異性再試行戦略を約束し、再試行のタイムアウト時間を設定し、再試行の有効性と再試行の流れの安定性をさらに保証する。
    コマンド設計モードを使用して、再試行対象に対応する論理操作を依頼することで、内部実装による再試行ロジックを実現します。
    Spring-tryerとgava-tryerツールは共にスレッドセキュリティの再試行であり、同時にビジネスシーンを再現する再試行ロジックの正確性をサポートすることができます。
    エレガントな再試行の適用シーン
    機能論理には不安定な依存シーンがあり、再試行を用いて予想結果を取得する必要があり、あるいは論理の再実行を試みてもすぐには終わらない。例えばリモートインターフェースのアクセス、データロードのアクセス、データアップロードのチェックなどです。
    異常シーンの存在にはシーンを再試行する必要があり、通常の論理と再試行論理を結合したい。
    データ媒体相互作用に基づく必要がある場合には、ポーリング検出を再試行して論理シーンを実行することも、リトライ方式を考慮してもよい。
    締め括りをつける
    以上がJavaプログラミングRetry再試行機構の実例について詳しく説明した内容です。興味のある方は引き続き当駅の他のテーマを参照してください。友達のサポートに感謝します。