このガイドでは、Netflix Hystrix フォールトトレランスライブラリを使用して、失敗する可能性のあるメソッド呼び出しにサーキットブレーカーを適用するプロセスについて説明します。

構築するもの

メソッド呼び出しが失敗したときに機能を適切に低下させるために、サーキットブレーカーパターン (英語) を使用するマイクロサービスアプリケーションを構築します。サーキットブレーカーパターンを使用すると、関連するサービスに障害が発生してもマイクロサービスの動作を継続させることができ、障害の連鎖を防ぎ、障害のあるサービスが回復するまでの時間を確保できます。

必要なもの

このガイドを完了する方法

ほとんどの Spring 入門ガイドと同様に、最初から始めて各ステップを完了するか、すでに慣れている場合は基本的なセットアップステップをバイパスできます。いずれにしても、最終的に動作するコードになります。

最初から始めるには、Spring Initializr から開始に進みます。

基本スキップするには、次の手順を実行します。

完了したときは、gs-circuit-breaker/complete のコードに対して結果を確認できます。

Spring Initializr から開始

すべての Spring アプリケーションの場合、Spring Initializr (英語) から開始する必要があります。Initializr は、アプリケーションに必要なすべての依存関係をすばやく取り込む方法を提供し、多くのセットアップを行います。

このガイドには 2 つのアプリケーションが必要です。最初のアプリケーション(単純な書店サイト)では、Web 依存関係のみが必要です。

次のリストは、Maven を選択したときに作成される pom.xml ファイル(構成サービス用)を示しています。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.3.2.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.example</groupId>
	<artifactId>circuit-breaker-bookstore</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>circuit-breaker-bookstore</name>
	<description>Demo project for Spring Boot</description>

	<properties>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
			<exclusions>
				<exclusion>
					<groupId>org.junit.vintage</groupId>
					<artifactId>junit-vintage-engine</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

次のリストは、Gradle を選択したときに作成される build.gradle ファイル(構成サービス用)を示しています。

plugins {
	id 'org.springframework.boot' version '2.3.2.RELEASE'
	id 'io.spring.dependency-management' version '1.0.9.RELEASE'
	id 'java'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'

repositories {
	mavenCentral()
}

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-web'
	testImplementation('org.springframework.boot:spring-boot-starter-test') {
		exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
	}
}

test {
	useJUnitPlatform()
}

2 番目のアプリケーション(Hystrix 回路ブレーカーを使用する読み取りアプリケーション)には、Web と Hystrix の依存関係が必要です。

次のリストは、Maven を選択したときに作成される pom.xml ファイル(構成クライアント用)を示しています。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.3.2.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.example</groupId>
	<artifactId>circuit-breaker-reading</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>circuit-breaker-reading</name>
	<description>Demo project for Spring Boot</description>

	<properties>
		<java.version>1.8</java.version>
		<spring-cloud.version>Hoxton.M3</spring-cloud.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
			<exclusions>
				<exclusion>
					<groupId>org.junit.vintage</groupId>
					<artifactId>junit-vintage-engine</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
	</dependencies>

	<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>org.springframework.cloud</groupId>
				<artifactId>spring-cloud-dependencies</artifactId>
				<version>${spring-cloud.version}</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
		</dependencies>
	</dependencyManagement>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

	<repositories>
		<repository>
			<id>spring-milestones</id>
			<name>Spring Milestones</name>
			<url>https://repo.spring.io/milestone</url>
		</repository>
	</repositories>

</project>

次のリストは、Gradle を選択したときに作成される build.gradle ファイル(構成クライアント用)を示しています。

plugins {
	id 'org.springframework.boot' version '2.3.2.RELEASE'
	id 'io.spring.dependency-management' version '1.0.9.RELEASE'
	id 'java'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'

repositories {
	mavenCentral()
}

ext {
	set('springCloudVersion', "Hoxton.SR1")
}

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-web'
	implementation 'org.springframework.cloud:spring-cloud-starter-netflix-hystrix'
	testImplementation('org.springframework.boot:spring-boot-starter-test') {
		exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
	}
}

dependencyManagement {
	imports {
		mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
	}
}

test {
	useJUnitPlatform()
}
便宜上、書店プロジェクトと読書プロジェクトの両方のビルドに使用できるビルドファイル(pom.xml ファイルと build.gradle ファイル)を、完全な初期プロジェクト(bookstore と reading ディレクトリの上の 1 つのディレクトリ)の最上部に提供しています。すぐに。そこに Maven および Gradle ラッパーも追加しました。

サーバーマイクロサービスアプリケーションをセットアップする

Bookstore サービスには単一のエンドポイントがあります。それは /recommended でアクセス可能であり、(簡単にするために) String として推奨読書リストを返します。

BookstoreApplication.java でメインクラスを作成する必要があります。次のリストのようになります(bookstore/src/main/java/com/example/circuitbreakerbookstore/CircuitBreakerBookstoreApplication.java から)。

package com.example.circuitbreakerbookstore;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RequestMapping;

@RestController
@SpringBootApplication
public class CircuitBreakerBookstoreApplication {

  @RequestMapping(value = "/recommended")
  public String readingList(){
  return "Spring in Action (Manning), Cloud Native Java (O'Reilly), Learning Spring Boot (Packt)";
  }

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

@RestController アノテーションは、BookstoreApplication が REST コントローラークラスであることを示し、このクラスの @RequestMapping メソッドが @ResponseBody でアノテーション付けされているかのように動作することを保証します。つまり、このクラスの @RequestMapping メソッドの戻り値は、元の型から自動的かつ適切に変換され、レスポンス本文に直接書き込まれます。

このアプリケーションを、消費アプリケーションと一緒にローカルで実行します。その結果、src/main/resources/application.properties で server.port を設定して、Bookstore サービスが実行中に消費アプリケーションと競合しないようにする必要があります。次のリスト(bookstore/src/main/resources/application.properties から)は、その方法を示しています。

server.port=8090

クライアントマイクロサービスアプリケーションをセットアップする

読書アプリケーションは、書店アプリケーションの消費者(モデリング訪問者)になります。/to-read で閲覧リストを表示でき、その閲覧リストは書店サービスアプリケーションから取得されます。次の例(reading/src/main/java/com/example/circuitbreakerreading/CircuitBreakerReadingApplication.java から)は、このクラスを示しています。

package com.example.circuitbreakerreading;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.web.client.RestTemplate;

@EnableCircuitBreaker
@RestController
@SpringBootApplication
public class CircuitBreakerReadingApplication {

  @Autowired
  private BookService bookService;

  @Bean
  public RestTemplate rest(RestTemplateBuilder builder) {
  return builder.build();
  }

  @RequestMapping("/to-read")
  public String toRead() {
  return bookService.readingList();
  }

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

書店からリストを取得するには、Spring の RestTemplate テンプレートクラスを使用できます。RestTemplate は書店サービスの URL に HTTP GET リクエストを行い、結果を String として返します。(Spring を使用して RESTful サービスを使用する方法の詳細については、RESTful Web サービスの使用ガイドを参照してください)これを行うには、server.port プロパティを reading/src/main/resources/application.properties に追加する必要があります。次のリストを参照してください。

server.port=8080

ブラウザで、閲覧アプリケーションの /to-read エンドポイントにアクセスし、閲覧リストを表示できるようになりました。ただし、ブックストアアプリケーションに依存しているため、何かが発生したり、読書アプリケーションがブックストアにアクセスできない場合、リストは表示されず、ユーザーには厄介な HTTP 500 エラーメッセージが表示されます。

サーキットブレーカーパターンを適用する

Netflix の Hystrix ライブラリは、サーキットブレーカーパターンの実装を提供します。回路ブレーカーをメソッドに適用すると、Hystrix はそのメソッドへの失敗した呼び出しを監視し、失敗がしきい値に達すると、Hystrix は回路を開いて後続の呼び出しが自動的に失敗するようにします。回線が開いている間、Hystrix は呼び出しをメソッドにリダイレクトし、指定されたフォールバックメソッドに渡されます。

Spring Cloud Netflix Hystrix は、@HystrixCommand アノテーションが付けられたメソッドを探し、サーキットブレーカーに接続されたプロキシでそのメソッドをラップして、Hystrix が監視できるようにします。現在、これは @Component または @Service でマークされたクラスでのみ機能します。読み取りアプリケーションの src/main/java/com/example/circuitbreakerreading に、新しいクラス(BookService と呼ばれる)を追加する必要があります。

RestTemplate は、作成時に BookService のコンストラクターに注入されます。次のリスト(reading/src/main/java/com/example/circuitbreakerreading/BookService.java からは BookService クラスを示しています):

package com.example.circuitbreakerreading;

import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.net.URI;

@Service
public class BookService {

  private final RestTemplate restTemplate;

  public BookService(RestTemplate rest) {
  this.restTemplate = rest;
  }

  @HystrixCommand(fallbackMethod = "reliable")
  public String readingList() {
  URI uri = URI.create("http://localhost:8090/recommended");

  return this.restTemplate.getForObject(uri, String.class);
  }

  public String reliable() {
  return "Cloud Native Java (O'Reilly)";
  }

}

@HystrixCommand を元の readingList() メソッドに適用しました。また、新しいメソッド reliable() もあります。@HystrixCommand アノテーションには、fallbackMethod として reliable があります。何らかの理由で、Hystrix が readingList() で回路を開くと、ユーザー向けの優れた(短い場合)プレースホルダー読み取りリストが用意されています。

メインクラス ReadingApplication では、RestTemplate Bean を作成し、BookService を挿入して、読み取りリスト用に呼び出す必要があります。次の例(reading/src/main/java/com/example/circuitbreakerreading/CircuitBreakerReadingApplication.java から)は、そのメソッドを示しています。

package com.example.circuitbreakerreading;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.web.client.RestTemplate;

@EnableCircuitBreaker
@RestController
@SpringBootApplication
public class CircuitBreakerReadingApplication {

  @Autowired
  private BookService bookService;

  @Bean
  public RestTemplate rest(RestTemplateBuilder builder) {
  return builder.build();
  }

  @RequestMapping("/to-read")
  public String toRead() {
  return bookService.readingList();
  }

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

これで、Bookstore サービスからリストを取得するために、bookService.readingList() を呼び出すことができます。最後のアノテーション @EnableCircuitBreaker も追加する必要があります。このアノテーションは、Spring Cloud に、読み取りアプリケーションがサーキットブレーカーを使用し、その監視、開始、および終了を可能にすることを伝えます(この場合、Hystrix によって提供される動作)。

試してみましょう

サーキットブレーカーをテストするには、書店サービスと読書サービスの両方を実行してから、localhost:8080/to-read で読書サービスのブラウザーを開きます。次のリストが示すように、完全な推奨読書リストが表示されるはずです。

Spring in Action (Manning), Cloud Native Java (O'Reilly), Learning Spring Boot (Packt)

次に、書店アプリケーションを停止します。リストのソースはなくなりましたが、Hystrix と Spring Cloud Netflix のおかげで、信頼できる短縮リストができあがりました。以下が表示されるはずです。

Cloud Native Java (O'Reilly)

要約

おめでとう!回路ブレーカーパターンを使用して連鎖障害から保護し、障害が発生する可能性のあるコールにフォールバック動作を提供する Spring アプリケーションを開発しました。

関連事項

次のガイドも役立ちます。

新しいガイドを作成したり、既存のガイドに貢献したいですか? 投稿ガイドラインを参照してください (GitHub)

すべてのガイドは、コード用の ASLv2 ライセンス、およびドキュメント用の Attribution、NoDerivatives クリエイティブコモンズライセンス (英語) でリリースされています。