クラウドネイティブ は、継続的デリバリーと価値主導型開発の分野におけるベストプラクティスの容易な導入を促進するアプリケーション開発のスタイルです。関連する分野として 12 要素アプリケーション (英語) の構築が挙げられます。この分野では、宣言型プログラミングや管理と監視などを使用して、開発実践が配信と運用のゴールに沿って調整されます。Spring Cloud は、さまざまな具体的な方法でこれらの開発スタイルを促進します。開始点は、分散システム内のすべてのコンポーネントに簡単にアクセスできる必要がある一連の機能です。
これらの機能の多くは Spring Boot でカバーされており、その上に Spring Cloud が構築されています。さらにいくつかの機能は、Spring Cloud Context と Spring Cloud Commons という 2 つのライブラリとして Spring Cloud によって提供されます。Spring Cloud コンテキストは、Spring Cloud アプリケーションの ApplicationContext
にユーティリティと特別なサービス (ブートストラップコンテキスト、暗号化、リフレッシュスコープ、および環境エンドポイント) を提供します。Spring Cloud Commons は、さまざまな Spring Cloud 実装 (Spring Cloud Netflix や Spring Cloud Consul など) で使用される一連の抽象化と共通クラスです。
「不正なキーサイズ」による例外が発生し、Sun の JDK を使用している場合は、Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction ポリシーファイルをインストールする必要があります。詳細については、次のリンクを参照してください。
使用する JRE/JDK x64/x86 のバージョンに応じて、ファイルを JDK/jre/lib/security フォルダーに抽出します。
Spring Cloud は、制限のない Apache 2.0 ライセンスでリリースされています。ドキュメントのこのセクションに貢献したい場合、またはエラーを見つけた場合は、プロジェクトのソースコードと課題追跡ツールを {docslink}[github] で見つけることができます。 |
1. Spring Cloud コンテキスト: アプリケーションコンテキストサービス
Spring Boot は、Spring でアプリケーションを構築する方法について独自の見解を持っています。たとえば、共通の構成ファイル用の従来の場所があり、共通の管理および監視タスク用のエンドポイントがあります。Spring Cloud はそ上に構築され、システム内の多くのコンポーネントが使用する、場合によって必要となるいくつかの機能を追加します。
1.1. ブートストラップアプリケーションコンテキスト
Spring Cloud アプリケーションは、メインアプリケーションの親コンテキストである「ブートストラップ」コンテキストを作成することによって動作します。このコンテキストは、外部ソースから構成プロパティをロードし、ローカルの外部構成ファイル内のプロパティを復号化するロールを果たします。2 つのコンテキストは、Spring アプリケーションの外部プロパティのソースである Environment
を共有します。デフォルトでは、ブートストラッププロパティ (bootstrap.properties
ではなく、ブートストラップフェーズ中に読み込まれるプロパティ) は高い優先順位で追加されるため、ローカル構成でオーバーライドすることはできません。
ブートストラップコンテキストは、メインアプリケーションコンテキストとは異なる外部構成の検索規則を使用します。application.yml
(または .properties
) の代わりに bootstrap.yml
を使用して、ブートストラップとメインコンテキストの外部構成を適切に分離することができます。次のリストは例を示しています。
spring: application: name: foo cloud: config: uri: ${SPRING_CONFIG_URI:http://localhost:8888}
アプリケーションがサーバーからのアプリケーション固有の構成を必要とする場合は、spring.application.name
( bootstrap.yml
または application.yml
内) を設定することをお勧めします。プロパティ spring.application.name
をアプリケーションのコンテキスト ID として使用するには、それを bootstrap.[properties | yml]
に設定する必要があります。
特定のプロファイル構成を取得する場合は、bootstrap.[properties | yml]
で spring.profiles.active
も設定する必要があります。
spring.cloud.bootstrap.enabled=false
を (たとえば、システムプロパティで) 設定すると、ブートストラッププロセスを完全に無効にすることができます。
1.2. アプリケーションコンテキスト階層
SpringApplication
または SpringApplicationBuilder
からアプリケーションコンテキストを構築すると、ブートストラップコンテキストがそのコンテキストの親として追加されます。子コンテキストが親からプロパティソースとプロファイルを継承するのは Spring の機能であるため、Spring Cloud Config を使用せずに同じコンテキストを構築する場合と比較して、「メイン」アプリケーションコンテキストには追加のプロパティソースが含まれます。追加のプロパティソースは次のとおりです。
“ブートストラップ”: ブートストラップコンテキストで
PropertySourceLocators
が見つかり、空ではないプロパティがある場合、オプションのCompositePropertySource
が高い優先度で表示されます。例としては、Spring Cloud Config サーバーからのプロパティがあります。このプロパティソースの内容をカスタマイズする方法については、"ブートストラッププロパティソースのカスタマイズ" を参照してください。
Spring Cloud 2022.0.3 より前は、PropertySourceLocators (Spring Cloud Config 用のものを含む) は、ブートストラップコンテキストではなく、メインアプリケーションコンテキストで実行されていました。bootstrap.[properties | yaml] で spring.cloud.config.initialize-on-context-refresh=true を設定すると、ブートストラップコンテキスト中に PropertySourceLocators を強制的に実行できます。 |
“applicationConfig: [ クラスパス: bootstrap.yml]」 (および関連ファイル (Spring プロファイルがアクティブな場合)):
bootstrap.yml
(または.properties
) がある場合、これらのプロパティはブートストラップコンテキストの構成に使用されます。その後、親が設定されると、子コンテキストに追加されます。これらは、application.yml
(または.properties
) や、Spring Boot アプリケーション作成プロセスの通常の部分として子に追加されるその他のプロパティソースよりも優先順位が低くなります。これらのプロパティソースの内容をカスタマイズする方法については、"ブートストラッププロパティの場所の変更" を参照してください。
プロパティソースの順序付け規則により、「ブートストラップ」エントリが優先されます。ただし、これらには bootstrap.yml
からのデータは含まれていないことに注意してください。bootstrap.yml
は優先順位が非常に低いですが、デフォルトの設定に使用できます。
作成した ApplicationContext
の親コンテキストを設定することによって、コンテキスト階層を継承できます。たとえば、独自のインターフェースを使用するか、SpringApplicationBuilder
の便利なメソッド (parent()
、child()
、sibling()
) を使用します。ブートストラップコンテキストは、自分で作成した最も古い祖先の親です。階層内のすべてのコンテキストには、値が誤って親から子孫に昇格されることを避けるために、独自の「ブートストラップ」(空の場合もある) プロパティソースがあります。構成サーバーがある場合、階層内のすべてのコンテキストは (原則として) 異なる spring.application.name
を持つことができ、異なる リモートプロパティソースを持つこともできます。通常の Spring アプリケーションコンテキストの動作ルールがプロパティの解決に適用されます。子コンテキストのプロパティは、名前およびプロパティソース名によって、親のプロパティをオーバーライドします。(子に親と同じ名前のプロパティソースがある場合、親の値は子に含まれません)。
SpringApplicationBuilder
を使用すると、階層全体で Environment
を共有できますが、これはデフォルトではないことに注意してください。兄弟コンテキストは (特に)、親と共通の値を共有する場合でも、同じプロファイルやプロパティソースを持つ必要はありません。
1.3. ブートストラッププロパティの場所の変更
bootstrap.yml
(または .properties
) の場所は、たとえばシステムプロパティで spring.cloud.bootstrap.name
(デフォルト: bootstrap
)、spring.cloud.bootstrap.location
(デフォルト: 空)、または spring.cloud.bootstrap.additional-location
(デフォルト: 空) を設定することで指定できます。
これらのプロパティは、同じ名前の spring.config.*
バリアントと同様に動作します。spring.cloud.bootstrap.location
では、デフォルトの場所が置き換えられ、指定された場所のみが使用されます。デフォルトのリストに場所を追加するには、spring.cloud.bootstrap.additional-location
を使用できます。実際、これらのプロパティは、Environment
にこれらのプロパティを設定することで、ブートストラップ ApplicationContext
をセットアップするために使用されます。アクティブなプロファイルがある場合 (spring.profiles.active
から、または構築しているコンテキストの Environment
API を通じて)、通常の Spring Boot アプリと同様に、そのプロファイル内のプロパティも読み込まれます (たとえば、development
プロファイルの場合は bootstrap-development.properties
から)。
1.4. リモートプロパティの値のオーバーライド
ブートストラップコンテキストによってアプリケーションに追加されるプロパティソースは、多くの場合「リモート」です (たとえば、Spring Cloud Config サーバーから)。デフォルトでは、ローカルでオーバーライドすることはできません。アプリケーションが独自のシステムプロパティまたは構成ファイルで リモートプロパティをオーバーライドできるようにする場合、リモートプロパティソースは spring.cloud.config.allowOverride=true
を設定してアクセス許可を付与する必要があります (これをローカルで設定することはできません)。このフラグが設定されると、システムプロパティとアプリケーションのローカル構成に関連した リモートプロパティの場所が、2 つのより詳細な設定によって制御されます。
spring.cloud.config.overrideNone=true
: ローカルプロパティソースからオーバーライドします。spring.cloud.config.overrideSystemProperties=false
: システムプロパティ、コマンドライン引数、環境変数のみ (ローカル構成ファイルは不可) が リモート設定をオーバーライドする必要があります。
1.5. ブートストラップ構成のカスタマイズ
ブートストラップコンテキストは、org.springframework.cloud.bootstrap.BootstrapConfiguration
という名前のキーの /META-INF/spring.factories
にエントリを追加することで、任意の操作を行うように設定できます。これには、コンテキストの作成に使用される Spring @Configuration
クラスのカンマ区切りのリストが保持されます。オートワイヤーのためにメインアプリケーションコンテキストで使用できるようにする Bean は、ここで作成できます。ApplicationContextInitializer
型の @Beans
には特約がございます。起動シーケンスを制御したい場合は、クラスに @Order
アノテーションをマークできます (デフォルトの順序は last
)。
カスタム BootstrapConfiguration を追加するときは、追加するクラスが必要のない「メイン」アプリケーションコンテキストに誤って @ComponentScanned にならないように注意してください。Boot 構成クラスには別のパッケージ名を使用し、その名前が @ComponentScan または @SpringBootApplication アノテーション付き構成クラスですでにカバーされていないことを確認してください。 |
ブートストラッププロセスは、メイン SpringApplication
インスタンスに初期化子を挿入して終了します (これは、スタンドアロンアプリケーションとして実行されるか、アプリケーションサーバーにデプロイされるかに関係なく、通常の Spring Boot 起動シーケンスです)。まず、spring.factories
にあるクラスからブートストラップコンテキストが作成されます。次に、型 ApplicationContextInitializer
のすべての @Beans
が、メイン SpringApplication
が開始される前にメイン SpringApplication
に追加されます。
1.6. ブートストラッププロパティソースのカスタマイズ
ブートストラッププロセスによって追加される外部構成のデフォルトのプロパティソースは Spring Cloud Config サーバーですが、型 PropertySourceLocator
の Bean を ( spring.factories
を介して) ブートストラップコンテキストに追加することで、追加のソースを追加できます。たとえば、別のサーバーまたはデータベースから追加のプロパティを挿入できます。
例として、次のカスタムロケーターを考えてみましょう。
@Configuration
public class CustomPropertySourceLocator implements PropertySourceLocator {
@Override
public PropertySource<?> locate(Environment environment) {
return new MapPropertySource("customProperty",
Collections.<String, Object>singletonMap("property.from.sample.custom.source", "worked as intended"));
}
}
渡される Environment
は、これから作成される ApplicationContext
用の Environment
です。つまり、追加のプロパティソースを提供する Environment
です。通常の Spring Boot が提供するプロパティソースがすでに存在するため、使用して、この Environment
に固有のプロパティソースを見つけることができます (たとえば、デフォルトの Spring Cloud Config サーバープロパティソースロケーターで行われるように、spring.application.name
にキーを入力することによって)。
このクラスを含む jar を作成し、次の設定を含む META-INF/spring.factories
を追加すると、その jar をクラスパスに含むアプリケーションに customProperty
PropertySource
が表示されます。
org.springframework.cloud.bootstrap.BootstrapConfiguration=sample.custom.CustomPropertySourceLocator
Spring Cloud 2022.0.3 以降、Spring Cloud は PropertySourceLocators
を 2 回呼び出すようになります。最初のフェッチでは、プロファイルを含まないプロパティソースが取得されます。これらのプロパティソースには、spring.profiles.active
を使用してプロファイルをアクティブ化する機会があります。メインアプリケーションコンテキストが開始された後、PropertySourceLocators
が 2 回目に呼び出されます。このときはアクティブなプロファイルが使用され、PropertySourceLocators
はプロファイルを持つ追加の PropertySources
を見つけることができます。
1.7. ロギング構成
Spring Boot を使用してログ設定を構成する場合、すべてのイベントに適用したい場合は、この構成を bootstrap.[yml | properties]
に配置する必要があります。
Spring Cloud がログ構成を適切に初期化するには、カスタムプレフィックスを使用することはできません。例: custom.loggin.logpath の使用は、ロギングシステムの初期化時に Spring Cloud によって認識されません。 |
1.8. 環境の変化
アプリケーションは EnvironmentChangeEvent
をリッスンし、いくつかの標準的な方法で変更に反応します (追加の ApplicationListeners
は通常の方法で @Beans
として追加できます)。EnvironmentChangeEvent
が観察されると、変更されたキー値のリストがあり、アプリケーションはそれらを使用して次のことを行います。
コンテキスト内の
@ConfigurationProperties
Bean を再バインドします。logging.level.*
のプロパティのロガーレベルを設定します。
Spring Cloud Config クライアントは、デフォルトでは Environment
の変更をポーリングしないことに注意してください。一般に、変更を検出するためにそのアプローチはお勧めしません (ただし、@Scheduled
アノテーションを使用してセットアップすることはできます)。スケールアウトされたクライアントアプリケーションがある場合は、(たとえば、Spring Cloud Bus [GitHub] (英語) を使用して) 変更をポーリングさせる代わりに、すべてのインスタンスに EnvironmentChangeEvent
をブロードキャストすることをお勧めします。
EnvironmentChangeEvent
は、実際に Environment
に変更を加えてイベントを発行できる限り、大規模なクラスのリフレッシュユースケースをカバーします。これらの API はパブリックであり、コア Spring の一部であることに注意してください。/configprops
エンドポイント (標準の Spring Boot Actuator 機能) にアクセスすると、変更が @ConfigurationProperties
Bean にバインドされていることを確認できます。たとえば、DataSource
は実行時に maxPoolSize
を変更し (Spring Boot によって作成されるデフォルトの DataSource
は @ConfigurationProperties
Bean です)、容量を動的に拡張できます。@ConfigurationProperties
の再バインドは、リフレッシュをより詳細に制御する必要がある場合や、ApplicationContext
全体に対してアトミックな変更が必要な場合など、別の大きなクラスのユースケースには対応していません。これらの関心事に対処するために、@RefreshScope
があります。
1.9. リフレッシュスコープ
構成の変更がある場合、@RefreshScope
としてマークされている Spring @Bean
は特別な扱いを受けます。この機能は、初期化時にのみ構成が挿入されるステートフル Bean の問題に対処します。たとえば、データベース URL が Environment
を通じて変更されたときに DataSource
が開いている接続がある場合、おそらく、それらの接続の所有者が実行中の作業を完了できるようにする必要があります。その後、次回何かがプールから接続を借用するときに、新しい URL を持つ接続を取得します。
場合によっては、一度しか初期化できない一部の Bean に @RefreshScope
アノテーションを適用することが必須になる場合もあります。Bean が「不変」の場合、Bean に @RefreshScope
のアノテーションを付けるか、プロパティキー spring.cloud.refresh.extra-refreshable
にクラス名を指定する必要があります。
DataSource Bean が HikariDataSource である場合は、リフレッシュできません。これは spring.cloud.refresh.never-refreshable のデフォルト値です。リフレッシュする必要がある場合は、別の DataSource 実装を選択してください。 |
リフレッシュスコープ Bean は、使用時 (つまり、メソッドの呼び出し時) に初期化される遅延プロキシであり、スコープは初期化された値のキャッシュとして機能します。次のメソッド呼び出しで Bean を強制的に再初期化するには、そのキャッシュエントリを無効にする必要があります。
RefreshScope
はコンテキスト内では Bean であり、ターゲットキャッシュをクリアすることでスコープ内のすべての Bean をリフレッシュするパブリック refreshAll()
メソッドを備えています。/refresh
エンドポイントは、この機能を (HTTP または JMX 経由で) 公開します。個々の Bean を名前でリフレッシュするには、refresh(String)
メソッドもあります。
/refresh
エンドポイントを公開するには、次の構成をアプリケーションに追加する必要があります。
management:
endpoints:
web:
exposure:
include: refresh
@RefreshScope は (技術的には) @Configuration クラスで動作しますが、予期しない動作が発生する可能性があります。例: そのクラスで定義されているすべての @Beans 自体が @RefreshScope にあるという意味ではありません。具体的には、これらの Bean に依存するものは、それ自体が @RefreshScope 内にない限り、リフレッシュの開始時にリフレッシュされることに依存できません。その場合、リフレッシュ時に再構築され、その依存関係が再注入されます。その時点で、それらはリフレッシュされた @Configuration から再初期化されます)。 |
構成値を削除してからリフレッシュを実行しても、構成値の存在はリフレッシュされません。リフレッシュ後に値をリフレッシュするには、構成プロパティが存在する必要があります。アプリケーション内の値の存在に依存している場合は、代わりに値の不在に依存するようにロジックを切り替えることができます。もう 1 つのオプションは、アプリケーションの構成に値が存在しないのではなく、値の変化に依存することです。 |
コンテキストのリフレッシュは、Spring AOT 変換およびネイティブイメージではサポートされていません。AOT およびネイティブイメージの場合、spring.cloud.refresh.enabled を false に設定する必要があります。 |
1.10. 暗号化と復号化
Spring Cloud には、プロパティ値をローカルで復号化するための Environment
プリプロセッサーがあります。Spring Cloud Config サーバーと同じルールに従い、encrypt.*
を介した同じ外部構成を持ちます。暗号化された値を {cipher}*
の形式で使用でき、有効なキーがある限り、メインアプリケーションコンテキストが Environment
設定を取得する前に値が復号化されます。アプリケーションで暗号化機能を使用するには、クラスパス (Maven 座標: org.springframework.security:spring-security-rsa
) に Spring Security RSA を含める必要があります。また、JVM には完全な強度の JCE 拡張機能も必要です。
「不正なキーサイズ」による例外が発生し、Sun の JDK を使用している場合は、Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction ポリシーファイルをインストールする必要があります。詳細については、次のリンクを参照してください。
使用する JRE/JDK x64/x86 のバージョンに応じて、ファイルを JDK/jre/lib/security フォルダーに抽出します。
1.11. エンドポイント
Spring Boot Actuator アプリケーションの場合、追加の管理エンドポイントがいくつか利用可能です。次のものが使用できます。
POST
を/actuator/env
に変更して、Environment
を更新し、@ConfigurationProperties
とログレベルを再バインドします。このエンドポイントを有効にするには、management.endpoint.env.post.enabled=true
を設定する必要があります。/actuator/refresh
を使用して Boot ストラップコンテキストを再ロードし、@RefreshScope
Bean をリフレッシュします。/actuator/restart
を使用してApplicationContext
を閉じ、再起動します (デフォルトでは無効)。Lifecycle
メソッド (ApplicationContext
のstop()
およびstart()
) を呼び出すための/actuator/pause
および/actuator/resume
。
/actuator/env エンドポイントに対して POST メソッドを有効にすると、アプリケーション環境変数の管理に柔軟性と利便性が提供されますが、潜在的なセキュリティリスクを防ぐために、エンドポイントがセキュリティで保護され、監視されていることを確認することが重要です。spring-boot-starter-security 依存関係を追加して、アクチュエーターのエンドポイントのアクセス制御を構成します。 |
/actuator/restart エンドポイントを無効にすると、/actuator/pause および /actuator/resume エンドポイントも無効になります。これは、これらは /actuator/restart の特殊なケースにすぎないためです。 |
2. Spring Cloud Commons: 一般的な抽象化
サービスディスカバリ、ロードバランシング、サーキットブレーカーなどのパターンは、実装 (たとえば、Eureka または Consul によるディスカバリ) に関係なく、すべての Spring Cloud クライアントによって使用できる共通の抽象化レイヤーに役立ちます。
2.1. @EnableDiscoveryClient
アノテーション
Spring Cloud Commons は @EnableDiscoveryClient
アノテーションを提供します。これは、META-INF/spring.factories
を使用した DiscoveryClient
および ReactiveDiscoveryClient
インターフェースの実装を探します。検出クライアントの実装では、org.springframework.cloud.client.discovery.EnableDiscoveryClient
キーの spring.factories
に構成クラスを追加します。DiscoveryClient
実装の例には、Spring Cloud Netflix Eureka (英語) 、Spring Cloud Consul ディスカバリ (英語) 、Spring Cloud Zookeeper ディスカバリ (英語) があります。
Spring Cloud は、デフォルトでブロッキングサービスディスカバリクライアントとリアクティブサービスディスカバリクライアントの両方を提供します。spring.cloud.discovery.blocking.enabled=false
または spring.cloud.discovery.reactive.enabled=false
を設定することで、ブロッキングクライアントやリアクティブクライアントを簡単に無効にすることができます。サービス検出を完全に無効にするには、spring.cloud.discovery.enabled=false
を設定するだけです。
デフォルトでは、DiscoveryClient
の実装はローカル Spring Boot サーバーを リモート検出サーバーに自動登録します。この動作は、@EnableDiscoveryClient
で autoRegister=false
を設定することで無効にできます。
@EnableDiscoveryClient は不要になりました。クラスパスに DiscoveryClient 実装を配置して、Spring Boot アプリケーションをサービス検出サーバーに登録させることができます。 |
2.1.1. ヘルスインジケーター
Commons は、次の Spring Boot ヘルスインジケーターを自動構成します。
DiscoveryClientHealthIndicator
この正常性インジケーターは、現在登録されている DiscoveryClient
実装に基づいています。
完全に無効にするには、
spring.cloud.discovery.client.health-indicator.enabled=false
を設定します。説明フィールドを無効にするには、
spring.cloud.discovery.client.health-indicator.include-description=false
を設定します。そうしないと、ロールアップされたHealthIndicator
のdescription
としてバブルアップする可能性があります。サービスの取得を無効にするには、
spring.cloud.discovery.client.health-indicator.use-services-query=false
を設定します。デフォルトでは、インジケーターはクライアントのgetServices
メソッドを呼び出します。多くのサービスが登録されている デプロイでは、チェックのたびにすべてのサービスを取得するにはコストがかかりすぎる可能性があります。これにより、サービスの取得がスキップされ、代わりにクライアントのprobe
メソッドが使用されます。
DiscoveryCompositeHealthContributor
この複合ヘルスインジケーターは、登録されているすべての DiscoveryHealthIndicator
Bean に基づいています。無効にするには、spring.cloud.discovery.client.composite-indicator.enabled=false
を設定します。
2.1.2. DiscoveryClient
インスタンスのオーダー
DiscoveryClient
インターフェースは Ordered
を継承します。これは、Spring アプリケーションによってロードされた Bean を順序付ける方法と同様に、返される検出クライアントの順序を定義できるため、複数の検出クライアントを使用する場合に便利です。デフォルトでは、DiscoveryClient
の順序は 0
に設定されます。カスタム DiscoveryClient
実装に別の順序を設定したい場合は、セットアップに適した値を返すように getOrder()
メソッドをオーバーライドするだけです。これとは別に、プロパティを使用して、ConsulDiscoveryClient
、EurekaDiscoveryClient
、ZookeeperDiscoveryClient
などの Spring Cloud によって提供される DiscoveryClient
実装の順序を設定できます。これを行うには、spring.cloud.{clientIdentifier}.discovery.order
(Eureka の場合は eureka.client.order
) プロパティを目的の値に設定するだけです。
2.1.3. SimpleDiscoveryClient
クラスパスに Service-Registry に基づく DiscoveryClient
がない場合は、プロパティを使用してサービスとインスタンスに関する情報を取得する SimpleDiscoveryClient
インスタンスが使用されます。
利用可能なインスタンスに関する情報は、プロパティを介して次の形式で渡される必要があります: spring.cloud.discovery.client.simple.instances.service1[0].uri=http://s11:8080
、ここで spring.cloud.discovery.client.simple.instances
は共通のプレフィックス、service1
は問題のサービスの ID を表し、[0]
はインスタンスのインデックス番号を示します (表示されているように) この例では、インデックスは 0
で始まり、uri
の値がインスタンスを使用できる実際の URI になります。
2.2. ServiceRegistry
Commons は、カスタム登録サービスを提供できる register(Registration)
や deregister(Registration)
などのメソッドを提供する ServiceRegistry
インターフェースを提供するようになりました。Registration
はマーカーインターフェースです。
次の例は、ServiceRegistry
の使用例を示しています。
@Configuration
@EnableDiscoveryClient(autoRegister=false)
public class MyConfiguration {
private ServiceRegistry registry;
public MyConfiguration(ServiceRegistry registry) {
this.registry = registry;
}
// called through some external process, such as an event or a custom actuator endpoint
public void register() {
Registration registration = constructRegistration();
this.registry.register(registration);
}
}
各 ServiceRegistry
実装には独自の Registry
実装があります。
ZookeeperRegistration
はZookeeperServiceRegistry
と一緒に使用されますEurekaRegistration
はEurekaServiceRegistry
と一緒に使用されますConsulRegistration
はConsulServiceRegistry
と一緒に使用されます
ServiceRegistry
インターフェースを使用している場合は、使用している ServiceRegistry
実装に正しい Registry
実装を渡す必要があります。
2.2.1. ServiceRegistry 自動登録
デフォルトでは、ServiceRegistry
実装は実行中のサービスを自動登録します。この動作を無効にするには、次のように設定します。* @EnableDiscoveryClient(autoRegister=false)
を設定して自動登録を永続的に無効にします。* spring.cloud.service-registry.auto-registration.enabled=false
は設定を通じて動作を無効にします。
ServiceRegistry 自動登録イベント
サービスが自動登録されるときに発生するイベントが 2 つあります。InstancePreRegisteredEvent
と呼ばれる最初のイベントは、サービスが登録される前に発生します。2 番目のイベントは InstanceRegisteredEvent
と呼ばれ、サービスが登録された後に発生します。ApplicationListener
を登録して、これらのイベントをリッスンして反応することができます。
spring.cloud.service-registry.auto-registration.enabled プロパティが false に設定されている場合、これらのイベントは発生しません。 |
2.2.2. サービスレジストリアクチュエーターエンドポイント
Spring Cloud Commons は、/serviceregistry
アクチュエーターエンドポイントを提供します。このエンドポイントは、Spring アプリケーションコンテキストの Registration
Bean に依存します。GET を使用して /serviceregistry
を呼び出すと、Registration
のステータスが返されます。JSON 本文を使用して同じエンドポイントに POST を使用すると、現在の Registration
のステータスが新しい値に変更されます。JSON 本文には、優先値を含む status
フィールドを含める必要があります。ステータスを更新するときに使用できる値と、ステータスに対して返される値については、使用する ServiceRegistry
実装のドキュメントを参照してください。たとえば、Eureka でサポートされるステータスは UP
、DOWN
、OUT_OF_SERVICE
、UNKNOWN
です。
2.3. ロードバランサクライアントとしての Spring RestTemplate
ロードバランサークライアントを使用するように RestTemplate
を構成できます。負荷分散された RestTemplate
を作成するには、次の例に示すように、RestTemplate
@Bean
を作成し、@LoadBalanced
修飾子を使用します。
@Configuration
public class MyConfiguration {
@LoadBalanced
@Bean
RestTemplate restTemplate() {
return new RestTemplate();
}
}
public class MyClass {
@Autowired
private RestTemplate restTemplate;
public String doOtherStuff() {
String results = restTemplate.getForObject("http://stores/stores", String.class);
return results;
}
}
RestTemplate Bean は自動構成によって作成されなくなりました。個々のアプリケーションがそれを作成する必要があります。 |
URI では仮想ホスト名 (つまり、ホスト名ではなくサービス名) を使用する必要があります。BlockingLoadBalancerClient は完全な物理アドレスを作成するために使用されます。
負荷分散された RestTemplate を使用するには、クラスパスにロードバランサーの実装が必要です。Spring Cloud LoadBalancer スターターを使用するには、プロジェクトに追加します。 |
2.4. ロードバランサクライアントとしての Spring WebClient
ロードバランサークライアントを自動的に使用するように WebClient
を構成できます。負荷分散された WebClient
を作成するには、次のように WebClient.Builder
@Bean
を作成し、@LoadBalanced
修飾子を使用します。
@Configuration
public class MyConfiguration {
@Bean
@LoadBalanced
public WebClient.Builder loadBalancedWebClientBuilder() {
return WebClient.builder();
}
}
public class MyClass {
@Autowired
private WebClient.Builder webClientBuilder;
public Mono<String> doOtherStuff() {
return webClientBuilder.build().get().uri("http://stores/stores")
.retrieve().bodyToMono(String.class);
}
}
URI では仮想ホスト名 (つまり、ホスト名ではなくサービス名) を使用する必要があります。Spring Cloud LoadBalancer は、完全な物理アドレスを作成するために使用されます。
@LoadBalanced WebClient.Builder を使用する場合は、クラスパスにロードバランサーを実装する必要があります。Spring Cloud LoadBalancer スターターをプロジェクトに追加することをお勧めします。そしてそに ReactiveLoadBalancer を使用します。 |
2.4.1. 失敗したリクエストの再試行
負荷分散された RestTemplate
は、失敗したリクエストを再試行するように構成できます。デフォルトでは、このロジックは無効になっています。非リアクティブバージョン ( RestTemplate
を使用) の場合は、アプリケーションのクラスパスに Spring Retry [GitHub] (英語) を追加することで有効にできます。リアクティブバージョン ( WebTestClient
を使用) の場合は、spring.cloud.loadbalancer.retry.enabled=true
を設定する必要があります。
クラスパス上で Spring Retry または Reactive Retry による再試行ロジックを無効にしたい場合は、spring.cloud.loadbalancer.retry.enabled=false
を設定できます。
非リアクティブ実装の場合、再試行で BackOffPolicy
を実装したい場合は、LoadBalancedRetryFactory
型の Bean を作成し、createBackOffPolicy()
メソッドをオーバーライドする必要があります。
リアクティブ実装の場合は、spring.cloud.loadbalancer.retry.backoff.enabled
を false
に設定して有効にするだけです。
以下を設定できます。
spring.cloud.loadbalancer.retry.maxRetriesOnSameServiceInstance
- 同じServiceInstance
上でリクエストを何回再試行するかを示します (選択したインスタンスごとに個別にカウントされます)spring.cloud.loadbalancer.retry.maxRetriesOnNextServiceInstance
- 新しく選択されたServiceInstance
がリクエストを再試行する回数を示しますspring.cloud.loadbalancer.retry.retryableStatusCodes
- 失敗したリクエストを常に再試行するためのステータスコード。
リアクティブ実装では、さらに以下を設定できます。- spring.cloud.loadbalancer.retry.backoff.minBackoff
- 最小バックオフ期間を設定します (デフォルトでは、5 ミリ秒) - spring.cloud.loadbalancer.retry.backoff.maxBackoff
- 最大バックオフ期間を設定します (デフォルトでは、ミリ秒の最大長値) - spring.cloud.loadbalancer.retry.backoff.jitter
- 使用されるジッタを設定します。各コールの実際のバックオフ期間を計算します (デフォルトでは 0.5)。
リアクティブ実装の場合は、独自の LoadBalancerRetryPolicy
を実装して、負荷分散された呼び出しの再試行をより詳細に制御することもできます。
どちらの実装でも、spring.cloud.loadbalancer.[serviceId].retry.retryable-exceptions
プロパティに値のリストを追加することで、応答をトリガーする例外を設定することもできます。そうする場合、再試行可能なステータスコードも再試行できるように、提供した例外のリストに RetryableStatusCodeExceptions
を必ず追加します。プロパティで例外を指定しない場合、デフォルトで使用される例外は IOException
、TimeoutException
、RetryableStatusCodeException
です。spring.cloud.loadbalancer.[serviceId].retry.retry-on-all-exceptions
を true
に設定することで、すべての例外での再試行を有効にすることもできます。
Spring 再試行でブロッキング実装を使用する場合、以前のリリースの動作を保持したい場合は、ブロッキング実装のデフォルトモードとして使用されていた spring.cloud.loadbalancer.[serviceId].retry.retry-on-all-exceptions を true に設定します。 |
個々のロードバランサークライアントは、プレフィックスが spring.cloud.loadbalancer.clients.<clientId>.* (clientId がロードバランサーの名前) であることを除き、上記と同じプロパティを使用して個別に構成できます。 |
負荷分散された再試行の場合、デフォルトでは、ServiceInstanceListSupplier Bean を RetryAwareServiceInstanceListSupplier でラップして、以前に選択したインスタンスとは異なるインスタンスを選択します (可能な場合)。この動作を無効にするには、spring.cloud.loadbalancer.retry.avoidPreviousInstance の値を false に設定します。 |
@Configuration
public class MyConfiguration {
@Bean
LoadBalancedRetryFactory retryFactory() {
return new LoadBalancedRetryFactory() {
@Override
public BackOffPolicy createBackOffPolicy(String service) {
return new ExponentialBackOffPolicy();
}
};
}
}
再試行機能に 1 つ以上の RetryListener
実装を追加する場合は、次の例に示すように、型 LoadBalancedRetryListenerFactory
の Bean を作成し、特定のサービスに使用する RetryListener
配列を返す必要があります。
@Configuration
public class MyConfiguration {
@Bean
LoadBalancedRetryListenerFactory retryListenerFactory() {
return new LoadBalancedRetryListenerFactory() {
@Override
public RetryListener[] createRetryListeners(String service) {
return new RetryListener[]{new RetryListener() {
@Override
public <T, E extends Throwable> boolean open(RetryContext context, RetryCallback<T, E> callback) {
//TODO Do you business...
return true;
}
@Override
public <T, E extends Throwable> void close(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) {
//TODO Do you business...
}
@Override
public <T, E extends Throwable> void onError(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) {
//TODO Do you business...
}
}};
}
};
}
}
2.5. 複数の RestTemplate
オブジェクト
負荷分散されていない RestTemplate
が必要な場合は、RestTemplate
Bean を作成して挿入します。負荷分散された RestTemplate
にアクセスするには、次の例に示すように、@Bean
の作成時に @LoadBalanced
修飾子を使用します。
@Configuration
public class MyConfiguration {
@LoadBalanced
@Bean
RestTemplate loadBalanced() {
return new RestTemplate();
}
@Primary
@Bean
RestTemplate restTemplate() {
return new RestTemplate();
}
}
public class MyClass {
@Autowired
private RestTemplate restTemplate;
@Autowired
@LoadBalanced
private RestTemplate loadBalanced;
public String doOtherStuff() {
return loadBalanced.getForObject("http://stores/stores", String.class);
}
public String doStuff() {
return restTemplate.getForObject("http://example.com", String.class);
}
}
前の例では、修飾されていない @Autowired インジェクションを明確にするために、プレーンな RestTemplate 宣言で @Primary アノテーションが使用されていることに注意してください。 |
java.lang.IllegalArgumentException: Can not set org.springframework.web.client.RestTemplate field com.my.app.Foo.restTemplate to com.sun.proxy.$Proxy89 などのエラーが表示された場合は、RestOperations を挿入するか、spring.aop.proxyTargetClass=true を設定してみてください。 |
2.6. 複数の WebClient オブジェクト
負荷分散されていない WebClient
が必要な場合は、WebClient
Bean を作成して挿入します。負荷分散された WebClient
にアクセスするには、次の例に示すように、@Bean
の作成時に @LoadBalanced
修飾子を使用します。
@Configuration
public class MyConfiguration {
@LoadBalanced
@Bean
WebClient.Builder loadBalanced() {
return WebClient.builder();
}
@Primary
@Bean
WebClient.Builder webClient() {
return WebClient.builder();
}
}
public class MyClass {
@Autowired
private WebClient.Builder webClientBuilder;
@Autowired
@LoadBalanced
private WebClient.Builder loadBalanced;
public Mono<String> doOtherStuff() {
return loadBalanced.build().get().uri("http://stores/stores")
.retrieve().bodyToMono(String.class);
}
public Mono<String> doStuff() {
return webClientBuilder.build().get().uri("http://example.com")
.retrieve().bodyToMono(String.class);
}
}
2.7. ロードバランサクライアントとしての Spring WebFlux WebClient
Spring WebFlux は、以下のトピックに従って、リアクティブ構成と非リアクティブ WebClient
構成の両方で動作できます。
2.7.1. Spring WebFlux WebClient
ReactorLoadBalancerExchangeFilterFunction
を使用する場合
ReactiveLoadBalancer
を使用するように WebClient
を構成できます。Spring Cloud LoadBalancer スターターをプロジェクトに追加し、spring-webflux
がクラスパス上にある場合、ReactorLoadBalancerExchangeFilterFunction
は自動構成されます。次の例は、リアクティブロードバランサを使用するように WebClient
を設定する方法を示しています。
public class MyClass {
@Autowired
private ReactorLoadBalancerExchangeFilterFunction lbFunction;
public Mono<String> doOtherStuff() {
return WebClient.builder().baseUrl("http://stores")
.filter(lbFunction)
.build()
.get()
.uri("/stores")
.retrieve()
.bodyToMono(String.class);
}
}
URI では仮想ホスト名 (つまり、ホスト名ではなくサービス名) を使用する必要があります。ReactorLoadBalancer
は、完全な物理アドレスを作成するために使用されます。
2.7.2. ノンリアクティブロードバランサクライアントを備えた Spring WebFlux WebClient
spring-webflux
がクラスパス上にある場合、LoadBalancerExchangeFilterFunction
は自動構成されます。ただし、これは内部で非リアクティブクライアントを使用することに注意してください。次の例は、ロードバランサを使用するように WebClient
を設定する方法を示しています。
public class MyClass {
@Autowired
private LoadBalancerExchangeFilterFunction lbFunction;
public Mono<String> doOtherStuff() {
return WebClient.builder().baseUrl("http://stores")
.filter(lbFunction)
.build()
.get()
.uri("/stores")
.retrieve()
.bodyToMono(String.class);
}
}
URI では仮想ホスト名 (つまり、ホスト名ではなくサービス名) を使用する必要があります。LoadBalancerClient
は、完全な物理アドレスを作成するために使用されます。
WARN: このアプローチは現在非推奨です。代わりにリアクティブロードバランサを備えた WebFlux を使用することをお勧めします。
2.8. ネットワークインターフェースを無視する
場合によっては、特定の名前付きネットワークインターフェースを無視して、サービスディスカバリの登録から除外できると便利です (たとえば、Docker コンテナーで実行している場合)。正規表現のリストを設定して、目的のネットワークインターフェースを無視することができます。次の設定では、docker0
インターフェースと veth
で始まるすべてのインターフェースが無視されます。
spring: cloud: inetutils: ignoredInterfaces: - docker0 - veth.*
次の例に示すように、正規表現のリストを使用して、指定したネットワークアドレスのみを強制的に使用することもできます。
spring: cloud: inetutils: preferredNetworks: - 192.168 - 10.0
次の例に示すように、サイトローカルアドレスのみの使用を強制することもできます。
spring: cloud: inetutils: useOnlySiteLocalInterfaces: true
サイトローカルアドレスの構成要素の詳細については、"Inet4Address.html.isSiteLocalAddress() (標準 Javadoc) " を参照してください。
2.9. HTTP クライアントファクトリ
Spring Cloud Commons は、Apache HTTP クライアント (ApacheHttpClientFactory
) と OK HTTP クライアント (OkHttpClientFactory
) の両方を作成するための Bean を提供します。OkHttpClientFactory
Bean は、OK HTTP jar がクラスパスにある場合にのみ作成されます。さらに、Spring Cloud Commons は、両方のクライアントで使用される接続マネージャーを作成するための Bean を提供します。Apache HTTP クライアントの場合は ApacheHttpClientConnectionManagerFactory
、OK HTTP クライアントの場合は OkHttpClientConnectionPoolFactory
です。下流プロジェクトで HTTP クライアントを作成する方法をカスタマイズする場合は、これらの Bean の独自の実装を提供できます。さらに、型 HttpClientBuilder
または OkHttpClient.Builder
の Bean を提供する場合、デフォルトのファクトリは、下流プロジェクトに返されるビルダーのベースとしてこれらのビルダーを使用します。spring.cloud.httpclientfactories.apache.enabled
または spring.cloud.httpclientfactories.ok.enabled
を false
に設定して、これらの Bean の作成を無効にすることもできます。
2.10. 有効な機能
Spring Cloud Commons は、/features
アクチュエーターエンドポイントを提供します。このエンドポイントは、クラスパスで利用可能な機能と、それらが有効かどうかを返します。返される情報には、機能の型、名前、バージョン、ベンダーが含まれます。
2.10.1. 特徴の種類
「機能」には、抽象機能と名前付き機能の 2 種類があります。
抽象機能は、インターフェースまたは抽象クラスが定義され、実装によって作成される機能です ( DiscoveryClient
、LoadBalancerClient
、LockService
など)。抽象クラスまたはインターフェースは、コンテキスト内でその型の Bean を見つけるために使用されます。表示されるバージョンは bean.getClass().getPackage().getImplementationVersion()
です。
名前付き機能は、実装する特定のクラスを持たない機能です。これらの機能には、「サーキットブレーカー」、「API ゲートウェイ」、"Spring Cloud Bus" などが含まれます。これらの機能には、名前と Bean 型が必要です。
2.10.2. 機能の宣言
次の例に示すように、どのモジュールでも任意の数の HasFeature
Bean を宣言できます。
@Bean
public HasFeatures commonsFeatures() {
return HasFeatures.abstractFeatures(DiscoveryClient.class, LoadBalancerClient.class);
}
@Bean
public HasFeatures consulFeatures() {
return HasFeatures.namedFeatures(
new NamedFeature("Spring Cloud Bus", ConsulBusAutoConfiguration.class),
new NamedFeature("Circuit Breaker", HystrixCommandAspect.class));
}
@Bean
HasFeatures localFeatures() {
return HasFeatures.builder()
.abstractFeature(Something.class)
.namedFeature(new NamedFeature("Some Other Feature", Someother.class))
.abstractFeature(Somethingelse.class)
.build();
}
これらの Bean はそれぞれ、適切に保護された @Configuration
に入れる必要があります。
2.11. Spring Cloud 互換性の検証
一部のユーザーが Spring Cloud アプリケーションのセットアップに問題を抱えているため、互換性検証メカニズムを追加することにしました。現在のセットアップが Spring Cloud 要件と互換性がない場合は、問題が発生したことを示すレポートとともに機能が停止します。
現時点では、Spring Boot のどのバージョンがクラスパスに追加されているかを確認しています。
レポートの例
*************************** APPLICATION FAILED TO START *************************** Description: Your project setup is incompatible with our requirements due to following reasons: - Spring Boot [2.1.0.RELEASE] is not compatible with this Spring Cloud release train Action: Consider applying the following actions: - Change Spring Boot version to one of the following versions [1.2.x, 1.3.x] . You can find the latest Spring Boot versions here [https://spring.io/projects/spring-boot#learn]. If you want to learn more about the Spring Cloud Release train compatibility, you can visit this page [https://spring.io/projects/spring-cloud#overview] and check the [Release Trains] section.
この機能を無効にするには、spring.cloud.compatibility-verifier.enabled
を false
に設定します。互換性のある Spring Boot バージョンをオーバーライドする場合は、互換性のある Spring Boot バージョンのカンマ区切りリストを使用して spring.cloud.compatibility-verifier.compatible-boot-versions
プロパティを設定するだけです。
3. Spring Cloud LoadBalancer
Spring Cloud は、独自のクライアント側ロードバランサーの抽象化と実装を提供します。負荷分散メカニズムについては、ReactiveLoadBalancer
インターフェースが追加され、ラウンドロビンベースおよびランダム実装が提供されています。リアクティブから選択するインスタンスを取得するには、ServiceInstanceListSupplier
が使用されます。現在、クラスパスで使用可能なディスカバリクライアントを使用してサービスディスカバリから利用可能なインスタンスを取得する、サービスディスカバリベースの ServiceInstanceListSupplier
実装をサポートしています。
spring.cloud.loadbalancer.enabled の値を false に設定することで、Spring Cloud LoadBalancer を無効にすることができます。 |
3.1. LoadBalancer コンテキストの積極的なロード
Spring Cloud LoadBalancer は、サービス ID ごとに個別の Spring 子コンテキストを作成します。デフォルトでは、サービス ID に対する最初のリクエストが負荷分散されるたびに、これらのコンテキストは遅延初期化されます。
これらのコンテキストを積極的にロードすることを選択できます。これを行うには、spring.cloud-loadbalancer.eager-load.clients
プロパティを使用して、即時ロードを実行するサービス ID を指定します。
3.2. 負荷分散アルゴリズムの切り替え
デフォルトで使用される ReactiveLoadBalancer
実装は RoundRobinLoadBalancer
です。選択したサービスまたはすべてのサービスを別の実装に切り替えるには、カスタム LoadBalancer 構成メカニズムを使用できます。
例: 次の設定を @LoadBalancerClient
アノテーション経由で渡して、RandomLoadBalancer
の使用に切り替えることができます。
public class CustomLoadBalancerConfiguration {
@Bean
ReactorLoadBalancer<ServiceInstance> randomLoadBalancer(Environment environment,
LoadBalancerClientFactory loadBalancerClientFactory) {
String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
return new RandomLoadBalancer(loadBalancerClientFactory
.getLazyProvider(name, ServiceInstanceListSupplier.class),
name);
}
}
@LoadBalancerClient または @LoadBalancerClients 構成引数として渡すクラスは、@Configuration のアノテーションが付けられていないか、コンポーネントのスキャン範囲外である必要があります。 |
3.3. Spring Cloud LoadBalancer の統合
Spring Cloud LoadBalancer を使いやすくするために、WebClient
で使用できる ReactorLoadBalancerExchangeFilterFunction
と、RestTemplate
で動作する BlockingLoadBalancerClient
を提供します。詳細と使用例については、次のセクションで説明します。
3.4. Spring Cloud LoadBalancer キャッシング
インスタンスを選択する必要があるたびに DiscoveryClient
経由でインスタンスを取得する基本的な ServiceInstanceListSupplier
実装とは別に、2 つのキャッシュ実装が提供されています。
3.4.1. Caffeine - バックアップされた LoadBalancer キャッシュ実装
クラスパスに com.github.ben-manes.caffeine:caffeine
がある場合は、Caffeine ベースの実装が使用されます。設定方法については、"LoadBalancerCacheConfiguration" セクションを参照してください。
Caffeine を使用している場合は、spring.cloud.loadbalancer.cache.caffeine.spec
プロパティに独自の Caffeine 仕様 (英語) を渡すことで、LoadBalancer のデフォルトの Caffeine キャッシュ設定をオーバーライドすることもできます。
WARN: 独自の Caffeine 仕様を渡すと、ttl
や capacity
などの一般的な LoadBalancer キャッシュ構成フィールドを含む他の LoadBalancerCache 設定がオーバーライドされます。
3.4.2. デフォルトの LoadBalancer キャッシュ実装
クラスパスに Caffeine がない場合は、spring-cloud-starter-loadbalancer
に自動的に付属する DefaultLoadBalancerCache
が使用されます。設定方法については、"LoadBalancerCacheConfiguration" セクションを参照してください。
デフォルトのキャッシュの代わりに Caffeine を使用するには、クラスパスに com.github.ben-manes.caffeine:caffeine 依存関係を追加します。 |
3.4.3. LoadBalancer キャッシュ構成
spring.cloud.loadbalancer.cache.ttl
プロパティの値として Spring Boot String
から Duration
へのコンバーターの構文に準拠した String
を渡すことで、Duration
で表される独自の ttl
値(書き込み後、エントリの有効期限が切れるまでの時間)を設定できます。また、spring.cloud.loadbalancer.cache.capacity
プロパティの値を設定することで、独自の LoadBalancer キャッシュ初期容量を設定することもできます。
デフォルトの設定には、35 秒に設定された ttl
が含まれており、デフォルトの initialCapacity
は 256
です。
spring.cloud.loadbalancer.cache.enabled
の値を false
に設定することで、loadBalancer キャッシュを完全に無効にすることもできます。
基本的なキャッシュされていない実装はプロトタイピングやテストには役立ちますが、キャッシュされたバージョンよりも効率がはるかに低いため、運用環境では常にキャッシュされたバージョンを使用することをお勧めします。DiscoveryClient 実装 ( EurekaDiscoveryClient など) によってキャッシュがすでに行われている場合は、二重キャッシュを防ぐためにロードバランサーのキャッシュを無効にする必要があります。 |
独自の構成を作成する場合、CachingServiceInstanceListSupplier を使用する場合は、ネットワーク経由でインスタンスを取得するサプライヤー ( DiscoveryClientServiceInstanceListSupplier など) の直後の階層内で、他のフィルタリングサプライヤーの前に必ず配置してください。 |
3.5. 加重負荷分散
加重ロードバランシングを有効にするために、WeightedServiceInstanceListSupplier
が提供されています。WeightFunction
を使用して各インスタンスの重みを計算します。デフォルトでは、メタデータマップから重みを読み取って解析しようとします (キーは weight
)。
メタデータマップで重みが指定されていない場合、このインスタンスの重みはデフォルトで 1 になります。
これを構成するには、spring.cloud.loadbalancer.configurations
の値を weighted
に設定するか、独自の ServiceInstanceListSupplier
Bean を指定します。例:
public class CustomLoadBalancerConfiguration {
@Bean
public ServiceInstanceListSupplier discoveryClientServiceInstanceListSupplier(
ConfigurableApplicationContext context) {
return ServiceInstanceListSupplier.builder()
.withDiscoveryClient()
.withWeighted()
.withCaching()
.build(context);
}
}
WeightFunction を提供することで、重み計算ロジックをカスタマイズすることもできます。 |
このサンプル構成を使用すると、すべてのインスタンスにランダムな重みを持たせることができます。
public class CustomLoadBalancerConfiguration {
@Bean
public ServiceInstanceListSupplier discoveryClientServiceInstanceListSupplier(
ConfigurableApplicationContext context) {
return ServiceInstanceListSupplier.builder()
.withDiscoveryClient()
.withWeighted(instance -> ThreadLocalRandom.current().nextInt(1, 101))
.withCaching()
.build(context);
}
}
3.6. ゾーンベースの負荷分散
ゾーンベースの負荷分散を有効にするために、ZonePreferenceServiceInstanceListSupplier
が提供されています。DiscoveryClient
-specific zone
構成 (たとえば、eureka.instance.metadata-map.zone
) を使用して、クライアントが利用可能なサービスインスタンスをフィルタリングしようとするゾーンを選択します。
spring.cloud.loadbalancer.zone プロパティの値を設定することで、DiscoveryClient -specific ゾーン設定をオーバーライドすることもできます。 |
当面は、LoadBalancer ゾーンを設定するために Eureka Discovery Client のみが装備されています。他の検出クライアントの場合は、spring.cloud.loadbalancer.zone プロパティを設定します。さらに多くの機器が間もなく登場します。 |
取得した ServiceInstance のゾーンを判断するには、そのメタデータマップ内の "zone" キーの値を確認します。 |
ZonePreferenceServiceInstanceListSupplier
は、取得したインスタンスをフィルタリングし、同じゾーン内のインスタンスのみを返します。ゾーンが null
である場合、または同じゾーン内にインスタンスがない場合は、取得されたすべてのインスタンスが返されます。
ゾーンベースの負荷分散アプローチを使用するには、カスタム構成で ZonePreferenceServiceInstanceListSupplier
Bean をインスタンス化する必要があります。
ServiceInstanceListSupplier
Bean を操作するためにデリゲートを使用します。DiscoveryClientServiceInstanceListSupplier
デリゲートを使用し、それを CachingServiceInstanceListSupplier
でラップして LoadBalancer キャッシュメカニズムを利用し、結果の Bean を ZonePreferenceServiceInstanceListSupplier
のコンストラクターに渡すことをお勧めします。
このサンプル構成を使用してセットアップできます。
public class CustomLoadBalancerConfiguration {
@Bean
public ServiceInstanceListSupplier discoveryClientServiceInstanceListSupplier(
ConfigurableApplicationContext context) {
return ServiceInstanceListSupplier.builder()
.withDiscoveryClient()
.withCaching()
.withZonePreference()
.build(context);
}
}
3.7. LoadBalancer のインスタンスのヘルスチェック
LoadBalancer に対してスケジュールされた HealthCheck を有効にすることができます。HealthCheckServiceInstanceListSupplier
はそのために提供されています。デリゲート ServiceInstanceListSupplier
によって提供されたインスタンスがまだ生きているかどうかを定期的に確認し、正常なインスタンスのみを返します (存在しない場合は、取得したすべてのインスタンスを返します)。
このメカニズムは、SimpleDiscoveryClient を使用する場合に特に役立ちます。実際のサービスレジストリによってサポートされているクライアントの場合、外部 ServiceDiscovery にクエリを実行した後、正常なインスタンスがすでに取得されているため、サービスレジストリを使用する必要はありません。 |
このサプライヤーは、失敗したインスタンスでの呼び出しの再試行を避けるために、サービスあたりのインスタンス数が少ないセットアップにも推奨されます。 |
サービスディスカバリがサポートするサプライヤーを使用している場合は、インスタンスの健全性状態を Service Registry から直接取得するため、通常、この健全性チェックメカニズムを追加する必要はありません。 |
HealthCheckServiceInstanceListSupplier は、デリゲート flux によって提供されるリフレッシュされたインスタンスに依存しています。インスタンスのリストが変更される可能性があるにもかかわらず、インスタンスをリフレッシュしないデリゲート (当社が提供する DiscoveryClientServiceInstanceListSupplier など) を使用するまれなケースでは、spring.cloud.loadbalancer.health-check.refetch-instances を true に設定して、インスタンスリストを HealthCheckServiceInstanceListSupplier によってリフレッシュすることができます。その後、spring.cloud.loadbalancer.health-check.refetch-instances-interval の値を変更して再フェッチ間隔を調整し、spring.cloud.loadbalancer.health-check.repeat-health-check を false に設定して追加のヘルスチェックの繰り返しを無効にすることもできます。これは、インスタンスの再フェッチごとにヘルスチェックもトリガーされるためです。 |
HealthCheckServiceInstanceListSupplier
は、spring.cloud.loadbalancer.health-check
という接頭辞が付いているプロパティを使用します。スケジューラーには initialDelay
と interval
を設定できます。spring.cloud.loadbalancer.health-check.path.default
プロパティの値を設定することで、ヘルスチェック URL のデフォルトのパスを設定できます。spring.cloud.loadbalancer.health-check.path.[SERVICE_ID]
プロパティの値を設定し、[SERVICE_ID]
をサービスの正しい ID に置き換えることにより、特定のサービスに特定の値を設定することもできます。[SERVICE_ID]
が指定されていない場合は、デフォルトで /actuator/health
が使用されます。[SERVICE_ID]
が null
に設定されている場合、または値が空の場合、ヘルスチェックは実行されません。spring.cloud.loadbalancer.health-check.port
の値を設定することで、ヘルスチェックリクエスト用のカスタムポートを設定することもできます。何も設定されていない場合、リクエストされたサービスをサービスインスタンスで使用できるポート。
デフォルトのパス (/actuator/health ) に依存する場合は、そのようなエンドポイントを独自に追加する予定がない限り、必ず spring-boot-starter-actuator をコラボレーターの依存関係に追加してください。 |
デフォルトでは、healthCheckFlux は取得された各生存 ServiceInstance に対して発行します。この動作は、spring.cloud.loadbalancer.health-check.update-results-list の値を false に設定することで変更できます。このプロパティが false に設定されている場合、生存インスタンスのシーケンス全体が最初にリストに収集され、その後発行されます。これにより、プロパティで設定されたヘルスチェック間隔の間に flux が値を発行しないことが保証されます。 |
ヘルスチェックスケジューラのアプローチを使用するには、カスタム構成で HealthCheckServiceInstanceListSupplier
Bean をインスタンス化する必要があります。
ServiceInstanceListSupplier
Bean を操作するためにデリゲートを使用します。HealthCheckServiceInstanceListSupplier
のコンストラクターで DiscoveryClientServiceInstanceListSupplier
デリゲートを渡すことをお勧めします。
このサンプル構成を使用してセットアップできます。
public class CustomLoadBalancerConfiguration {
@Bean
public ServiceInstanceListSupplier discoveryClientServiceInstanceListSupplier(
ConfigurableApplicationContext context) {
return ServiceInstanceListSupplier.builder()
.withDiscoveryClient()
.withHealthChecks()
.build(context);
}
}
非リアクティブスタックの場合は、withBlockingHealthChecks() を使用してこのサプライヤーを作成します。チェックに使用する独自の WebClient または RestTemplate インスタンスを渡すこともできます。 |
HealthCheckServiceInstanceListSupplier には、Reactor Flux replay() に基づく独自のキャッシュメカニズムがあります。これが使用されている場合は、そのサプライヤーを CachingServiceInstanceListSupplier でラップするのをスキップすることをお勧めします。 |
独自の構成 HealthCheckServiceInstanceListSupplier を作成する場合は、ネットワーク経由でインスタンスを取得するサプライヤー ( DiscoveryClientServiceInstanceListSupplier など) の直後の階層内で、他のフィルタリングサプライヤーの前に必ず配置してください。 |
3.8. LoadBalancer の同じインスタンス設定
以前に選択されたインスタンスが使用可能な場合、そのインスタンスが優先されるように LoadBalancer をセットアップできます。
そのためには、SameInstancePreferenceServiceInstanceListSupplier
を使用する必要があります。これを構成するには、spring.cloud.loadbalancer.configurations
の値を same-instance-preference
に設定するか、独自の ServiceInstanceListSupplier
Bean を指定します。たとえば、次のようになります。
public class CustomLoadBalancerConfiguration {
@Bean
public ServiceInstanceListSupplier discoveryClientServiceInstanceListSupplier(
ConfigurableApplicationContext context) {
return ServiceInstanceListSupplier.builder()
.withDiscoveryClient()
.withSameInstancePreference()
.build(context);
}
}
これも Zookeeper StickyRule の代替です。 |
3.9. LoadBalancer のリクエストベースのスティッキーセッション
リクエスト Cookie で提供される instanceId
を持つインスタンスが優先されるように LoadBalancer をセットアップできます。現在、リクエストが ClientRequestContext
または ServerHttpRequestContext
を介して LoadBalancer に渡される場合、これはサポートされています。これらは SC LoadBalancer 交換フィルター関数およびフィルターによって使用されます。
そのためには、RequestBasedStickySessionServiceInstanceListSupplier
を使用する必要があります。これを構成するには、spring.cloud.loadbalancer.configurations
の値を request-based-sticky-session
に設定するか、独自の ServiceInstanceListSupplier
Bean を指定します。たとえば、次のようになります。
public class CustomLoadBalancerConfiguration {
@Bean
public ServiceInstanceListSupplier discoveryClientServiceInstanceListSupplier(
ConfigurableApplicationContext context) {
return ServiceInstanceListSupplier.builder()
.withDiscoveryClient()
.withRequestBasedStickySession()
.build(context);
}
}
この機能では、リクエストを転送する前に、選択したサービスインスタンス (元のリクエスト Cookie が使用できない場合は、そのサービスインスタンスと異なる可能性があります) を更新できると便利です。これを行うには、spring.cloud.loadbalancer.sticky-session.add-service-instance-cookie
の値を true
に設定します。
デフォルトでは、Cookie の名前は sc-lb-instance-id
です。spring.cloud.loadbalancer.instance-id-cookie-name
プロパティの値を変更することで変更できます。
この機能は現在、WebClient ベースのロードバランシングでサポートされています。 |
3.10. Spring Cloud LoadBalancer ヒント
Spring Cloud LoadBalancer を使用すると、Request
オブジェクト内の LoadBalancer に渡され、後で処理できる ReactiveLoadBalancer
実装で使用できる String
ヒントを設定できます。
spring.cloud.loadbalancer.hint.default
プロパティの値を設定することで、すべてのサービスのデフォルトのヒントを設定できます。spring.cloud.loadbalancer.hint.[SERVICE_ID]
プロパティの値を設定し、[SERVICE_ID]
をサービスの正しい ID に置き換えることにより、特定のサービスに特定の値を設定することもできます。ユーザーがヒントを設定しない場合は、default
が使用されます。
3.11. ヒントベースの負荷分散
また、ヒントベースのインスタンス選択のための ServiceInstanceListSupplier
実装である HintBasedServiceInstanceListSupplier
も提供します。
HintBasedServiceInstanceListSupplier
は、ヒントリクエストヘッダー (デフォルトのヘッダー名は X-SC-LB-Hint
ですが、spring.cloud.loadbalancer.hint-header-name
プロパティの値を変更することで変更できます) をチェックし、ヒントリクエストヘッダーが見つかった場合は、ヘッダーに渡されたヒント値を使用してフィルターします。サービスインスタンス。
ヒントヘッダーが追加されていない場合、HintBasedServiceInstanceListSupplier
はプロパティからのヒント値を使用してサービスインスタンスをフィルターします。
ヘッダーまたはプロパティによってヒントが設定されていない場合は、デリゲートによって提供されたすべてのサービスインスタンスが返されます。
フィルタリング中に、HintBasedServiceInstanceListSupplier
は、metadataMap
の hint
キーに設定された一致する値を持つサービスインスタンスを検索します。一致するインスタンスが見つからない場合は、デリゲートによって提供されたすべてのインスタンスが返されます。
次のサンプル構成を使用してセットアップできます。
public class CustomLoadBalancerConfiguration {
@Bean
public ServiceInstanceListSupplier discoveryClientServiceInstanceListSupplier(
ConfigurableApplicationContext context) {
return ServiceInstanceListSupplier.builder()
.withDiscoveryClient()
.withCaching()
.withHints()
.build(context);
}
}
3.12. 負荷分散された HTTP リクエストを変換する
選択した ServiceInstance
を使用して、負荷分散された HTTP リクエストを変換できます。
RestTemplate
の場合、次のように LoadBalancerRequestTransformer
を実装して定義する必要があります。
@Bean
public LoadBalancerRequestTransformer transformer() {
return new LoadBalancerRequestTransformer() {
@Override
public HttpRequest transformRequest(HttpRequest request, ServiceInstance instance) {
return new HttpRequestWrapper(request) {
@Override
public HttpHeaders getHeaders() {
HttpHeaders headers = new HttpHeaders();
headers.putAll(super.getHeaders());
headers.add("X-InstanceId", instance.getInstanceId());
return headers;
}
};
}
};
}
WebClient
の場合、次のように LoadBalancerClientRequestTransformer
を実装して定義する必要があります。
@Bean
public LoadBalancerClientRequestTransformer transformer() {
return new LoadBalancerClientRequestTransformer() {
@Override
public ClientRequest transformRequest(ClientRequest request, ServiceInstance instance) {
return ClientRequest.from(request)
.header("X-InstanceId", instance.getInstanceId())
.build();
}
};
}
複数のトランスフォーマが定義されている場合、Bean が定義されている順序で適用されます。または、LoadBalancerRequestTransformer.DEFAULT_ORDER
または LoadBalancerClientRequestTransformer.DEFAULT_ORDER
を使用して順序を指定することもできます。
3.13. Spring Cloud LoadBalancer スターター
Spring Boot アプリに Spring Cloud LoadBalancer を簡単に追加できるスターターも提供しています。これを使用するには、ビルドファイルの Spring Cloud 依存関係に org.springframework.cloud:spring-cloud-starter-loadbalancer
を追加するだけです。
Spring Cloud LoadBalancer スターターには、Spring Boot キャッシングおよびエヴィクター [GitHub] (英語) が含まれます。 |
3.14. 独自の Spring Cloud LoadBalancer 構成を渡す
次のように、@LoadBalancerClient
アノテーションを使用して、ロードバランサークライアントの名前と構成クラスを渡して、独自のロードバランサークライアント構成を渡すこともできます。
@Configuration
@LoadBalancerClient(value = "stores", configuration = CustomLoadBalancerConfiguration.class)
public class MyConfiguration {
@Bean
@LoadBalanced
public WebClient.Builder loadBalancedWebClientBuilder() {
return WebClient.builder();
}
}
独自の LoadBalancer 構成での作業を容易にするために、ServiceInstanceListSupplier クラスに builder() メソッドを追加しました。 |
また、spring.cloud.loadbalancer.configurations プロパティの値を zone-preference に設定して ZonePreferenceServiceInstanceListSupplier をキャッシュとともに使用するか、health-check に設定して HealthCheckServiceInstanceListSupplier をキャッシュとともに使用することにより、デフォルトの構成の代わりに代替の事前定義された構成を使用することもできます。 |
この機能を使用すると、ユーザーが作成した、またはデフォルト設定をオーバーライドするための代替手段 (たとえば ZonePreferenceServiceInstanceListSupplier
) として当社が提供した ServiceInstanceListSupplier
または ReactorLoadBalancer
のさまざまな実装をインスタンス化できます。
カスタム構成の例はここで見ることができます。
アノテーション value 引数 (上記の例では stores ) は、指定されたカスタム構成でリクエストを送信する必要があるサービスのサービス ID を指定します。 |
次の例に示すように、@LoadBalancerClients
アノテーションを介して複数の構成 (複数のロードバランサークライアント用) を渡すこともできます。
@Configuration
@LoadBalancerClients({@LoadBalancerClient(value = "stores", configuration = StoresLoadBalancerClientConfiguration.class), @LoadBalancerClient(value = "customers", configuration = CustomersLoadBalancerClientConfiguration.class)})
public class MyConfiguration {
@Bean
@LoadBalanced
public WebClient.Builder loadBalancedWebClientBuilder() {
return WebClient.builder();
}
}
@LoadBalancerClient または @LoadBalancerClients 構成引数として渡すクラスは、@Configuration のアノテーションが付けられていないか、コンポーネントのスキャン範囲外である必要があります。 |
独自の構成を作成する場合、CachingServiceInstanceListSupplier または HealthCheckServiceInstanceListSupplier を使用する場合は、両方ではなくどちらか一方を使用し、ネットワーク経由でインスタンスを取得するサプライヤーの直後の階層(たとえば DiscoveryClientServiceInstanceListSupplier など)に、他のフィルタリングサプライヤーよりも前に配置するようにしてください。 |
3.15. Spring Cloud LoadBalancer ライフサイクル
カスタム LoadBalancer 構成を使用して登録すると便利な Bean の型の 1 つは LoadBalancerLifecycle
です。
LoadBalancerLifecycle
Bean は、onStart(Request<RC> request)
、onStartRequest(Request<RC> request, Response<T> lbResponse)
、onComplete(CompletionContext<RES, T, RC> completionContext)
という名前のコールバックメソッドを提供します。これを実装して、ロードバランシングの前後に実行するアクションを指定する必要があります。
onStart(Request<RC> request)
は Request
オブジェクトをパラメーターとして受け取ります。これには、ダウンストリームクライアントのリクエストやヒントなど、適切なインスタンスを選択するために使用されるデータが含まれています。onStartRequest
は、Request
オブジェクトに加えて、Response<T>
オブジェクトもパラメーターとして受け取ります。一方、CompletionContext
オブジェクトは onComplete(CompletionContext<RES, T, RC> completionContext)
メソッドに提供されます。これには、選択したサービスインスタンス、そのサービスインスタンスに対して実行されたリクエストの Status
、(利用可能な場合) ダウンストリームクライアントに返されたレスポンス、(例外が発生した場合) 対応する Throwable
を含む LoadBalancer Response
が含まれます。
supports(Class requestContextClass, Class responseClass, Class serverTypeClass)
メソッドを使用すると、問題のプロセッサーが指定された型のオブジェクトを処理するかどうかを判断できます。ユーザーによってオーバーライドされていない場合は、true
を返します。
前述のメソッド呼び出しでは、RC は RequestContext 型を意味し、RES はクライアントレスポンス型を意味し、T は返されたサーバー型を意味します。 |
3.16. Spring Cloud LoadBalancer 統計
MicrometerStatsLoadBalancerLifecycle
と呼ばれる LoadBalancerLifecycle
Bean が提供されており、これは Micrometer を使用して負荷分散された呼び出しの統計を提供します。
この Bean をアプリケーションコンテキストに追加するには、spring.cloud.loadbalancer.stats.micrometer.enabled
の値を true
に設定し、MeterRegistry
を使用できるようにします (たとえば、プロジェクトに Spring Boot Actuator を追加します)。
MicrometerStatsLoadBalancerLifecycle
は次のメーターを MeterRegistry
に登録します。
loadbalancer.requests.active
: 任意のサービスインスタンスの現在アクティブなリクエストの数を監視できるゲージ (サービスインスタンスデータはタグ経由で利用可能)。loadbalancer.requests.success
: 基礎となるクライアントにレスポンスを渡して終了した、負荷分散されたリクエストの実行時間を測定するタイマー。loadbalancer.requests.failed
: 例外で終了した負荷分散されたリクエストの実行時間を測定するタイマー。loadbalancer.requests.discard
: 破棄された負荷分散リクエスト、つまりリクエストを実行するサービスインスタンスが LoadBalancer によって取得されていないリクエストの数を測定するカウンター。
サービスインスタンス、リクエストデータ、レスポンスデータに関する追加情報は、利用可能な場合には常にタグを介してメトリクスに追加されます。
BlockingLoadBalancerClient などの一部の実装では、引数からジェネリクス型を確立し、型を判断してデータを読み取ることができない可能性があるため、リクエストデータとレスポンスデータが利用できない場合があります。 |
特定のメーターに少なくとも 1 つのレコードが追加されると、メーターはレジストリに登録されます。 |
MeterFilters を追加することで、これらのメトリクスの動作をさらに構成できます ( 公開パーセンタイルやヒストグラム (英語) の追加など)。 |
3.17. 個別の LoadBalancerClients の構成
個々のロードバランサークライアントは、異なるプレフィックス spring.cloud.loadbalancer.clients.<clientId>.
を使用して個別に構成できます。clientId
はロードバランサーの名前です。デフォルトの構成値は spring.cloud.loadbalancer.
名前空間で設定でき、優先されるクライアント固有の値とマージされます。
spring: cloud: loadbalancer: health-check: initial-delay: 1s clients: myclient: health-check: interval: 30s
上記の例では、initial-delay=1s
および interval=30s
とマージされたヘルスチェック @ConfigurationProperties
オブジェクトが生成されます。
クライアントごとの構成プロパティは、次のグローバルなプロパティを除き、ほとんどのプロパティで機能します。
spring.cloud.loadbalancer.enabled
- 負荷分散をグローバルに有効または無効にしますspring.cloud.loadbalancer.retry.enabled
- 負荷分散された再試行をグローバルに有効または無効にします。グローバルに有効にしても、client
-prefixed プロパティを使用して特定のクライアントの再試行を無効にすることはできますが、その逆はできません。spring.cloud.loadbalancer.cache.enabled
- LoadBalancer キャッシュをグローバルに有効または無効にします。グローバルに有効にした場合でも、ServiceInstanceListSupplier
デリゲート階層にCachingServiceInstanceListSupplier
を含まないカスタム構成を作成することで、特定のクライアントのキャッシュを無効にすることができますが、その逆はできません。spring.cloud.loadbalancer.stats.micrometer.enabled
- LoadBalancer Micrometer メトリクスをグローバルに有効または無効にします
すでに使用されている場所にマップされ、clients キーワードを使用せずにクライアントごとに異なる値を指定できるプロパティ ( hints 、health-check.path など) については、ライブラリの下位互換性を維持するためにその動作が維持されています。次のメジャーリリースで変更される予定です。 |
4.0.4 から、LoadBalancerProperties に callGetWithRequestOnDelegates フラグを導入しました。このフラグが true に設定されている場合、ServiceInstanceListSupplier#get(Request request) メソッドが実装され、そのメソッドをまだ実装していない DelegatingServiceInstanceListSupplier から割り当て可能なクラスで delegate.get(request) が呼び出されます。ただし、CachingServiceInstanceListSupplier と HealthCheckServiceInstanceListSupplier は除外されます。これらは、リクエストベースのフィルタリングが行われる前に、ネットワーク経由でインスタンスの取得を実行するサプライヤーの直後のインスタンスサプライヤー階層に配置する必要があります。4.0.x の場合、フラグはデフォルトで false に設定されていますが、4.1.0 以降はデフォルトで true に設定されます。 |
3.18. AOT およびネイティブイメージのサポート
4.0.0
以降、Spring Cloud LoadBalancer は Spring AOT 変換とネイティブイメージをサポートします。ただし、この機能を使用するには、LoadBalancerClient
サービス ID を明示的に定義する必要があります。これを行うには、@LoadBalancerClient
アノテーションの value
または name
属性を使用するか、spring.cloud.loadbalancer.eager-load.clients
プロパティの値として使用します。
4. Spring Cloud Circuit Breaker
4.1. 導入
Spring Cloud サーキットブレーカーは、さまざまなサーキットブレーカー実装にわたる抽象化を提供します。アプリケーションで使用する一貫した API が提供されるため、開発者はアプリケーションのニーズに最適なサーキットブレーカーの実装を選択できます。
4.1.1. サポートされている実装
Spring Cloud は、次のサーキットブレーカーの実装をサポートしています。
4.2. コアコンセプト
コード内にサーキットブレーカーを作成するには、CircuitBreakerFactory
API を使用できます。Spring Cloud Circuit Breaker スターターをクラスパスに含めると、この API を実装する Bean が自動的に作成されます。次の例は、この API の使用方法の簡単な例を示しています。
@Service
public static class DemoControllerService {
private RestTemplate rest;
private CircuitBreakerFactory cbFactory;
public DemoControllerService(RestTemplate rest, CircuitBreakerFactory cbFactory) {
this.rest = rest;
this.cbFactory = cbFactory;
}
public String slow() {
return cbFactory.create("slow").run(() -> rest.getForObject("/slow", String.class), throwable -> "fallback");
}
}
CircuitBreakerFactory.create
API は、CircuitBreaker
というクラスのインスタンスを作成します。run
メソッドは Supplier
と Function
を受け取ります。Supplier
は、サーキットブレーカーにラップするコードです。Function
は、サーキットブレーカーが作動した場合に実行されるフォールバックです。この関数には、フォールバックをトリガーした Throwable
が渡されます。フォールバックを提供したくない場合は、オプションでフォールバックを除外できます。
4.2.1. リアクティブコードのサーキットブレーカー
プロジェクト Reactor がクラスパス上にある場合は、リアクティブコードに ReactiveCircuitBreakerFactory
を使用することもできます。次の例は、その方法を示しています。
@Service
public static class DemoControllerService {
private ReactiveCircuitBreakerFactory cbFactory;
private WebClient webClient;
public DemoControllerService(WebClient webClient, ReactiveCircuitBreakerFactory cbFactory) {
this.webClient = webClient;
this.cbFactory = cbFactory;
}
public Mono<String> slow() {
return webClient.get().uri("/slow").retrieve().bodyToMono(String.class).transform(
it -> cbFactory.create("slow").run(it, throwable -> return Mono.just("fallback")));
}
}
ReactiveCircuitBreakerFactory.create
API は、ReactiveCircuitBreaker
というクラスのインスタンスを作成します。run
メソッドは、Mono
または Flux
を受け取り、それをサーキットブレーカーでラップします。オプションでフォールバック Function
をプロファイリングできます。フォールバック Function
は、サーキットブレーカーが作動し、障害の原因となった Throwable
が渡された場合に呼び出されます。
4.3. 構成
型 Customizer
の Bean を作成することで、サーキットブレーカーを構成できます。Customizer
インターフェースには、Object
を使用してカスタマイズする単一のメソッド ( customize
と呼ばれる) があります。
特定の実装をカスタマイズする方法の詳細については、次のドキュメントを参照してください。
Resilience4JCircuitBreaker
などの一部の CircuitBreaker
実装は、CircuitBreaker#run
が呼び出されるたびに customize
メソッドを呼び出します。非効率的になる可能性があります。その場合は、CircuitBreaker#once
メソッドを使用できます。これは、たとえば、Resilience4j のイベントを使用する (英語) 場合など、customize
を何度も呼び出すことが意味がない場合に役立ちます。
次の例は、各 io.github.resilience4j.circuitbreaker.CircuitBreaker
がイベントを消費する方法を示しています。
Customizer.once(circuitBreaker -> {
circuitBreaker.getEventPublisher()
.onStateTransition(event -> log.info("{}: {}", event.getCircuitBreakerName(), event.getStateTransition()));
}, CircuitBreaker::getName)
5. CachedRandomPropertySource
Spring Cloud Context は、キーに基づいてランダムな値をキャッシュする PropertySource
を提供します。キャッシュ機能以外では、Spring Boot の RandomValuePropertySource
[GitHub] (英語) と同じように動作します。このランダム値は、Spring アプリケーションコンテキストが再起動した後でも一貫したランダム値が必要な場合に便利です。プロパティ値は cachedrandom.[yourkey].[type]
の形式をとり、yourkey
はキャッシュ内のキーです。type
値には、Spring Boot の RandomValuePropertySource
でサポートされる任意の型を指定できます。
myrandom=${cachedrandom.appname.value}
6. セキュリティ
6.1. シングルサインオン
OAuth2 SSO およびリソースサーバー機能はすべて、バージョン 1.3 の Spring Boot に移行されました。ドキュメントは Spring Boot ユーザーガイドにあります。 |
6.1.1. クライアントトークンリレー
アプリが OAuth2 クライアントに面するユーザー (つまり、@EnableOAuth2Sso
または @EnableOAuth2Client
を宣言している) である場合、そのアプリは Spring Boot からのリクエストスコープに OAuth2ClientContext
を持ちます。このコンテキストとオートワイヤーされた OAuth2ProtectedResourceDetails
から独自の OAuth2RestTemplate
を作成すると、コンテキストは常にアクセストークンをダウンストリームに転送し、有効期限が切れた場合はアクセストークンを自動的にリフレッシュします。(Spring Security、Spring Boot の特長です。)
6.1.2. リソースサーバートークンリレー
アプリに @EnableResourceServer
がある場合は、受信トークンをダウンストリームで他のサービスに中継することをお勧めします。RestTemplate
を使用してダウンストリームサービスに接続する場合、これは適切なコンテキストを使用してテンプレートを作成する方法だけの問題です。
サービスが受信トークンの認証に UserInfoTokenServices
を使用している場合 (つまり、security.oauth2.user-info-uri
構成を使用している場合)、オートワイヤーされた OAuth2ClientContext
を使用して OAuth2RestTemplate
を簡単に作成できます (バックエンドコードに到達する前に認証プロセスによって設定されます)。同様に (Spring Boot 1.4 を使用する場合)、UserInfoRestTemplateFactory
を挿入し、構成内でその OAuth2RestTemplate
を取得できます。例:
@Bean
public OAuth2RestTemplate restTemplate(UserInfoRestTemplateFactory factory) {
return factory.getUserInfoRestTemplate();
}
この Rest テンプレートには、認証フィルターで使用されるものと同じ OAuth2ClientContext
(リクエストスコープ) が含まれるため、それを使用して同じアクセストークンでリクエストを送信できます。
アプリが UserInfoTokenServices
を使用していなくてもクライアントである場合 (つまり、@EnableOAuth2Client
または @EnableOAuth2Sso
を宣言している場合)、Spring Security Cloud では、ユーザーが @Autowired
OAuth2Context
から作成した OAuth2RestOperations
もトークンを転送します。この機能はデフォルトで MVC ハンドラーインターセプターとして実装されるため、Spring MVC でのみ動作します。MVC を使用していない場合は、AccessTokenContextRelay
をラップするカスタムフィルターまたは AOP インターセプターを使用して、同じ機能を提供できます。
以下は、他の場所で作成されたオートワイヤーされた REST テンプレートの使用を示す基本的な例です ("foo.com" は、周囲のアプリと同じトークンを受け入れるリソースサーバーです)。
@Autowired
private OAuth2RestOperations restTemplate;
@RequestMapping("/relay")
public String relay() {
ResponseEntity<String> response =
restTemplate.getForEntity("https://foo.com/bar", String.class);
return "Success! (" + response.getBody() + ")";
}
トークンを転送したくない場合 (トークンを送信したクライアントではなく、自分自身として動作する可能性があるため、これは有効な選択です)、必要なのは、デフォルトのもの。
偽のクライアントは、OAuth2ClientContext
が利用可能な場合はそれを使用するインターセプターも選択するため、RestTemplate
が実行する場所であればどこでもトークンリレーを実行する必要があります。
7. プロパティの構成
Spring Cloud Commons に関連するすべての構成プロパティのリストを表示するには、付録ページを確認してください。