1. 概要

このチュートリアルでは、フォールトトレランスライブラリであるSpring CloudNetflixHystrixについて説明します。 ライブラリを使用して、Circuit Breakerエンタープライズパターンを実装します。これは、アプリケーションのさまざまなレベルでの障害のカスケードに対する戦略を説明しています。

原理は電子機器に類似しています。Hystrixは、関連サービスへの呼び出しが失敗するメソッドを監視しています。 このような障害が発生した場合は、回線が開かれ、コールがフォールバック方式に転送されます。

ライブラリは、しきい値までの障害を許容します。 それを超えると、回路は開いたままになります。 つまり、将来の障害を防ぐために、後続のすべての呼び出しをフォールバックメソッドに転送します。 これにより、関連サービスが障害状態から回復するためのタイムバッファーが作成されます。

2. RESTプロデューサー

サーキットブレーカーのパターンを示すシナリオを作成するには、最初にサービスが必要です。 次のステップで作成するHystrix対応の「RESTコンシューマー」のデータを提供するため、「RESTプロデューサー」という名前を付けます。

spring-boot-starter-web 依存関係を使用して、新しいMavenプロジェクトを作成しましょう。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <version>2.2.6.RELEASE</version>
</dependency>

プロジェクト自体は意図的にシンプルに保たれています。 これは、1つの @RequestMapping 注釈付きGETメソッドが、このインターフェイスを実装する String、 @RestController 、および@SpringBootApplication[を返すコントローラーインターフェイスで構成されます。 X216X]。

インターフェイスから始めましょう:

public interface GreetingController {
    @GetMapping("/greeting/{username}")
    String greeting(@PathVariable("username") String username);
}

そして実装:

@RestController
public class GreetingControllerImpl implements GreetingController {
 
    @Override
    public String greeting(@PathVariable("username") String username) {
        return String.format("Hello %s!\n", username);
    }
}

次に、メインのアプリケーションクラスを書き留めます。

@SpringBootApplication
public class RestProducerApplication {
    public static void main(String[] args) {
        SpringApplication.run(RestProducerApplication.class, args);
    }
}

このセクションを完了するために残された唯一のことは、リッスンするアプリケーションポートを構成することです。 次の手順で説明するアプリケーション用にポートを予約したままにする必要があるため、デフォルトのポート8080は使用しません。

さらに、後で紹介するクライアントアプリケーションからプロデューサーを検索できるようにアプリケーション名を定義しています。

次に、application.propertiesファイルで9090のポートとrest-producerの名前を指定しましょう。

server.port=9090
spring.application.name=rest-producer

これで、cURLを使用してプロデューサーをテストできます。

$> curl http://localhost:9090/greeting/Cid
Hello Cid!

3. Hystrixを使用したRESTコンシューマー

デモンストレーションシナリオでは、RestTemplateHystrixを使用して前のステップのRESTサービスを使用するWebアプリケーションを実装します。 簡単にするために、これを「RESTコンシューマー」と呼びます。

したがって、 spring-cloud-starter-hystrix 、spring-boot-starter-web 、およびspring-boot-starter-thymeleafを使用して新しいMavenプロジェクトを作成します。依存関係として:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-hystrix</artifactId>
    <version>1.4.7.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <version>2.2.6.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
    <version>2.2.6.RELEASE</version>
</dependency>

Circuit Breakerが機能するために、Hystixは@Componentまたは@Service注釈付きクラスをスキャンして@HystixCommand 注釈付きメソッドを探し、そのプロキシを実装してその呼び出しを監視します。

最初に@Serviceクラスを作成します。これは、@Controllerに挿入されます。 Thymeleafを使用してWebアプリケーションを構築しているため、ビューとして機能するHTMLテンプレートも必要です。

これは、関連するフォールバックメソッドを使用して@HystrixCommandを実装する注入可能な@Serviceになります。 このフォールバックでは、元のフォールバックと同じ署名を使用する必要があります。

@Service
public class GreetingService {
    @HystrixCommand(fallbackMethod = "defaultGreeting")
    public String getGreeting(String username) {
        return new RestTemplate()
          .getForObject("http://localhost:9090/greeting/{username}", 
          String.class, username);
    }
 
    private String defaultGreeting(String username) {
        return "Hello User!";
    }
}

RestConsumerApplicationがメインのアプリケーションクラスになります。 @EnableCircuitBreaker アノテーションは、クラスパスをスキャンして、互換性のあるサーキットブレーカーの実装を探します。

Hystrixを明示的に使用するには、このクラスに@EnableHystrixでアノテーションを付ける必要があります。

@SpringBootApplication
@EnableCircuitBreaker
public class RestConsumerApplication {
    public static void main(String[] args) {
        SpringApplication.run(RestConsumerApplication.class, args);
    }
}

GreetingServiceを使用してコントローラーをセットアップします。

@Controller
public class GreetingController {
 
    @Autowired
    private GreetingService greetingService;
 
    @GetMapping("/get-greeting/{username}")
    public String getGreeting(Model model, @PathVariable("username") String username) {
        model.addAttribute("greeting", greetingService.getGreeting(username));
        return "greeting-view";
    }
}

そして、これがHTMLテンプレートです。

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
    <head>
        <title>Greetings from Hystrix</title>
    </head>
    <body>
        <h2 th:text="${greeting}"/>
    </body>
</html>

アプリケーションが定義されたポートでリッスンしていることを確認するために、application.propertiesファイルに以下を配置します。

server.port=8080

Hystixサーキットブレーカーの動作を確認するために、コンシューマーを起動し、ブラウザーで http:// localhost:8080 / get-greeting /Cidを指定しています。 通常の状況では、以下が表示されます。

Hello Cid!

プロデューサーの障害をシミュレートするために、単に停止します。ブラウザーの更新が終了すると、@Serviceのフォールバックメソッドから返される一般的なメッセージが表示されます。

Hello User!

4. HystrixとFeignを使用したRESTコンシューマー

ここで、前の手順のプロジェクトを変更して、Spring RestTemplateの代わりにSpringNetflixFeignを宣言型RESTクライアントとして使用します。

利点は、後でFeign Clientインターフェイスを簡単にリファクタリングして、サービス検出に Spring NetflixEurekaを使用できることです。

新しいプロジェクトを開始するには、コンシューマーのコピーを作成し、プロデューサーとspring-cloud-starter-feignを依存関係として追加します。

<dependency>
    <groupId>com.baeldung.spring.cloud</groupId>
    <artifactId>spring-cloud-hystrix-rest-producer</artifactId>
    <version>1.0.0-SNAPSHOT</version>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-feign</artifactId>
    <version>1.1.5.RELEASE</version>
</dependency>

これで、GreetingControllerを使用してFeignクライアントを拡張できるようになりました。 Hystrix フォールバックを、@Componentアノテーションが付けられた静的内部クラスとして実装します。

または、このフォールバッククラスのインスタンスを返す@Bean注釈付きメソッドを定義することもできます。

@FeignClientのnameプロパティは必須です。 このプロパティが指定されている場合、Eurekaクライアントを介したサービス検出またはURLのいずれかによってアプリケーションを検索するために使用されます。

@FeignClient(
  name = "rest-producer"
  url = "http://localhost:9090", 
  fallback = GreetingClient.GreetingClientFallback.class
)
public interface GreetingClient extends GreetingController {
     
    @Component
    public static class GreetingClientFallback implements GreetingController {
 
        @Override
        public String greeting(@PathVariable("username") String username) {
            return "Hello User!";
        }
    }
}

Spring Netflix Eurekaをサービス検出に使用する方法の詳細については、この記事をご覧ください。

RestConsumerFeignApplication では、Feign統合を有効にするための追加のアノテーション、実際には@EnableFeignClientsをメインアプリケーションクラスに配置します。

@SpringBootApplication
@EnableCircuitBreaker
@EnableFeignClients
public class RestConsumerFeignApplication {
     
    public static void main(String[] args) {
        SpringApplication.run(RestConsumerFeignApplication.class, args);
    }
}

以前に挿入された@Serviceではなく、自動配線されたFeign Clientを使用するようにコントローラーを変更して、挨拶を取得します。

@Controller
public class GreetingController {
    @Autowired
    private GreetingClient greetingClient;
 
    @GetMapping("/get-greeting/{username}")
    public String getGreeting(Model model, @PathVariable("username") String username) {
        model.addAttribute("greeting", greetingClient.greeting(username));
        return "greeting-view";
    }
}

この例を前の例と区別するために、application.propertiesのアプリケーションリスニングポートを変更します。

server.port=8082

最後に、前のセクションのように、このFeign対応のコンシューマーをテストします。 期待される結果は同じであるはずです。

5. Hystrixによるキャッシュフォールバック

次に、 SpringCloudプロジェクトにHystrixを追加します。 このクラウドプロジェクトでは、データベースと通信して書籍の評価を取得する評価サービスがあります。

私たちのデータベースが需要のあるリソースであり、その応答待ち時間が時間とともに変化するか、時間内に利用できない可能性があると仮定しましょう。 このシナリオは、HystrixCircuitBreakerがデータのキャッシュにフォールバックすることで処理します。

5.1. セットアップと構成

spring-cloud-starter-hystrix依存関係を評価モジュールに追加しましょう。

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>

評価がデータベースに挿入/更新/削除されると、リポジトリを使用して同じものをRedisキャッシュに複製します。 Redisの詳細については、この記事を確認してください。

RatingService を更新して、データベースクエリメソッドを @HystrixCommand を使用してHystrixコマンドでラップし、Redisからの読み取りへのフォールバックを使用して構成します。

@HystrixCommand(
  commandKey = "ratingsByIdFromDB", 
  fallbackMethod = "findCachedRatingById", 
  ignoreExceptions = { RatingNotFoundException.class })
public Rating findRatingById(Long ratingId) {
    return Optional.ofNullable(ratingRepository.findOne(ratingId))
      .orElseThrow(() -> 
        new RatingNotFoundException("Rating not found. ID: " + ratingId));
}

public Rating findCachedRatingById(Long ratingId) {
    return cacheRepository.findCachedRatingById(ratingId);
}

フォールバックメソッドは、ラップされたメソッドと同じシグネチャを持ち、同じクラスに存在する必要があることに注意してください。 これで、 findRatingById が失敗するか、指定されたしきい値を超えて遅延すると、HystrixはfindCachedRatingById。にフォールバックします。

Hystrix機能はAOPアドバイスとして透過的に注入されるため、Springのトランザクションアドバイスなどの他のアドバイスがある場合は、アドバイスがスタックされる順序を調整する必要があります。 ここでは、SpringのトランザクションAOPアドバイスを調整して、HystrixAOPアドバイスよりも優先順位を低くしています。

@EnableHystrix
@EnableTransactionManagement(
  order=Ordered.LOWEST_PRECEDENCE, 
  mode=AdviceMode.ASPECTJ)
public class RatingServiceApplication {
    @Bean
    @Primary
    @Order(value=Ordered.HIGHEST_PRECEDENCE)
    public HystrixCommandAspect hystrixAspect() {
        return new HystrixCommandAspect();
    }
 
    // other beans, configurations
}

ここでは、SpringのトランザクションAOPアドバイスを調整して、HystrixAOPアドバイスよりも優先順位を低くしています。

5.2. Hystrixフォールバックのテスト

回路を構成したので、リポジトリが相互作用するH2データベースを停止することで回路をテストできます。 ただし、最初に、H2インスタンスを組み込みデータベースとして実行するのではなく、外部プロセスとして実行してみましょう。

H2ライブラリ( h2-1.4.193.jar )を既知のディレクトリにコピーして、H2サーバーを起動してみましょう。

>java -cp h2-1.4.193.jar org.h2.tools.Server -tcp
TCP server running at tcp://192.168.99.1:9092 (only local connections)

次に、 ratio-service.properties のモジュールのデータソースURLを更新して、このH2サーバーを指すようにします。

spring.datasource.url = jdbc:h2:tcp://localhost/~/ratings

Spring Cloudシリーズの以前の記事で示したようにサービスを開始し、実行している外部H2インスタンスを停止することで各書籍の評価をテストできます。

H2データベースにアクセスできない場合、Hystrixは自動的にRedisにフォールバックして、各本の評価を読み取ることがわかりました。 このユースケースを示すソースコードは、ここにあります。

6. スコープの使用

通常、 @HytrixCommand 注釈付きメソッドは、スレッドプールコンテキストで実行されます。 ただし、@SessionScope@RequestScopeなど、ローカルスコープで実行する必要がある場合もあります。 これは、コマンド注釈に引数を与えることで実行できます。

@HystrixCommand(fallbackMethod = "getSomeDefault", commandProperties = {
  @HystrixProperty(name = "execution.isolation.strategy", value = "SEMAPHORE")
})

7. Hystrixダッシュボード

Hystrixの優れたオプション機能は、ダッシュボードでそのステータスを監視する機能です。

これを有効にするには、spring-cloud-starter-hystrix-dashboardspring-boot-starter-actuatorpom.xmlに配置します。消費者:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
    <version>1.4.7.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
    <version>2.2.6.RELEASE</version>
</dependency>

前者は@Configuration@EnableHystrixDashboardの注釈を付けることで有効にする必要があり、後者はWebアプリケーション内で必要なメトリックを自動的に有効にします。

アプリケーションの再起動が完了したら、ブラウザーで http:// localhost:8080 / hystrix を指定し、HystrixストリームのメトリックURLを入力して、監視を開始します。

最後に、次のようなものが表示されます。

Hystrixストリームの監視は問題ありませんが、複数のHystrix対応アプリケーションを監視する必要がある場合は、不便になります。 この目的のために、Spring CloudはTurbineと呼ばれるツールを提供します。このツールは、ストリームを集約して1つのHystrixダッシュボードに表示できます。

Turbineの構成はこの記事の範囲を超えていますが、その可能性についてはここで言及する必要があります。 したがって、Turbineストリームを使用して、メッセージングを介してこれらのストリームを収集することもできます。

8. 結論

これまで見てきたように、SpringNetflixHystrixとSpringRestTemplateまたはSpringNetflixFeignのいずれかを使用して、サーキットブレーカーパターンを実装できるようになりました。

これは、デフォルトのデータを使用してフォールバックを含むサービスを利用でき、このデータの使用状況を監視できることを意味します。

いつものように、ソースはGitHubにあります。