1. 分離とダウングレード
電流制限は予防策です。電流制限により、同時実行性の高さによって引き起こされるサービス障害を回避できますが、他の理由でサービスが失敗する可能性もあります。
これらの障害を特定の範囲内で制御し、雪崩を回避するには、スレッド分離(バルクウォール モード) とヒューズのダウングレード方法に依存する必要があります。
スレッド分離: サービス プロバイダーを呼び出すとき、呼び出し元は呼び出しリクエストごとに独立したスレッド プールを割り当てます。障害が発生した場合、呼び出し元のすべてのリソースが使い果たされるのを避けるために、最大でもこのスレッド プール内のリソースが消費されます。
ヒューズダウングレード: サービスプロバイダーへの通話をカウントするために発信者側にサーキットブレーカーを追加するもので、通話の失敗率が高すぎるとサービスが切断され、サービスプロバイダーへのアクセスが許可されなくなります。
スレッドの分離であっても、ヒューズのダウングレードであっても、それがクライアント(呼び出し元) の保護であることがわかります。呼び出し元がリモート呼び出しを開始するときに、スレッド分離またはサービス融合を実行する必要があります。
また、マイクロサービスのリモート呼び出しはすべて Feign に基づいているため、Feign を Sentinel と統合し、Feign にスレッド分離とサービス ヒューズを実装する必要があります。
1.1、FeignClient は Sentinel を統合します
Spring Cloud では、マイクロサービス呼び出しはすべて Feign を通じて実装されるため、クライアント保護のために Feign と Sentinel を統合する必要があります。
設定を変更してセンチネル機能を有効にする
OrderService の application.yml ファイルを変更して、Feign の Sentinel 機能を有効にします。
feign: sentinel: enabled: true # 开启feign对sentinel的支持
書き込み失敗のダウングレードロジック
ビジネスの失敗後、エラーを直接報告することはできませんが、わかりやすいプロンプトまたはデフォルトの結果がユーザーに返される必要があります。これが失敗のダウングレード ロジックです。
障害後の FeignClient のダウングレード ロジックを作成する
① 方法 1: FallbackClass はリモート呼び出しの例外を処理できません
②方法 2: リモート呼び出しの例外を処理できる FallbackFactory を選択します。
ここでは、2 番目の方法の障害ダウングレード処理を示します。
ステップ 1 : Feeding-API プロジェクトでクラスを定義して FallbackFactory を実装します。
コード:
@Slf4j public class UserClientFallbackFactory implements FallbackFactory<UserClient> { @Override public UserClient create(Throwable throwable) { return new UserClient() { @Override public User findById(Long id) { log.error("查询用户异常", throwable); return new User(); } }; } }
ステップ 2 : Feeding-API プロジェクトの DefaultFeignConfiguration クラスに UserClientFallbackFactory を Bean として登録します。
@Bean public UserClientFallbackFactory userClientFallbackFactory(){ return new UserClientFallbackFactory(); }
ステップ 3 : feed-api プロジェクトの UserClient インターフェイスで UserClientFallbackFactory を使用します。
@FeignClient(value = "userservice", fallbackFactory = UserClientFallbackFactory.class) public interface UserClient { @GetMapping("/user/{id}") User findById(@PathVariable("id") Long id); }
再起動後、注文クエリ サービスに一度アクセスし、センチネル コンソールを確認すると、新しいクラスター ポイントのリンクが表示されます。
要約する
Sentinel がサポートする Avalanche ソリューション:
-
スレッド分離 (サイロ壁モード)
-
サーキットブレーカーのダウングレード
Feign が Sentinel を統合する手順:
-
application.yml で設定します: feign.sentienl.enable=true
-
FeignClient用のFallbackFactoryを記述しBeanとして登録する
-
FallbackFactory を FeignClient に構成する
1.2. スレッド分離 (バルクウォール モード)
スレッド分離の実装
スレッドの分離は次の 2 つの方法で実現できます。
スレッドプールの分離
セマフォ分離 (Sentinel はデフォルトで使用します)
図に示すように:
スレッドプール分離: 各サービスコールビジネスにスレッドプールを割り当て、スレッドプール自体を使用して分離効果を実現します
セマフォ分離: スレッド プールを作成する代わりに、カウンター モードを使用してビジネスで使用されるスレッド数を記録し、セマフォの上限に達すると、新しいリクエストを禁止します。
両方の長所と短所:
センチネルのスレッド分離
使用説明書:
スロットリング ルールを追加する場合、次の 2 つのしきい値タイプを選択できます。
QPS: クイック スタートで示されている、1 秒あたりのリクエストの数です。
スレッド数: このリソースで使用できる Tomcat スレッドの最大数です。つまり、スレッドの数を制限することで、スレッドの分離(バルクウォール モード) が実現されます。
ケース要件: order-service サービスの UserClient のクエリ ユーザー インターフェイスのフロー制御ルールを設定し、スレッド数が 2 を超えることはできません。次に、jemeter を使用してテストします。
1) 分離ルールを構成する
偽インターフェイスの背後にあるフロー制御ボタンを選択します。
フォームに記入する:
2) Jmeterテスト
「しきい値の種類 - スレッド数 < 2」を選択します。
実行結果を確認します。
結果はすべて渡されますが、一部のリクエストに対する応答はダウングレードによって返される null 情報であることがわかります。
要約する
スレッド分離の 2 つの手段は何ですか?
-
セマフォの分離
-
スレッドプールの分離
セマフォ分離の特徴は何ですか?
-
カウンタモードに基づいており、シンプルでオーバーヘッドが低い
スレッド プール分離の特徴は何ですか?
-
スレッド プール モードに基づいて追加のオーバーヘッドがありますが、分離制御はより強力です
1.3、ヒューズのダウングレード
ヒューズのダウングレードは、雪崩問題を解決する重要な手段です。その考え方は、サーキット ブレーカーがサービス コールの異常な割合と遅いリクエストの割合をカウントし、しきい値を超えるとサービスが中断されるというものです。つまり、サービスへのアクセス要求はすべて傍受され、サービスが復元されると、サーキット ブレーカーはサービスへのアクセス要求を解放します。
サーキット ブレーカーの制御の溶断と解放は、ステート マシンを通じて行われます。
ステート マシンは 3 つの状態で構成されます。
-
クローズド: クローズ状態。サーキット ブレーカーはすべてのリクエストを解放し、例外と遅いリクエストの割合のカウントを開始します。閾値を超えるとオープン状態に切り替わります
-
open: オープン状態では、サービス呼び出しは中断され、中断されたサービスへのアクセス要求は拒否され、フェイルファストして、ダウングレード ロジックに直接進みます。オープン状態で5秒後、半オープン状態になります。
-
ハーフオープン: ハーフオープン状態ではリクエストが解放され、実行結果に応じて次の動作が判断されます。
-
リクエストは成功しました。クローズ状態に切り替わります。
-
リクエストが失敗しました: オープン状態に切り替えます
-
サーキットブレーカーのヒューズ戦略には、スローコール、異常比率、異常数の 3 種類があります。
1.3.1、遅い通話
遅い通話: サービス応答時間 (RT) が指定された時間より長いリクエストは、遅い通話リクエストとみなされます。指定された時間内に、リクエストの数が設定された最小数を超え、低速コールの割合が設定されたしきい値より大きい場合、サーキット ブレーカーがトリガーされます。
例えば:
解釈: RT が 500 ミリ秒を超えるコールは低速コールです。最後の 10,000 ミリ秒以内のリクエストを数えます。リクエストの数が 10 を超え、低速コールの割合が 0.5 以上の場合、サーキット ブレーカーがトリガーされます。サーキットブレーカーは 5 秒間持続します。その後、ハーフオープン状態に入り、テスト用のリクエストをリリースします。
ケース
要件: UserClient のクエリ ユーザー インターフェイスのダウングレード ルールを設定します。低速呼び出しの RT しきい値は 50 ミリ秒、統計時間は 1 秒、リクエストの最小数は 5、失敗しきい値の比率は 0.4、ヒューズ期間は 5 です。
1) 低速通話を設定する
user-service の /user/{id} インターフェースのサービスを変更します。スリープによる遅延時間をシミュレートします。
この時点で、orderId=101 の注文は ID が 1 のユーザーに関連付けられており、呼び出し時間は 60 ミリ秒です。
2) ヒューズルールを設定する
次に、feign インターフェイスのダウングレード ルールを設定します。
50ミリ秒を超えるリクエストは遅いリクエストとみなされます
3) テスト
ブラウザでhttp://localhost:8088/order/101 にアクセスし、すばやく 5 回更新すると、次の情報が見つかります。
サーキット ブレーカーがトリガーされ、リクエスト期間が 5ms に短縮され、すぐに失敗し、劣化したロジックに従い、null が返されました。
ブラウザでアクセスします: http://localhost:8088/order/102、これもブローされました:
1.3.2. 異常率と異常数
異常割合または異常数:指定した期間内のコール数をカウントし、コール数が指定したリクエスト数を超え、かつ異常の割合が設定した割合のしきい値に達した場合(または指定した異常数を超えた場合)、サーキットブレーカーが作動します。引き金になった。
たとえば、通常とは異なるスケール設定:
解釈: 過去 1000 ミリ秒以内のリクエストをカウントし、リクエスト数が 10 を超え、異常率が 0.4 以上の場合、サーキット ブレーカーが作動します。
例外番号の設定:
解釈: 過去 1000 ミリ秒以内のリクエストをカウントし、リクエスト数が 10 を超え、異常比率が 2 以上の場合、サーキット ブレーカーがトリガーされます。
ケース
要件: UserClient のクエリ ユーザー インターフェイスのダウングレード ルールを設定します。統計時間は 1 秒、リクエストの最小数は 5、失敗しきい値比率は 0.4、ヒューズ期間は 5 秒です。
1) 例外リクエストの設定
まず、user-service のインターフェイス /user/{id} のビジネスを変更します。手動で例外をスローして、異常な比率でサーキット ブレーカーをトリガーします。
つまり、ID が 2 の場合、例外がトリガーされます。
2) ヒューズルールを設定する
次に、feign インターフェイスのダウングレード ルールを設定します。
5 つのリクエストでは、例外率が 0.4 を超える限り、つまり例外が 2 つ以上ある限り、サーキット ブレーカーがトリガーされます。
3) テスト
ブラウザでhttp://localhost:8088/order/102 にすばやくアクセスし、すばやく 5 回更新して、サーキット ブレーカーをトリガーします。
この時点で、103 にアクセスします。これは正常であるはずです。
2. 認可ルール
認可ルールは、要求元のソースを判断および制御できます。
2.1. 基本ルール
認可ルールは呼び出し元を制御でき、ホワイト リストとブラック リストの 2 つの方法があります。
-
ホワイトリスト: 発信元がホワイトリストに含まれている発信者はアクセスを許可されます。
-
ブラックリスト: 発信元がブラックリストに含まれている発信者はアクセスを許可されません
左側のメニューの「認可」をクリックして、認可ルールを表示します。
-
リソース名: /order/{orderId} などの保護されたリソースです。
-
フロー制御アプリケーション: ソースのリストです。
-
ホワイト リストがチェックされている場合、リスト内のソースへのアクセスが許可されます。
-
ブラックリストがチェックされている場合、リスト内のソースへのアクセスは禁止されます。
-
例えば:
ゲートウェイから order-service へのリクエストは許可されますが、ブラウザーが order-service にアクセスすることは許可されないため、ゲートウェイのソース名 (オリジン) をホワイト リストに入力する必要があります。
2.2. 原点の取得方法
Sentinel は、RequestOriginParser インターフェイスの parseOrigin を通じてリクエストのソースを取得します。
public interface RequestOriginParser {
/**
* 从请求request对象中获取origin,获取方式自定义
*/
String parseOrigin(HttpServletRequest request);
}
このメソッドの機能は、リクエスト オブジェクトからリクエスターの元の値を取得し、それを返すことです。
デフォルトでは、リクエスタの送信元に関係なく、sentinel は常にデフォルト値を返します。これは、すべてのリクエストのソースが同じデフォルト値であるとみなされることを意味します。
したがって、異なるリクエストが異なるオリジンを返せるように、このインターフェースの実装をカスタマイズする必要があります。
たとえば、order-service サービスでは、RequestOriginParser の実装クラスを定義します。
@Component
public class HeaderOriginParser implements RequestOriginParser {
@Override
public String parseOrigin(HttpServletRequest request) {
// 1.获取请求头
String origin = request.getHeader("origin");
// 2.非空判断
if (StringUtils.isEmpty(origin)) {
origin = "blank";
}
return origin;
}
}
リクエストヘッダーから元の値を取得しようとします。
2.3. ゲートウェイにリクエストヘッダーを追加する
リクエストの送信元を取得する方法は、リクエスト ヘッダーから送信元の値を取得することなので、ゲートウェイからマイクロサービスにルーティングされるすべてのリクエストに送信元ヘッダーを持たせる必要があります。
これは、以前に学習した GatewayFilter、AddRequestHeaderGatewayFilter を使用して実現する必要があります。
ゲートウェイ サービスの application.yml を変更し、defaultFilter を追加します。
spring:
cloud:
gateway:
default-filters:
- AddRequestHeader=origin,gateway
routes:
# ...略
このようにして、ゲートウェイからルーティングされるすべてのリクエストには、値ゲートウェイを含むオリジン ヘッダーが含まれます。他の場所からマイクロサービスに到着するリクエストには、このヘッダーがありません。
2.4. 認可ルールの設定
次に、元の値がゲートウェイであるリクエストを許可する認可ルールを追加します。
構成は次のとおりです。
ここで、ゲートウェイを直接スキップして、order-service サービスにアクセスします。
ゲートウェイ経由でアクセスします。
2.5. カスタム例外の結果
デフォルトでは、電流制限、ダウングレード、または認可インターセプトが発生すると、呼び出し元に例外がスローされます。異常な結果は流量制限(電流制限)です。これは十分に友好的ではなく、電流制限なのか、ダウングレードなのか、それとも許可された傍受なのかを知ることは不可能です。
例外の種類
また、例外が発生したときに返される結果をカスタマイズしたい場合は、BlockExceptionHandler インターフェイスを実装する必要があります。
public interface BlockExceptionHandler { /** * 处理请求被限流、降级、授权拦截时抛出的异常:BlockException */ void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception; }
このメソッドには 3 つのパラメータがあります。
HttpServletRequest リクエスト:リクエスト对象
HttpServletResponse 応答:応答オブジェクト
BlockException e: センチネルによってインターセプトされたときにスローされる例外
ここの BlockException には、いくつかの異なるサブクラスが含まれています。
異常な 説明する フロー例外 電流制限例外 ParamFlowException 異常なホットスポットパラメータの電流制限 劣化例外 ダウングレード例外 権限例外 認可ルールの例外 システムブロック例外 システムルール例外
カスタム例外処理
次に、order-service でカスタム例外処理クラスを定義します。
@Component public class SentinelExceptionHandler implements BlockExceptionHandler { @Override public void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception { String msg = "未知异常"; int status = 429; if (e instanceof FlowException) { msg = "请求被限流了"; } else if (e instanceof ParamFlowException) { msg = "请求被热点参数限流"; } else if (e instanceof DegradeException) { msg = "请求被降级了"; } else if (e instanceof AuthorityException) { msg = "没有权限访问"; status = 401; } response.setContentType("application/json;charset=utf-8"); response.setStatus(status); response.getWriter().println("{\"msg\": " + msg + ", \"status\": " + status + "}"); } }
テストを再開すると、さまざまなシナリオで、さまざまな例外メッセージが返されます。
制限:
傍受を許可する場合:
3. ルールの永続性
現在、センチネルのすべてのルールはメモリに保存されており、再起動するとすべてのルールが失われます。運用環境では、損失を避けるためにこれらのルールの永続性を確保する必要があります。
3.1、ルール管理モード
ルールを永続化できるかどうかは、ルール管理モードによって異なります。Sentinel は、次の 3 つのルール管理モードをサポートしています。
-
オリジナル モード: Sentinel のデフォルト モード。ルールはメモリに保存され、サービスを再起動するとサービスは失われます。
-
プルモード
-
プッシュモード
プルモード
プル モード: コンソールは構成されたルールを Sentinel クライアントにプッシュし、クライアントは構成されたルールをローカル ファイルまたはデータベースに保存します。将来的には、ローカル ファイルまたはデータベースに定期的にクエリを実行して、ローカル ルールを更新する予定です。
プッシュモード
プッシュ モード: コンソールは、Nacos などのリモート構成センターに構成ルールをプッシュします。Sentinel クライアントは Nacos を監視し、設定変更のプッシュ メッセージを取得し、ローカル設定の更新を完了します。
3.2. プッシュモードの実現
項目を変更する
Nacos のセンチネル ルール設定をリッスンするようにプロジェクトを変更します。
1. 依存関係を導入する
order-service で nacos の依存関係を監視するためにセンチネルを導入します。
<dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-datasource-nacos</artifactId> </dependency>
2.nacosアドレスを設定する
nacos アドレスを構成し、order-service の application.yml ファイルで構成情報をモニターします。
spring: cloud: sentinel: datasource: flow: nacos: server-addr: localhost:8848 # nacos地址 dataId: orderservice-flow-rules groupId: SENTINEL_GROUP rule-type: flow # 还可以是:degrade、authority、param-flow
センチネル ダッシュボードのソース コードを変更する
SentinelDashboard はデフォルトでは nacos 永続性をサポートしていないため、ソース コードを変更する必要があります。
IDEA でセンチネル ソース パッケージを開く
1. nacos の依存関係を変更する
Sentinel-dashboard ソース コードの pom ファイルでは、nacos はテストのデフォルト スコープに依存しており、テスト中にのみ使用できます。ここでは削除する必要があります。
Sentinel-datasource-nacos が依存するスコープを削除します。
<dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-datasource-nacos</artifactId> </dependency>
2.nacos サポートを追加する
Sentinel-dashboard のテスト パッケージには nacos のサポートが記述されているので、これを main にコピーする必要があります。
3.nacosアドレスを変更する
次に、テスト コード内の NacosConfig クラスも変更する必要があります。
nacos アドレスを変更し、application.properties の設定を読み取れるようにします。
nacos アドレス設定を Sentinel-dashboard の application.properties に追加します。
nacos.addr=localhost:8848
4. nacos データソースの構成
さらに、com.alibaba.csp.sentinel.dashboard.controller.v2 パッケージの下の FlowControllerV2 クラスを変更する必要があります。
追加した Nacos データ ソースを有効にします
5. フロントエンドページを変更する
次に、フロントエンド ページを変更し、nacos をサポートするメニューを追加します。
src/main/webapp/resources/app/scripts/directives/sidebar/ ディレクトリ内のsidebar.html ファイルを変更します。
コメントのこの部分をオンにします。
その中のテキストを変更します。
6. プロジェクトを再コンパイルしてパッケージ化する
IDEA で Maven プラグインを実行し、変更した Sentinel-Dashboard をコンパイルしてパッケージ化します。
7.スタート
起動方法は公式と同じです。
java -jar sentinel-dashboard.jar
nacos アドレスを変更する場合は、パラメーターを追加する必要があります。
java -jar -Dnacos.addr=localhost:8848 sentinel-dashboard.jar