Spring Cloud Netflixのガイド– Hystrix
1. 概要
このチュートリアルでは、フォールトトレランスライブラリであるSpring Cloud Netflix Hystrixについて説明します。 ライブラリを使用して、Circuit Breakerエンタープライズパターンを実装します。これは、アプリケーションのさまざまなレベルでの障害のカスケードに対する戦略を説明しています。
原理は電子機器に類似しています。Hystrixは、関連サービスへの呼び出しが失敗するメソッドを監視しています。 そのような障害がある場合、回線を開き、コールをフォールバックメソッドに転送します。
ライブラリは、しきい値までの障害を許容します。 それを超えると、回路は開いたままになります。 つまり、将来の失敗を防ぐために、後続のすべての呼び出しをフォールバックメソッドに転送します。 This creates a time buffer for the related service to recover from its failing state.
2. RESTプロデューサー
Circuit Breakerパターンを示すシナリオを作成するには、最初にサービスが必要です。 次のステップで作成するHystrix対応の「REST Consumer」のデータを提供するため、「RESTProducer」という名前を付けます。
spring-boot-starter-web依存関係を使用して、新しいMavenプロジェクトを作成しましょう。
org.springframework.boot
spring-boot-starter-web
1.4.0.RELEASE
プロジェクト自体は意図的にシンプルに保たれています。 これは、このインターフェイスを実装するString,、@RestController、および@SpringBootApplicationを返す1つの@RequestMapping注釈付きGETメソッドを備えたコントローラーインターフェイスで構成されます。
インターフェースから始めます。
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は使用しません。
さらに、後で紹介するクライアントアプリケーションから「REST Producer」を検索できるようにアプリケーション名を定義しています。 次の内容でapplication.propertiesを作成しましょう。
server.port=9090
spring.application.name=rest-producer
これで、curlを使用して「REST Producer」をテストできます。
$> curl http://localhost:9090/greeting/Cid
Hello Cid!
3. HystrixのRESTコンシューマー
デモシナリオでは、RestTemplateとHystrixを使用して前のステップのRESTサービスを使用するWebアプリケーションを実装します。 簡単にするために、これを「REST Consumer」と呼びます。
したがって、依存関係としてhttps://search.maven.org/classic/#search%7Cgav%7C1%7Cg%3A%22org.springframework.cloud%22%20AND%20a%3A%22spring-cloud-starter-hystrix%22, spring-boot-starter-webと_spring-boot-starter-thymeleafを使用して新しいMavenプロジェクトを作成します。
org.springframework.cloud
spring-cloud-starter-hystrix
1.1.5.RELEASE
org.springframework.boot
spring-boot-starter-web
1.4.0.RELEASE
org.springframework.boot
spring-boot-starter-thymeleaf
1.4.0.RELEASE
Circuit Breakerが機能するために、Hystixは@Component or @Serviceアノテーション付きクラスをスキャンして@HystixCommandアノテーション付きメソッドを探し、そのプロキシを実装してその呼び出しを監視します。
最初に@Serviceクラスを作成し、これを@Controllerに注入します。 web-application using Thymeleaf,を作成しているので、ビューとして機能する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アノテーションは、互換性のあるCircuit Breaker実装のクラスパスをスキャンします。
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テンプレートです。
Greetings from Hystrix
アプリケーションが定義されたポートでリッスンしていることを確認するために、application.propertiesファイルに以下を配置します。
server.port=8080
Hystixサーキットブレーカーの動作を確認するために、「REST Consumer」を起動し、ブラウザーでhttp://localhost:8080/get-greeting/Cidを指定します。 通常の状況では、次が表示されます。
Hello Cid!
‘REST Producer’の失敗をシミュレートするには、単に停止します。ブラウザの更新が完了すると、@Serviceのフォールバックメソッドから返される一般的なメッセージが表示されます。
Hello User!
4. HystrixおよびFeignのRESTコンシューマー
ここで、前の手順のプロジェクトを変更して、SpringRestTemplateの代わりにSpring Netflix Feignを宣言型RESTクライアントとして使用します。
利点は、後でFeign Clientインターフェースを簡単にリファクタリングして、サービス検出にSpring Netflix Eurekaを使用できることです。
新しいプロジェクトを開始するには、「REST Consumer」のコピーを作成し、「RESTプロデューサー」とspring-cloud-starter-feignを依存関係として追加します。
com.example.spring.cloud
spring-cloud-hystrix-rest-producer
1.0.0-SNAPSHOT
org.springframework.cloud
spring-cloud-starter-feign
1.1.5.RELEASE
これで、GreetingControllerを使用してFeignクライアントを拡張できるようになりました。 Hystrixフォールバックを、@Componentアノテーションが付けられた静的内部クラスとして実装します。
または、このフォールバッククラスのインスタンスを返す@Beanアノテーション付きメソッドを定義することもできます。
@FeignClientのnameプロパティは必須です。 このプロパティが指定されている場合は、Eureka ClientまたはURLを介したサービス検出によってアプリケーションを検索するために使用されます。 Spring Netflix Eurekaをサービス検出に使用する方法の詳細については、at this articleを参照してください。
@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!";
}
}
}
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対応の「REST Consumer」をテストします。 期待される結果は同じはずです。
5. Hystrixによるキャッシュフォールバック
次に、HystrixをSpring Cloudプロジェクトに追加します。 このクラウドプロジェクトには、データベースと通信して書籍の評価を取得する評価サービスがあります。
データベースが需要のあるリソースであり、その応答待ち時間が時間によって変化する場合や、時間によって利用できない場合があると仮定しましょう。 このシナリオは、HystrixCircuit-Breakerがデータのキャッシュにフォールバックすることで処理します。
5.1. セットアップと構成
spring-cloud-starter-hystrixの依存関係を評価モジュールに追加しましょう:
org.springframework.cloud
spring-cloud-starter-hystrix
評価がデータベースに挿入/更新/削除されると、Repositoryを使用して同じものをRedisキャッシュに複製します。 Redisについて詳しく知りたい場合は、this article.を確認してください。
RatingServiceを更新して、Hystrixコマンドのデータベースクエリメソッドを@HystrixCommandでラップし、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アドバイスを、Hystrix AOPアドバイスよりも優先度が低くなるように調整しました。
@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’sトランザクションAOPアドバイスをHystrix AOPアドバイスよりも優先度が低くなるように調整しました。
5.2. Hystrixフォールバックのテスト
回路を構成したので、リポジトリが相互作用するH2データベースを停止することで回路をテストできます。 ただし、最初に、H2インスタンスを組み込みデータベースとして実行するのではなく、外部プロセスとして実行してみましょう。
H2 library(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)
モジュールのデータソースURLをrating-service.propertiesで更新して、このH2サーバーを指すようにします。
spring.datasource.url = jdbc:h2:tcp://localhost/~/ratings
Spring-Cloudシリーズの以前のarticleで指定されたとおりにサービスを開始し、実行している外部H2インスタンスを停止することで各書籍の評価をテストできます。
H2データベースに到達できない場合、Hystrixは自動的にRedisにフォールバックして、各本の評価を読み取ることがわかりました。 このユースケースを示すソースコードは、hereにあります。
6. スコープの使用
通常、@HytrixCommandアノテーション付きメソッドは、スレッドプールコンテキストで実行されます。 ただし、@SessionScopeや@RequestScopeなどのローカルスコープで実行する必要がある場合もあります。 これは、コマンドアノテーションに引数を与えることで実行できます。
@HystrixCommand(fallbackMethod = "getSomeDefault", commandProperties = {
@HystrixProperty(name = "execution.isolation.strategy", value = "SEMAPHORE")
})
7. Hystrixダッシュボード
Hystrixの優れたオプション機能は、ダッシュボードでそのステータスを監視する機能です。
これを有効にするには、「REST Consumer」のpom.xmlにspring-cloud-starter-hystrix-dashboardとspring-boot-starter-actuatorを配置します。
org.springframework.cloud
spring-cloud-starter-hystrix-dashboard
1.1.5.RELEASE
org.springframework.boot
spring-boot-starter-actuator
1.4.0.RELEASE
前者は@Configurationに@EnableHystrixDashboardの注釈を付けることで有効にする必要があり、後者はWebアプリケーション内で必要なメトリックを自動的に有効にします。
アプリケーションの再起動が完了したら、ブラウザでhttp://localhost:8080/hystrixを指定し、「hystrix.stream」の指標URLを入力して、監視を開始します。
最後に、次のようなものが表示されます。
「hystrix.stream」を監視することは問題ありませんが、複数のHystrix対応アプリケーションを監視する必要がある場合は、不便になります。 この目的のために、Spring CloudはTurbineと呼ばれるツールを提供します。このツールは、ストリームを集約して1つのHystrix Dashboardに表示できます。
Turbineの構成はこの記事の範囲を超えていますが、その可能性についてはここで説明する必要があります。 したがって、Turbine Streamを使用して、メッセージングを介してこれらのストリームを収集することもできます。
8. 結論
これまで見てきたように、Spring RestTemplateまたはSpring Netflix FeignとともにSpring Netflix Hystrixを使用してCircuit Breakerパターンを実装できるようになりました。
これは、「静的」または「デフォルト」データを使用してフォールバックを含むサービスを利用でき、このデータの使用状況を監視できることを意味します。
いつものように、ソースはGitHubにあります。