10. ハイストリックスサーキットブレーカー
- Hystrix サービスデグレードフレームワーク SpringCloud は正式に更新を停止しましたが、その設計思想は非常に優れており、サービスデグレード、サービスサーキットブレーカー、サービス電流制限など、その一連の考え方は後続のフレームワークが学ぶべき必須の薬となっています。したがって、Hystrix について詳しく調べる必要があります。
- 現在公式サイトでは resilience4j の使用を推奨していますが、海外では resilience4j の方が一般的に使われています。
- 中国では主に Hystrix または Sentienl (Alibaba) を使用します。
- コンシューマ側とサービス側の両方で使用でき、一般的にはコンシューマ側で使用されます。
10.1 概要
10.1.1 分散システムが直面する問題
-
分散システムが直面する問題
复杂分布式体系结构中的应用程序有数十个依赖关系,每个依赖关系在某些时候将不可避免地失败。
-
サービス雪崩
- 複数のマイクロサービス間で呼び出しを行う場合、マイクロサービス A がマイクロサービス B とマイクロサービス C を呼び出し、マイクロサービス B とマイクロサービス C が他のマイクロサービスを呼び出すとします
“扇出”
。ファンアウト リンク上の特定のマイクロサービスの呼び出し応答時間が長すぎるか、使用できない場合、マイクロサービス A への呼び出しがますます多くのシステム リソースを占有し、システムのクラッシュ、いわゆる「雪崩効果」が発生します。 - 高トラフィックのアプリケーションの場合、単一のバックエンド依存関係により、すべてのサーバー上のすべてのリソースが数秒以内に飽和する可能性があります。障害よりもさらに悪いことに、これらのアプリケーションはサービス間の遅延を増加させ、バックアップ キュー、スレッド、その他のシステム リソースに負担をかけ、システム全体でさらに連鎖的な障害を引き起こす可能性があります。これらはすべて、単一の依存関係の障害によってアプリケーションやシステム全体がダウンしないように、障害と遅延を分離して管理する必要性を表しています。したがって、通常、モジュール配下のインスタンスに障害が発生したことが判明した場合、そのモジュールは引き続きトラフィックを受信し、問題のあるモジュールも他のモジュールを呼び出すため、カスケード障害 (雪崩) が発生します。
- 複数のマイクロサービス間で呼び出しを行う場合、マイクロサービス A がマイクロサービス B とマイクロサービス C を呼び出し、マイクロサービス B とマイクロサービス C が他のマイクロサービスを呼び出すとします
-
例: サービス 80 は 8001 を呼び出し、8001 は 8002 を呼び出し、8002 は 8004 を呼び出し、8004 は 8006 を呼び出します。お互いを 1 つずつ呼び出していくと、リンクはますます長くなります。そのうちの 1 つが失敗すると、すべてのサービスに問題が発生します。
10.1.2 とは
- Hystrix は、分散システムを処理するために使用される
延迟
オープン容错
ソース ライブラリです。分散システムでは、タイムアウトや例外など、多くの依存関係が必然的に呼び出しに失敗します。Hystrix は、依存関係が間違った場合に不会导致整体服务失败,避免级联故障,以提高分布式系统的弹性
、 - 「サーキット ブレーカー」自体はスイッチング デバイスであり、サービス ユニットに障害が発生した場合、サーキット ブレーカーの障害監視 (ヒューズが切れるのと同様) によって、
向调用方返回一个符合预期的、可处理的备选响应(FallBack),而不是长时间的等待或者抛出调用方无法处理的异常
サービス呼び出し元のスレッドが長時間不必要にブロックされないようにすることができます。土地が占有されているため、分散システム内の断層の拡大や雪崩さえも回避されます。
10.1.3 できること
- サービスのダウングレード
- サービスサーキットブレーカー
- ほぼリアルタイムのモニタリング
- …
10.1.4 公式ウェブサイトの情報
- 公式ウェブサイト情報: https://github.com/Netflix/Hystrix/wiki/How-To-Use
10.1.5 Hystrix公式発表、メンテナンスのためアップデート停止
- https://github.com/Netflix/Hystrix
- 受動的にバグを修正する
- マージリクエストは受け付けられなくなりました
- もう新しいリリースはありません
10.2 Hystrix の重要な概念
10.2.1 サービスのダウングレードのフォールバック
- サーバーがビジーです。クライアントを待たせずに、後でもう一度試してください。すぐにフレンドリーなプロンプトを返します。フォールバック
- つまり、if-else 構造と同様に、相手のシステムが利用できないため、明確な解決策を提供する必要があります。
- どのような状況でダウングレードが発生しますか?
- プログラムが異常に動作する
- タイムアウト
- サービスサーキットブレーカーがサービス低下を引き起こす
- スレッド プール/セマフォがいっぱいになると、サービスの低下が発生します。
10.2.2 サービス中断
- アナログ ヒューズが最大サービス アクセスに達すると、アクセスは直接拒否され、電源が切断され、サービス ダウングレード メソッドが呼び出され、わかりやすいプロンプトが返されます。
- それはヒューズです。サービスの低下 -> その後ヒューズ -> 通話リンクを復元します
- サービスの中断もダウングレードの一種とみなすことができます。
10.2.3 サービスフロー制限 flowlimit
- 同時実行性の高いフラッシュキルなどの操作は密集が厳禁で、全員が1秒間にN回並び、整然と進められます。
10.3 ヒストリックス事件
- 複数のサービスを起動するのは面倒なので、テスト用にスタンドアロン版に変更しました。
- 7001 をスタンドアロン バージョンに復元
- 7001 をスタンドアロン バージョンに復元
10.3.1 ビルド
1) 新しいクラウドプロバイダー-hystrix-payment8001 を作成します。
- ヒストリックスが吹き飛ばされた 8001 を作成する
2)ポム
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>cloud2020</artifactId>
<groupId>com.angenin.springcloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-provider-hystrix-payment8001</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<!--hystrix-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<!--eureka client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency><!-- 引入自己定义的api通用包,可以使用Payment支付Entity -->
<groupId>com.angenin.springcloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
3)YML
server:
port: 8001
spring:
application:
name: cloud-provider-hystrix-payment
eureka:
client:
register-with-eureka: true
fetch-registry: true
service-url:
#集群版
#defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
#单机版
defaultZone: http://eureka7001.com:7001/eureka
4) メイン起動
package com.angenin.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@EnableEurekaClient
@SpringBootApplication
public class PaymentHystrixMain8001 {
public static void main(String[] args) {
SpringApplication.run(PaymentHystrixMain8001.class, args);
}
}
5) 業種
- service : 通常はインターフェースとインターフェース実装クラスを記述する必要がありますが、時間を節約するために実装クラスを直接記述します。
package com.angenin.springcloud.service;
import org.springframework.stereotype.Service;
import java.util.concurrent.TimeUnit;
@Service
public class PaymentService {
//正常访问方法
public String paymentInfo_OK(Integer id){
//如果正常访问则,返回当前线程池的名字、传入的id、表情包
return "线程池: "+Thread.currentThread().getName()+" paymentInfo_OK,id: "+id+"\t"+"O(∩_∩)O哈哈~";
}
//超时访问方法
public String paymentInfo_TimeOut(Integer id){
//前面学过时会导致服务降级,模拟错误
int timeNumber = 3;
try {
TimeUnit.SECONDS.sleep(timeNumber);
} catch (InterruptedException e) {
e.printStackTrace();
}
//超时返回的提示信息
return "线程池:" + Thread.currentThread().getName() +
"paymentInfo_TimeOut,id:" +id+"\t"+"O(∩_∩)O哈哈~"+" 耗时(秒):"+timeNumber;
}
}
- コントローラ
package com.angenin.springcloud.controller;
import com.angenin.springcloud.service.PaymentService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@Slf4j
@RestController
public class PaymentController {
@Resource
PaymentService paymentService;
@Value("${server.port}") //spring的@Value注解
private String ServerPort;
//正常
@GetMapping("/payment/hystrix/ok/{id}")
public String paymentInfo_OK(@PathVariable("id") Integer id){
String result = paymentService.paymentInfo_OK(id);
log.info("******result:" + result);
return result;
}
//超时
@GetMapping("/payment/hystrix/timeout/{id}")
public String paymentInfo_TimeOut(@PathVariable("id") Integer id){
String result = paymentService.paymentInfo_TimeOut(id);
log.info("******result:" + result);
return result;
}
}
6) 通常テスト
-
エウレカ7001をスタート
-
クラウドプロバイダー-hystrix-payment8001 を開始します
-
アクセス: すべての人が正しくアクセスして結果を返すことができます。
-
成功方法: http://localhost:8001/payment/hystrix/ok/4
-
各呼び出しには 3 秒かかります: http://localhost:8001/payment/hystrix/timeout/4
-
-
上記のモジュールはすべて OK です。上記を基本プラットフォームとして使用し、正しい -> エラー -> サーキット ブレーカーのダウングレード -> 回復の順に進みます。
10.3.2 高度な同時実行テスト
- 上記は、同時実行性が高くない状況でもかろうじて要件を満たすことができますが、...
1) Jmeterストレステスト
-
Jmeter を開くと、20,000 の同時リクエストが 8001 をクラッシュし、20,000 のリクエストはすべてpaymentInfo_TimeOut サービスにアクセスします
。
-
エウレカ7001をスタート
-
クラウドプロバイダー-hystrix-payment8001 を開始します
-
2 つのメソッドにそれぞれアクセスし、デモンストレーション結果を表示します (セルフテスト)
- 成功方法: http://localhost:8001/payment/hystrix/ok/4
- 各呼び出しには 3 秒かかります: http://localhost:8001/payment/hystrix/timeout/4
-
結果:
- どちらも勝手にぐるぐる回っています
- アクセスに成功したメソッドはすぐに結果を返しますが、アクセスしたメソッドは結果を返すまでに3秒かかります(スレッド数が少なく、2スレッドしかありません)。
- 現在: 両方のメソッドが円を描くように回転し、この成功したメソッドも速度が低下していることを示します (多数のスレッド、20,000 + 2 スレッド)
- なぜ詰まってしまうのでしょうか?
- Tomcat のデフォルトの作業スレッド数はいっぱいであり、圧力を分解して処理するための追加のスレッドはありません。(Springboot はデフォルトで Tomact を統合します。これには Tomact コンテナー用のスレッド プールがあります)
- 同じマイクロサービスにアクセスするには 2 つの方法があります。マイクロサービスは、同時実行性の高いリクエストを処理するためにリソースを集中させます。負荷がかかるとリソースが消耗されるため、成功したアクセス方法も遅れや遅延の影響を受けます。
- どちらも勝手にぐるぐる回っています
2) Jmeter 圧力テストの結論
- これはまだサービスであり
提供者8001自己测试
、このタイミングで外部の消費者80も来訪すると消费者
、ただ待つことしかできず、最終的には消費者80の不満が高まり、サーバ8001はそのまま死に至ることになる。
3) 大事なことを軽視せず、楽しさを見て、80 人の新メンバーが参加
-
新しいcloud-consumer-feign-hystrix-order80を作成します
-
POM
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>cloud2020</artifactId>
<groupId>com.angenin.springcloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-consumer-feign-hystrix-order80</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<!--openfeign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!--hystrix-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<!--eureka client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!-- 引入自己定义的api通用包,可以使用Payment支付Entity -->
<dependency>
<groupId>com.angenin.springcloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>${project.version}</version>
</dependency>
<!--web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--一般基础通用配置-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
- YML
server:
port: 80
eureka:
client:
register-with-eureka: false
service-url:
defaultZone: http://eureka7001.com:7001/eureka/
- メインブート
package com.angenin.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableFeignClients //激活feifn
public class OrderHystrixMain80
{
public static void main(String[] args) {
SpringApplication.run(OrderHystrixMain80.class,args);
}
}
- ビジネスクラス (PaymentHystrixService、OrderHystirxController)
package com.angenin.springcloud.service;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@Component
//调用的微服务名
@FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT" )
public interface PaymentHystrixService
{
@GetMapping("/payment/hystrix/ok/{id}")
public String paymentInfo_OK(@PathVariable("id") Integer id);
@GetMapping("/payment/hystrix/timeout/{id}")
public String paymentInfo_TimeOut(@PathVariable("id") Integer id);
}
-----------------------------------------------------------
package com.angenin.springcloud.controller;
import com.angenin.springcloud.service.PaymentHystrixService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@RestController
@Slf4j
public class OrderHystirxController {
@Resource
private PaymentHystrixService paymentHystrixService;
//调用ok方法
@GetMapping("/consumer/payment/hystrix/ok/{id}")
public String paymentInfo_OK(@PathVariable("id") Integer id) {
String result = paymentHystrixService.paymentInfo_OK(id);
return result;
}
//调用超时方法
@GetMapping("/consumer/payment/hystrix/timeout/{id}")
public String paymentInfo_TimeOut(@PathVariable("id") Integer id) {
String result = paymentHystrixService.paymentInfo_TimeOut(id);
return result;
}
}
-
通常のテスト
-
開始 7001、8001、80
-
アクセスOK: http://localhost/consumer/payment/hystrix/ok/4 (速度も非常に速いです)
-
-
高度な同時実行テスト
- 2Wスレッドプレス8001
- 次に、コンシューマ側 80 マイクロサービスは、通常の Ok マイクロサービス 8001 アドレスにアクセスします。
- http://localhost/consumer/payment/hystrix/ok/32
- 効果:
- または、グルグルと待機すると、結果が返されるまでにしばらく時間がかかります。
- または、コンシューマがタイムアウト エラーを報告する
10.3.3 故障現象と原因
- 8001 Tomcat スレッド プール内の作業スレッドが占有されているため、同じレベルの他のインターフェイス サービスがトラップされます。
- この時点で 80 が 8001 を呼び出しますが、クライアント アクセスの応答が遅く、ぐるぐる回っています。
10.3.4 控訴の終結
- 上記の障害やパフォーマンスの低下があったからこそ、当社のダウングレード/フォールトトレランス/電流制限などのテクノロジーが誕生しました。
10.3.5 どうすれば解決できますか? 解決された要件
- タイムアウトによりサーバーが遅くなります (ぐるぐる回転): タイムアウト後に待つ必要はありません
- エラー (ダウンタイムまたはプログラム操作エラー): エラーを明確に理解していることを確認してください。
- 解決策:
- 相手のサービス (8001) がタイムアウトしました。発信者 (80) が永遠に待機しているわけにはいきません。サービスのダウングレードが必要です。
- 相手のサービス (8001) がダウンしています。発信者 (80) が永遠に待機しているわけにはいきません。サービスのダウングレードが必要です。
- 相手のサービス (8001) は正常ですが、呼び出し元 (80) は失敗するか、独自の要件 (サービス プロバイダーよりも待ち時間が短い) があるため、ダウングレード自体を処理します。
10.3.6 サービスの低下
1) ダウングレード構成
- @HystrixCommand
- 現在では、コーディングではなく実際の設定が基本的に使用されます。
2) 8001 はまず内部の問題を探します。
- 独自の通話タイムアウトのピーク値を設定します。ピーク値以内であれば通常の動作が可能ですが、ピーク値を超えた場合は、サービス低下に備えたバックアップ方法で対処する必要があります。
3)8001フォールバック
プロデューサーのダウングレード: タイムアウト メソッドのデフォルトのピーク値は 3 秒ですが、現在は 5 秒間スリープするため、ダウングレードして隠蔽メソッドを実行する必要があります。
- ビジネスクラス対応
- @HystrixCommand によって報告された例外に対処する方法
- サービス メソッドの呼び出しが失敗し、エラー メッセージがスローされると、@HystrixCommand でマークされた fallbackMethod 呼び出しクラス内の指定されたメソッドが自動的に呼び出されます。
package com.angenin.springcloud.service;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import org.springframework.stereotype.Service;
import java.util.concurrent.TimeUnit;
@Service
public class PaymentService {
//正常访问方法
public String paymentInfo_OK(Integer id){
//如果正常访问则,返回当前线程池的名字、传入的id、表情包
return "线程池: "+Thread.currentThread().getName()+" paymentInfo_OK,id: "+id+"\t"+"O(∩_∩)O哈哈~";
}
/**
* @HystrixCommand:启用
* 超时访问方法
* fallbackMethod:此方法出现问题了,执行哪个兜底的方法
* HystrixProperty:此方法线程的超时时间为3秒钟,我们现在睡眠5秒说明超时了,就走兜底的方法
*/
@HystrixCommand(fallbackMethod = "paymentInfo_TimeOutHandler",commandProperties = {
@HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="3000")
})
public String paymentInfo_TimeOut(Integer id){
//前面学过时会导致服务降级,模拟错误
int timeNumber = 5;
//int age = 10/0; //程序出现异常,同样会走兜底的方法
try {
TimeUnit.SECONDS.sleep(timeNumber);
} catch (InterruptedException e) {
e.printStackTrace();
}
//超时返回的提示信息
return "线程池:" + Thread.currentThread().getName() +
"paymentInfo_TimeOut,id:" +id+"\t"+"O(∩_∩)O哈哈~"+" 耗时(秒):"+timeNumber;
}
// 兜底方法
public String paymentInfo_TimeOutHandler(Integer id){
// 回调函数向调用方返回一个符合预期的、可处理的备选响应
return "线程池: "+Thread.currentThread().getName()+" 8001系统繁忙或者运行报错,请稍后再试,id: "+id+"\t"+"o(╥﹏╥)o";
}
}
- メインスタートアップクラスのアクティブ化
package com.angenin.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@EnableEurekaClient
@SpringBootApplication
@EnableCircuitBreaker //激活
public class PaymentHystrixMain8001 {
public static void main(String[] args) {
SpringApplication.run(PaymentHystrixMain8001.class, args);
}
}
-
セルフテスト: 開始 7001、8001
-
http://localhost:8001/payment/hystrix/timeout/1
4)80フォールバック
コンシューマのダウングレード: プロデューサのピーク タイムアウトは 5 秒で、3 秒間スリープしました。現在、コンシューマの呼び出しには 1.5 秒が必要で、3 秒待つことができないため、サービスのダウングレードは隠蔽メソッドを呼び出します。
- 80 次のマイクロサービスは、自身をより適切に保護することもでき、同じ例に従ってクライアントのダウングレードを保護することもできます。
- 余談ですが、構成したホット デプロイメント方法では Java コードに明らかな変更が加えられていますが、
@HystrixCommand
内部。 - YML
feign:
hystrix:
enabled: true
- メインブート
package com.angenin.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableFeignClients //激活feifn
@EnableHystrix //激活
public class OrderHystrixMain80
{
public static void main(String[] args) {
SpringApplication.run(OrderHystrixMain80.class,args);
}
}
- ビジネスクラス
package com.angenin.springcloud.controller;
import com.angenin.springcloud.service.PaymentHystrixService;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@RestController
@Slf4j
public class OrderHystirxController {
@Resource
private PaymentHystrixService paymentHystrixService;
//调用ok方法
@GetMapping("/consumer/payment/hystrix/ok/{id}")
public String paymentInfo_OK(@PathVariable("id") Integer id) {
String result = paymentHystrixService.paymentInfo_OK(id);
return result;
}
//调用超时方法
@GetMapping("/consumer/payment/hystrix/timeout/{id}")
@HystrixCommand(fallbackMethod = "paymentTimeOutFallbackMethod",commandProperties = {
@HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="1500")
})
public String paymentInfo_TimeOut(@PathVariable("id") Integer id) {
int age = 10/0; //测试出现异常同样要执行兜底的方法
String result = paymentHystrixService.paymentInfo_TimeOut(id);
return result;
}
public String paymentTimeOutFallbackMethod(@PathVariable("id") Integer id) {
return "我是消费者80,对方支付系统繁忙请10秒钟后再试或者自己运行出错请检查自己,o(╥﹏╥)o";
}
}
-
プロデューサー側を通常に変更します:プロデューサー側のピーク値は 5 秒で、3 秒間スリープします。このとき、コンシューマー側のピーク値は 1.5 秒で、3 秒待つことができないため、バックアップ方法が実行されます。
-
テスト: 開始 7001、8001、80
-
http://localhost/consumer/payment/hystrix/timeout/1
5) 現在の問題点
-
問題点 1: 各ビジネス メソッドが秘密メソッドに対応しており、コードが肥大化している。
-
問題点2:ビジネスロジック手法と秘密手法が混在しており、コードの結合度が非常に高い。
-
解決策: 統合とカスタマイズを分離する
- ビジネス メソッドは 100 あり、そのうち 97 の一般的なメソッドはグローバル構成を使用し、3 つの特別なメソッドのみをカスタマイズ (3 つの秘密メソッドを作成) することで、フォールバック サービス低下メソッドの生成を減らすことができます。
6) 問題解決のデモンストレーション
問題 1 を解決します。メソッドごとに 1 つを構成しますか? ? ? 拡大
-
フェイクインターフェイスシリーズ
-
@DefaultProperties(defaultFallback = "")
- 1:1 それぞれの方法でサービスのダウングレード方法を構成することは、技術的には可能ですが、実際には愚かです。
- 1:N 一部の排他的な重要基幹業務を除き、その他の共通業務は @DefaultProperties(defaultFallback = “”) により統一処理結果ページへ一律にジャンプ可能
通用的和独享的各自分开,避免了代码膨胀,合理减少了代码量,O(∩_∩)O哈哈~
-
コントローラの設定
package com.angenin.springcloud.controller;
import com.angenin.springcloud.service.PaymentHystrixService;
import com.netflix.hystrix.contrib.javanica.annotation.DefaultProperties;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@RestController
@Slf4j
/**
* 没有配置过定制的@HystrixCommand(fallbackMethod)方法就走这个全局定义的@DefaultProperties(defaultFallback)方法,
* 如果配置了就走自定义的@HystrixCommand(fallbackMethod)兜底方法。
*/
@DefaultProperties(defaultFallback = "payment_Global_FallbackMethod")
public class OrderHystirxController {
@Resource
private PaymentHystrixService paymentHystrixService;
//调用ok方法
@GetMapping("/consumer/payment/hystrix/ok/{id}")
public String paymentInfo_OK(@PathVariable("id") Integer id) {
String result = paymentHystrixService.paymentInfo_OK(id);
return result;
}
//调用超时方法
@GetMapping("/consumer/payment/hystrix/timeout/{id}")
/*@HystrixCommand(fallbackMethod = "paymentTimeOutFallbackMethod",commandProperties = {
@HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="1500")
})*/
/**
* 注意:需要注释的是这个@HystrixCommand注解中的属性而不是整个注解
* 注释掉注解:代表不使用服务降级,正确就正确,错误就错误
* 使用@HystrixProperty注解:不指定fallbackMethod属性表示使用全局的,指定代表使用定制的。
*/
@HystrixCommand
public String paymentInfo_TimeOut(@PathVariable("id") Integer id) {
int age = 10/0; //测试出现异常同样要执行兜底的方法
String result = paymentHystrixService.paymentInfo_TimeOut(id);
return result;
}
public String paymentTimeOutFallbackMethod(@PathVariable("id") Integer id) {
return "我是消费者80,对方支付系统繁忙请10秒钟后再试或者自己运行出错请检查自己,o(╥﹏╥)o";
}
//下面是全局fallback兜底方法
public String payment_Global_FallbackMethod() {
return "Global异常处理信息,请稍后再试,/(ㄒoㄒ)/~~";
}
}
- 再起動: 7001、8001、80 テスト
- 効果:
http://localhost/consumer/payment/hystrix/timeout/1
問題 2 を解決します: ビジネス ロジックと混合しますか? ? ? 混乱
- アイデア: 消費者が Feign を使用して呼び出しを行う限り、サービス インターフェイスが必要であり、このインターフェイス内のすべてのメソッドを統一された方法で定義およびスケジュールできるため、分離の目的を達成できます。
- サービスが低下しています。クライアントがサーバーを呼び出すと、サーバーはダウンまたはシャットダウンされます (タイムアウトとランタイム例外は以前にテストされています)。
- この場合のサービス縮退処理は
在客户端80实现完成的
サーバ8001とは関係ありません。Feignクライアントが定義したインターフェースにサービス縮退処理の実装クラスを追加するだけで切り離しが可能です。 - 私たちが将来直面するであろう異常事態
- 走る
- タイムアウト
- ダウンタイム
- ビジネス クラス PaymentController をもう一度見てみましょう
- cloud-consumer-feign-hystrix-order80 を変更する
- Cloud-consumer-feign-hystrix-order80 の既存の PaymentHystrixService インターフェイスに従って、インターフェイスを実装する新しいクラス (PaymentFallbackService) を作成し、例外処理のためのインターフェイス内のメソッドを統合します。
- PaymentFallbackService クラスは、PaymentFeignClientService インターフェイスを実装します。
package com.angenin.springcloud.service;
import org.springframework.stereotype.Component;
@Component
public class PaymentFallbackService implements PaymentHystrixService{
@Override
public String paymentInfo_OK(Integer id) {
return "-----PaymentFallbackService fall back-paymentInfo_OK ,o(╥﹏╥)o";
}
@Override
public String paymentInfo_TimeOut(Integer id) {
return "-----PaymentFallbackService fall back-paymentInfo_TimeOut ,o(╥﹏╥)o";
}
}
- YML (以前にセットアップ済み)
- PaymentFeignClientService インターフェース
package com.angenin.springcloud.service;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@Component
/**
* value:调用的微服务名
* 过程:fallback:相当于去找CLOUD-PROVIDER-HYSTRIX-PAYMENT这个微服务的名字,去调用下面已有的方法,
* 假如出事了去调用PaymentFallbackService里面的方法
*/
@FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT",fallback = PaymentFallbackService.class )
public interface PaymentHystrixService
{
@GetMapping("/payment/hystrix/ok/{id}")
public String paymentInfo_OK(@PathVariable("id") Integer id);
@GetMapping("/payment/hystrix/timeout/{id}")
public String paymentInfo_TimeOut(@PathVariable("id") Integer id);
}
- テスト
- 単一のエウレカが最初に 7001 から始まります
- PaymentHystrixMain8001 が開始され、OrderHystrixMain80
- 通常のアクセステスト:
http://localhost/consumer/payment/hystrix/ok/31
- マイクロサービスを意図的にシャットダウンする 8001
- クライアントはプロンプトを呼び出します。現時点では、サーバープロバイダーがダウンしていますが、サーバーが利用できないときにクライアントがサーバーをハングアップせずにプロンプト情報を取得できるように、サービスのダウングレード処理が行われています。
10.3.7 サービスサーキットブレーカー
1) 理論
-
サーキットブレーカー: 一言で言えば、家のヒューズです。
-
サーキットブレーカーの仕組みの概要
- サーキット ブレーカー メカニズムは、アバランシェ効果に対処するためのマイクロサービス リンク保護メカニズムです。ファンアウト リンク上のマイクロサービスがエラーまたは応答時間が長すぎるために使用できなくなると、サービスが低下し、その結果、ノード
上のマイクロサービスの呼び出しが中断され、すぐに誤った応答情報が返されます。 - ノードのマイクロサービス呼び出し応答が正常であることが検出されると、呼び出しリンクが復元されます。
- Spring Cloud フレームワークでは、サーキット ブレーカー メカニズムは Hystrix を通じて実装されます。Hystrix はマイクロサービス間の呼び出しのステータスを監視し、
失敗した呼び出しが特定のしきい値 (デフォルトでは 5 秒以内に 20 件の失敗した呼び出し) に達すると、サーキット ブレーカー メカニズムがアクティブになります。サーキット ブレーカー メカニズムのアノテーションは依然として @HystrixCommand です。 - 修士論文: https://martinfowler.com/bliki/CircuitBreaker.html
- サーキット ブレーカー メカニズムは、アバランシェ効果に対処するためのマイクロサービス リンク保護メカニズムです。ファンアウト リンク上のマイクロサービスがエラーまたは応答時間が長すぎるために使用できなくなると、サービスが低下し、その結果、ノード
2) 実際の操作
修改
クラウドプロバイダー-hystrix-payment8001
- 支払いサービス
//=========服务熔断
/**
* commandProperties中配置的4个注解的含义:
* true使用断路器,假设在时间窗口期10秒钟内,10次请求有
* 超过60%都是失败的,那么这个断路器将起作用。
*
*/
@HystrixCommand(fallbackMethod = "paymentCircuitBreaker_fallback",commandProperties = {
@HystrixProperty(name = "circuitBreaker.enabled",value = "true"), // 是否开启断路器
@HystrixProperty(name = "circuitBreaker.requestVolumeThreshold",value = "10"), // 请求次数
@HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds",value = "10000"), // 时间窗口期
@HystrixProperty(name = "circuitBreaker.errorThresholdPercentage",value = "60"), // 失败率达到多少后跳闸
})
public String paymentCircuitBreaker(@PathVariable("id") Integer id) {
/* 业务逻辑:
* 如果输入的id大于等于0,则输出流水号,如果输入的id是个负数抛出异常,
* 那么根据上面注解配置的熔断机制执行降级的兜底方法paymentCircuitBreaker_fallback
* */
if(id<0){
throw new RuntimeException("******id 不能负数");
}
/**
* IdUtil.simpleUUID()类似于 UUID.randomUUID().toString().replaceAll("-", "")
* 它来自于之前在父项目中引入的hutool依赖
* hutool是个功能强大的JAVA工具包(中国人编写的),官网:https://hutool.cn/
*/
String serialNumber = IdUtil.simpleUUID();
return Thread.currentThread().getName()+"\t"+"调用成功,流水号: " + serialNumber;
}
//降级的兜底方法
public String paymentCircuitBreaker_fallback(@PathVariable("id") Integer id) {
return "id 不能负数,请稍后再试,/(ㄒoㄒ)/~~ id: " +id;
}
- これらのパラメータを設定する理由については、公式 Web サイトを確認してください。
https://github.com/Netflix/Hystrix/wiki/How-it-Works#CircuitBreaker
- 支払いコントローラー
//=========服务熔断
@GetMapping("/payment/circuit/{id}")
public String paymentCircuitBreaker(@PathVariable("id") Integer id) {
String result = paymentService.paymentCircuitBreaker(id);
log.info("****result: "+result);
return result;
}
テスト:
-
启アニメーション:cloud-eureka-server7001、cloud-provider-hystrix-payment8001
-
セルフテストクラウドプロバイダー-hystrix-payment8001
-
正确:http://localhost:8001/payment/circuit/31
-
错误:http://localhost:8001/payment/circuit/-31
-
1 つの正しいトライトライと 1 つの間違ったトライトライ
-
主要なテスト: 間違いが多く、徐々に修正しましたが、最初は条件が満たされておらず、正しいアクセス アドレスさえ使用できないことがわかりました。
- 説明: 負の ID を複数回入力するとエラー ページが返されます (60% 以上でブレーカーが飛ぶ設定になっています)。このとき、正の ID を入力してもエラー ページが返されます。正のIDを複数回入力すると正解率が上がりますので、ゆっくりと正しいページに戻してください。
- 負の ID を複数回入力するとエラー ページが返される
- このとき、正の ID を入力してもエラー ページが返されます。
- 正の ID を複数回入力すると、正解率が増加し、エラー率が減少し、正しいページがゆっくりと復元されます。
3) 原則(概要)
-
神の結論
-
ヒューズの種類
- ヒューズが開いています
- リクエストは現在のサービスを呼び出すことはなくなります。内部設定クロックは通常 MTTR (Mean Time to Failure) です。オープン時間が設定クロックに達すると、半ヒューズ状態に入ります。
- サーキットブレーカーが閉じた
- サーキット ブレーカーをオフにしても、サービスはサーキット ブレークされません。
- ヒューズ半開
- 一部のリクエストは、ルールに従って現在のサービスを呼び出します。リクエストが成功し、ルールに従っている場合、現在のサービスは通常に戻っているとみなされ、サーキット ブレーカーがオフになります。
- ヒューズが開いています
-
公式サイトサーキットブレーカーのフローチャート
-
公式サイトの手順
-
サーキット ブレーカーはどのような状況で機能し始めるのですか?
それには、サーキット ブレーカーの 3 つの重要なパラメータが関係します快照时间窗、请求总数阀值、错误百分比阀值
。- 1): スナップショット時間枠: サーキット ブレーカーを開くかどうかを決定するには、いくつかのリクエスト データとエラー データをカウントする必要があります。統計時間範囲はスナップショット時間枠であり、デフォルトは最新の 10 秒です。
- 2): リクエストの合計数のしきい値: サーキット ブレーカーの資格を得るには、スナップショット時間枠内でリクエストの合計数のしきい値を満たす必要があります。デフォルトは 20 です。これは、hystrix コマンドの呼び出しが 10 秒以内に 20 回未満の場合、すべてのリクエストがタイムアウトするか他の理由で失敗した場合でも、サーキット ブレーカーは開かれないことを意味します。
- 3): エラー パーセンテージのしきい値: スナップショット時間枠内でリクエストの合計数がしきい値を超えると、たとえば 30 件の呼び出しが発生し、これら 30 件の呼び出しのうち 15 件のタイムアウト例外が発生した場合、つまりエラー パーセンテージが 50% を超えた場合、デフォルト設定の 50% しきい値では、この時点でサーキット ブレーカーが開きます。
-
サーキットブレーカーの開閉条件
- 特定のしきい値が満たされたとき (デフォルトでは 10 秒以内に 20 リクエストを超えます)
- 失敗率が特定のレベルに達すると (デフォルトでは、リクエストの 50% 以上が 10 秒以内に失敗します)
- 上記のしきい値に達すると、サーキットブレーカーが開きます
- 有効にすると、すべてのリクエストは転送されません。
- 一定時間 (デフォルトは 5 秒) が経過すると、サーキット ブレーカーが半分開き、リクエストの 1 つが転送されます。成功するとサーキット ブレーカーは閉じられ、失敗すると開いたままになります。4と5を繰り返します
-
サーキットブレーカーが開いた後
- 別のリクエストが呼び出されるとき、メイン ロジックは呼び出されず、ダウングレード フォールバックが直接呼び出されます。サーキットブレーカーによりエラーが自動的に発見され、ダウングレードロジックからメインロジックに切り替わるため、応答遅延が軽減されます。
- 元のメインロジックを復元するにはどうすればよいですか?
この問題に対して、hystrix は自動回復機能も実装してくれました。
サーキット ブレーカーがオープンされてメイン ロジックが切断されると、hystrix はスリープ タイム ウィンドウを開始します。このタイム ウィンドウの間、ダウングレード ロジックが一時的にメイン ロジックになります。スリープ タイム ウィンドウが終了すると、サーキット ブレーカーはハーフタイムに入ります。オープン状態です。元のメイン ロジックへのリクエストを解放します。リクエストが正常に返された場合、サーキット ブレーカーは引き続き閉じられ、メイン ロジックが復元されます。このリクエストにまだ問題がある場合、サーキット ブレーカーは引き続き動作します。オープン状態になると、スリープ時間ウィンドウの時間が再調整されます。
-
すべての構成: 次のように
-
//========================All
@HystrixCommand(fallbackMethod = "str_fallbackMethod",
groupKey = "strGroupCommand",
commandKey = "strCommand",
threadPoolKey = "strThreadPool",
commandProperties = {
// 设置隔离策略,THREAD 表示线程池 SEMAPHORE:信号池隔离
@HystrixProperty(name = "execution.isolation.strategy", value = "THREAD"),
// 当隔离策略选择信号池隔离的时候,用来设置信号池的大小(最大并发数)
@HystrixProperty(name = "execution.isolation.semaphore.maxConcurrentRequests", value = "10"),
// 配置命令执行的超时时间
@HystrixProperty(name = "execution.isolation.thread.timeoutinMilliseconds", value = "10"),
// 是否启用超时时间
@HystrixProperty(name = "execution.timeout.enabled", value = "true"),
// 执行超时的时候是否中断
@HystrixProperty(name = "execution.isolation.thread.interruptOnTimeout", value = "true"),
// 执行被取消的时候是否中断
@HystrixProperty(name = "execution.isolation.thread.interruptOnCancel", value = "true"),
// 允许回调方法执行的最大并发数
@HystrixProperty(name = "fallback.isolation.semaphore.maxConcurrentRequests", value = "10"),
// 服务降级是否启用,是否执行回调函数
@HystrixProperty(name = "fallback.enabled", value = "true"),
// 是否启用断路器
@HystrixProperty(name = "circuitBreaker.enabled", value = "true"),
// 该属性用来设置在滚动时间窗中,断路器熔断的最小请求数。例如,默认该值为 20 的时候,
// 如果滚动时间窗(默认10秒)内仅收到了19个请求, 即使这19个请求都失败了,断路器也不会打开。
@HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "20"),
// 该属性用来设置在滚动时间窗中,表示在滚动时间窗中,在请求数量超过
// circuitBreaker.requestVolumeThreshold 的情况下,如果错误请求数的百分比超过50,
// 就把断路器设置为 "打开" 状态,否则就设置为 "关闭" 状态。
@HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "50"),
// 该属性用来设置当断路器打开之后的休眠时间窗。 休眠时间窗结束之后,
// 会将断路器置为 "半开" 状态,尝试熔断的请求命令,如果依然失败就将断路器继续设置为 "打开" 状态,
// 如果成功就设置为 "关闭" 状态。
@HystrixProperty(name = "circuitBreaker.sleepWindowinMilliseconds", value = "5000"),
// 断路器强制打开
@HystrixProperty(name = "circuitBreaker.forceOpen", value = "false"),
// 断路器强制关闭
@HystrixProperty(name = "circuitBreaker.forceClosed", value = "false"),
// 滚动时间窗设置,该时间用于断路器判断健康度时需要收集信息的持续时间
@HystrixProperty(name = "metrics.rollingStats.timeinMilliseconds", value = "10000"),
// 该属性用来设置滚动时间窗统计指标信息时划分"桶"的数量,断路器在收集指标信息的时候会根据
// 设置的时间窗长度拆分成多个 "桶" 来累计各度量值,每个"桶"记录了一段时间内的采集指标。
// 比如 10 秒内拆分成 10 个"桶"收集这样,所以 timeinMilliseconds 必须能被 numBuckets 整除。否则会抛异常
@HystrixProperty(name = "metrics.rollingStats.numBuckets", value = "10"),
// 该属性用来设置对命令执行的延迟是否使用百分位数来跟踪和计算。如果设置为 false, 那么所有的概要统计都将返回 -1。
@HystrixProperty(name = "metrics.rollingPercentile.enabled", value = "false"),
// 该属性用来设置百分位统计的滚动窗口的持续时间,单位为毫秒。
@HystrixProperty(name = "metrics.rollingPercentile.timeInMilliseconds", value = "60000"),
// 该属性用来设置百分位统计滚动窗口中使用 “ 桶 ”的数量。
@HystrixProperty(name = "metrics.rollingPercentile.numBuckets", value = "60000"),
// 该属性用来设置在执行过程中每个 “桶” 中保留的最大执行次数。如果在滚动时间窗内发生超过该设定值的执行次数,
// 就从最初的位置开始重写。例如,将该值设置为100, 滚动窗口为10秒,若在10秒内一个 “桶 ”中发生了500次执行,
// 那么该 “桶” 中只保留 最后的100次执行的统计。另外,增加该值的大小将会增加内存量的消耗,并增加排序百分位数所需的计算时间。
@HystrixProperty(name = "metrics.rollingPercentile.bucketSize", value = "100"),
// 该属性用来设置采集影响断路器状态的健康快照(请求的成功、 错误百分比)的间隔等待时间。
@HystrixProperty(name = "metrics.healthSnapshot.intervalinMilliseconds", value = "500"),
// 是否开启请求缓存
@HystrixProperty(name = "requestCache.enabled", value = "true"),
// HystrixCommand的执行和事件是否打印日志到 HystrixRequestLog 中
@HystrixProperty(name = "requestLog.enabled", value = "true"),
},
threadPoolProperties = {
// 该参数用来设置执行命令线程池的核心线程数,该值也就是命令执行的最大并发量
@HystrixProperty(name = "coreSize", value = "10"),
// 该参数用来设置线程池的最大队列大小。当设置为 -1 时,线程池将使用 SynchronousQueue 实现的队列,
// 否则将使用 LinkedBlockingQueue 实现的队列。
@HystrixProperty(name = "maxQueueSize", value = "-1"),
// 该参数用来为队列设置拒绝阈值。 通过该参数, 即使队列没有达到最大值也能拒绝请求。
// 该参数主要是对 LinkedBlockingQueue 队列的补充,因为 LinkedBlockingQueue
// 队列不能动态修改它的对象大小,而通过该属性就可以调整拒绝请求的队列大小了。
@HystrixProperty(name = "queueSizeRejectionThreshold", value = "5"),
}
)
public String strConsumer() {
return "hello 2020";
}
public String str_fallbackMethod()
{
return "*****fall back str_fallbackMethod";
}
10.3.8 サービス電流制限
- 以下の高度な章では、Alibaba の Sentinel の指示について説明します。
10.4 ヒストリックスのワークフロー
-
https://github.com/Netflix/Hystrix/wiki/How-it-Works
-
Hystrix ワークフロー
-
公式サイトの凡例
-
手順の説明
-
1) HystrixCommand (依存サービスが単一の操作結果を返す場合に使用) オブジェクトまたは HystrixObserableCommand (依存サービスが複数の操作結果を返す場合に使用) オブジェクトを作成します。
-
2) コマンドの実行。このうち、HystrixComand は以下の最初の 2 つの実行メソッドを実装し、HystrixObservableCommand は後の 2 つの実行メソッドを実装します:execute(): 同期実行、依存サービスから単一の結果オブジェクトを返す、またはエラー発生時に例外をスローします。queue(): 非同期実行。Future オブジェクトを直接返します。このオブジェクトには、サービスの実行終了時に返される単一の結果オブジェクトが含まれます。observ(): 操作の複数の結果を表す Observable オブジェクトを返します。これはホット オブザーバブルです (「イベント ソース」に「サブスクライバー」があるかどうかに関係なく、イベントは作成後に公開されます)。 「サブスクライバ」は「イベント ソース」の途中から開始する場合があり、操作全体の一部しか表示されない場合があります)。toObservable(): また、操作の複数の結果を表す Observable オブジェクトも返しますが、Cold Observable を返します (「サブスクライバー」が存在しない場合はイベントを公開せず、「サブスクライバー」が存在するまで待機します)。イベントはその後にのみ公開されるため、Cold Observable のサブスクライバーは、操作全体のプロセス全体を最初から確認できるようになります。
-
3) 現在のコマンドのリクエスト キャッシュ機能が有効で、コマンド キャッシュがヒットした場合、キャッシュされた結果が Observable オブジェクトの形式で即座に返されます。
-
4) サーキットブレーカーが開いているかどうかを確認します。サーキット ブレーカーが開いている場合、Hystrix はコマンドを実行せず、代わりにフォールバック処理ロジックに移行します (ステップ 8)。サーキット ブレーカーが閉じている場合は、コマンドを実行するために利用可能なリソースがあるかどうかを確認します (ステップ 5)。
-
5) スレッド プール/リクエスト キュー/セマフォがいっぱいかどうか。コマンドがサービスの専用スレッド プールとリクエスト キューに依存している場合、またはセマフォ (スレッド プールが使用されていない場合) がすでにいっぱいである場合、Hystrix はコマンドを実行せず、フォールバック処理ロジックに転送します (ステップ8) 。
-
6) Hystrix は、私たちが作成したメソッドに基づいて依存サービスをリクエストする方法を決定します。HystrixCommand.run(): 単一の結果を返すか、例外をスローします。HystrixObservableCommand.construct(): Observable オブジェクトを返して複数の結果を出力するか、onError を通じてエラー通知を送信します。
-
7) Hystrix は、「成功」、「失敗」、「拒否」、「タイムアウト」およびその他の情報をサーキット ブレーカーに報告し、サーキット ブレーカーはこれらのデータをカウントするための一連のカウンターを維持します。サーキット ブレーカーはこれらの統計を使用して、依存サービスに対するリクエストを「切断/ショート」するためにサーキット ブレーカーを開くかどうかを決定します。
-
8) コマンドの実行が失敗すると、Hystrix はフォールバックに入り、プロセスのロールバックを試みます。通常、この操作を「サービスのダウングレード」と呼びます。次の状況では、サービスの低下が発生する可能性があります。 ステップ 4: 現在のコマンドは「ヒューズ/短絡」状態にあり、サーキット ブレーカーが開いています。ステップ 5: 現在のコマンドのスレッド プール、リクエスト キュー、またはセマフォがいっぱいの場合。ステップ 6: HystrixObservableCommand.construct() または HystrixCommand.run() が例外をスローした場合。
-
9) Hystrix コマンドが正常に実行されると、処理結果が直接または Observable の形式で返されます。
-
ヒント: コマンドの劣化ロジックを実装していない場合、または劣化処理ロジックで例外がスローされた場合でも、Hystrix は Observable オブジェクトを返しますが、結果データは出力されません。代わりに、コマンドにただちに中断するように通知します。リクエストは onError メソッドを通じて送信され、コマンドの失敗の原因となった例外は onError() メソッドを通じて呼び出し元に送信されます。
-
-
10.5 サービス監視 hystrixDashboard
10.5.1 概要
- 依存サービスへの呼び出しを分離することに加えて、Hystrix は、
准实时的调用监控(Hystrix Dashboard)
Hystrix を通じて開始されたすべてのリクエストの実行情報を継続的に記録し、1 秒あたりに実行されるリクエストの数、実行方法などの統計レポートとグラフィックの形式でユーザーに表示することも提供します。成功の数、失敗の数など。Netflix は、hystrix-metrics-event-stream プロジェクトを通じて上記の指標のモニタリングを実装しています。Spring Cloud は、監視コンテンツをビジュアル インターフェイスに変換するための Hystrix Dashboard との統合も提供します。- つまり: hystrix のダッシュボード監視インターフェイスのグラフィカル表示
10.5.2 ダッシュボード 9001
1) 新しいcloud-consumer-hystrix-dashboard9001を作成します
2)ポム
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>cloud2020</artifactId>
<groupId>com.angenin.springcloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-consumer-hystrix-dashboard9001</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
3)YML
server:
port: 9001
4) メインスタートアップクラス
package com.angenin.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;
@SpringBootApplication
@EnableHystrixDashboard //启用Hystrix仪表盘
public class HystrixDashboardMain9001
{
public static void main(String[] args)
{
SpringApplication.run(HystrixDashboardMain9001.class,args);
}
}
5) すべてのプロデューサー pom ファイルを表示する
- すべてのプロバイダー マイクロサービス クラス (8001/8002/8003) は依存関係の構成を監視する必要があります
6) テスト
- Cloud-consumer-hystrix-dashboard9001 を開始します。このマイクロサービスは、その後マイクロサービス 8001 を監視します。
- http://localhost:9001/hystrix. このインターフェイスの表示は、hystrixDashboard 監視プラットフォームが確立されていることを示します。
10.5.3 サーキットブレーカーのデモンストレーション (サービス監視 hystrixDashboard)
-
デモ: 8001 サービスサーキットブレーカーの前述のケースを例として、8001 を監視する 9001 によってどのようなアイコンが生成されるかを確認します。
-
9001の監視・テストプラットフォームを自分で構築する必要があり面倒ですが、Hystrixが国内アリババのsenienlに変わってからはWebサイトに直接ログインして監視できるようになりました。
1)cloud-provider-hystrix-payment8001を変更します
予防:
- 監視対象のプロデューサー サービスは通常、グラフィカル監視を有効にするには 2 つの依存関係を追加する必要があります。
- Hystrix の新しいバージョンでは、メインのスタートアップ クラス MainAppHystrix8001 で監視パスを指定する必要があります。指定しないと、「コマンド メトリック ストリーム 404 に接続できません」が報告されます。
package com.angenin.springcloud;
import com.netflix.hystrix.contrib.metrics.eventstream.HystrixMetricsStreamServlet;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.context.annotation.Bean;
@EnableEurekaClient
@SpringBootApplication
@EnableCircuitBreaker //激活
public class PaymentHystrixMain8001 {
public static void main(String[] args) {
SpringApplication.run(PaymentHystrixMain8001.class, args);
}
/**
*此配置是为了服务监控而配置,与服务容错本身无关,springcloud升级后的坑
*ServletRegistrationBean因为springboot的默认路径不是"/hystrix.stream",
*只要在自己的项目里配置上下面的servlet就可以了
*/
@Bean
public ServletRegistrationBean getServlet() {
HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);
registrationBean.setLoadOnStartup(1);
registrationBean.addUrlMappings("/hystrix.stream");
registrationBean.setName("HystrixMetricsStreamServlet");
return registrationBean;
}
}
2) モニタリング試験
1 つの eureka または 3 つの eureka クラスターを開始できます
- 启動cloud-eureka-server7001、cloud-provider-hystrix-payment8001、cloud-consumer-hystrix-dashboard9001
監視ウィンドウを観察する
-
9001 監視 8001
- 監視アドレスを入力します: http://localhost:8001/hystrix.stream
- 監視アドレスを入力します: http://localhost:8001/hystrix.stream
-
テスト アドレス (これらは、上記の 8001 テスト サービス サーキット ブレーカーの 2 つのアドレス、10.3.7 ディレクトリです)
-
http://localhost:8001/payment/circuit/31 (正しいページに戻るには、正の ID を入力してください)
-
http://localhost:8001/payment/circuit/-31 マイナスの ID を入力してエラー ページに戻ります)
-
上記のテストに合格しました
-
わかりました
-
最初に正しい住所にアクセスし、次に間違った住所にアクセスし、次に正しい住所にアクセスすると、写真のブレーカーがゆっくりと解除されることがわかります。
-
モニタリング結果、成功
-
監視結果、失敗
-
-
-
どうやって見るのですか?
-
7色
-
1周
- 黒丸: 2 つの意味があります。色の変化を通じてインスタンスの健全性を表します。健全性は緑色から緑色に変化します。色の変化に加えて、インスタンスのリクエスト トラフィックに応じてサイズも変化します。トラフィックが多いほど、サイズも大きくなります。実線の円になります。したがって、黒丸の表示により、多数の例の中からすぐに見つけることができます
故障实例和高压力实例
。
- 黒丸: 2 つの意味があります。色の変化を通じてインスタンスの健全性を表します。健全性は緑色から緑色に変化します。色の変化に加えて、インスタンスのリクエスト トラフィックに応じてサイズも変化します。トラフィックが多いほど、サイズも大きくなります。実線の円になります。したがって、黒丸の表示により、多数の例の中からすぐに見つけることができます
-
1行
- 曲線: 2 分以内の流量の相対的な変化を記録するために使用され、流量の上昇傾向と下降傾向を観察できます。
- 曲線: 2 分以内の流量の相対的な変化を記録するために使用され、流量の上昇傾向と下降傾向を観察できます。
-
全体像説明
-
全体像説明2
-
-
1 つを理解して初めて、複雑なものも理解できるようになります
11. ズールルーティングゲートウェイ
- Zuul は古いのでここでは説明しませんが、新しい世代のゲートウェイ Gateway に直接行きましょう。会社の古いプロジェクトに zuul テクノロジーが使用されている場合は、メモを取って脳マップを確認してください。
12. ゲートウェイ 新世代ゲートウェイ
12.1 概要 はじめに
-
なぜゲートウェイが必要なのでしょうか?
-
ゲートウェイの技術的実装
-
公式ウェブサイト
-
前世代のzuul 1.X: https://github.com/Netflix/zuul/wiki
-
現在前のゲートウェイ:https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.1.RELEASE/reference/html/
-
-
とは
-
概要
-
一文で言うと:
- SpringCloud Gateway によって使用される Webflux のactor-netty リアクティブ プログラミング コンポーネントは、下部で Netty 通信フレームワークを使用します。
- ソースコードのアーキテクチャ
-
-
何ができますか
- リバースプロキシ
- 認証
- フロー制御
- ヒューズ
- ログ監視
- …
-
マイクロサービス アーキテクチャにおけるゲートウェイはどこにあるのでしょうか?
-
ズールがあったのになぜまたゲートウェイが出てきたのでしょうか?
-
ゲートウェイを選んだ理由は何ですか?
-
neflixは信頼できず、zuul2.0は遅れてリリースされていません。
-
SpringCloud Gateway には次の機能があります。
-
SpringCloud GatewayとZuulの違い
-
-
Zuul1.xモデル
-
ゲートウェイモデル
-
WebFluxとは
-
https://docs.spring.io/spring/docs/current/spring-framework-reference/web-reactive.html#webflux-new-framework
-
注: struts2、springmvc などの従来の Web フレームワークはすべて、サーブレット API とサーブレット コンテナに基づいて実行されます。しかし
在Servlet3.1之后有了异步非阻塞的支持
。WebFlux は典型的なノンブロッキング非同期フレームワークであり、そのコアは Reactor 関連の API に基づいて実装されています。従来の Web フレームワークと比較して、Netty、Undertow、Servlet3.1 などのコンテナ上で実行できます。ノンブロッキング + 関数型プログラミング (Spring5 では java8 を使用できるようにする必要があります) Spring WebFlux は Spring 5.0 で導入された新しいリアクティブ フレームワークです。Spring MVC とは異なり、サーブレット API に依存する必要はありません。完全に非同期でノンブロッキングです。であり、Reactor に基づいてリアクティブ ストリーミング仕様を実装しています。
-
-
12.2 3 つの中心的な概念
-
ルート
- ルーティングは、ゲートウェイを構築するための基本モジュールです。ID、ターゲット URI、一連のアサーションとフィルターで構成されます。アサーションが true の場合、ルートは一致します。
-
Predicate(断言)
- リファレンスは Java8 の java.util.function.Predicate です
。開発者は HTTP リクエスト内のすべてのもの (リクエスト ヘッダーやリクエスト パラメータなど) を照合できます。如果请求与断言相匹配则进行路由
- リファレンスは Java8 の java.util.function.Predicate です
-
フィルター
- Spring フレームワークの GatewayFilter のインスタンスを参照します。フィルターを使用すると、リクエストがルーティングされる前または後にリクエストを変更できます。
-
全体:
- Web リクエストは、いくつかの一致条件を通じて実際のサービス ノードを見つけます。そして、この転送プロセスの前後にいくつかの洗練された制御を実行します。
predicate は一致条件です。 - そしてフィルターは全能のインターセプターとして理解できます。これら 2 つの要素とターゲット URI を使用して、特定のルートを実装できます。
- Web リクエストは、いくつかの一致条件を通じて実際のサービス ノードを見つけます。そして、この転送プロセスの前後にいくつかの洗練された制御を実行します。
12.3 ゲートウェイのワークフロー
-
公式サイト概要
-
コアロジック:
路由转发+执行过滤器链
12.4 設定の開始
12.4.1 Gateway9527のセットアップ
1) 新しいモジュールを作成する
- クラウドゲートウェイ-ゲートウェイ9527
2)ポム
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>cloud2020</artifactId>
<groupId>com.angenin.springcloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-gateway-gateway9527</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<!--gateway-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!--eureka-client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!-- 引入自己定义的api通用包,可以使用Payment支付Entity -->
<dependency>
<groupId>com.angenin.springcloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>${project.version}</version>
</dependency>
<!--一般基础配置类-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
3)YML
- GateWay ゲートウェイもマイクロサービスとしてサービス センターに登録する必要があります。zk などの任意の登録センターを使用できます。
server:
port: 9527
spring:
application:
name: cloud-gateway
eureka:
instance:
hostname: cloud-gateway-service
client: #服务提供者provider注册进eureka服务列表内
service-url:
register-with-eureka: true
fetch-registry: true
defaultZone: http://eureka7001.com:7001/eureka #以单机版为例,不然集群启动太慢
4) 業種不問
- ゲートウェイにはビジネスクラスはなく、正面からゲートを見守っているのは彼だ。
5) メインスタートアップクラス
package com.angenin.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication
@EnableEurekaClient
public class GateWayMain9527 {
public static void main(String[] args) {
SpringApplication.run(GateWayMain9527.class, args);
}
}
6) 9527 ゲートウェイはルーティング マッピングをどのように行うのですか? ? ?
-
例として、cloud-provider-payment8001 を取り上げます。
-
cloud-provider-payment8001コントローラーのアクセスアドレスを確認してください
-
getメソッド:テストクエリ関数
-
lib: カスタム負荷分散ルールをテストする
-
-
現時点ではポート 8001 を公開したくありません。8001 の外側に 9527 のレイヤーを配置したいと考えています。これはより安全であり、他のユーザーが 8001 を直接攻撃するのを防ぎます。それをブロックするゲートウェイのレイヤーがあります。
7) YML での新しいゲートウェイ構成
server:
port: 9527
spring:
application:
name: cloud-gateway
#网关配置:
cloud:
gateway:
routes: #routes表示可以路由多个,可以为某个controller里面的所有rest接口都可以做路由
#第一个路由
- id: payment_routh #payment_route #路由的ID,没有固定规则但要求唯一,建议配合服务名
uri: http://localhost:8001 #匹配后提供服务的路由地址 写死的
predicates:
- Path=/payment/get/** # 断言,路径相匹配的进行路由
#第二个路由
- id: payment_routh2 #payment_route #路由的ID,没有固定规则但要求唯一,建议配合服务名
uri: http://localhost:8001 #匹配后提供服务的路由地址 写死的
predicates:
- Path=/payment/lb/** # 断言,路径相匹配的进行路由
eureka:
instance:
hostname: cloud-gateway-service
client: #服务提供者provider注册进eureka服务列表内
service-url:
register-with-eureka: true
fetch-registry: true
defaultZone: http://eureka7001.com:7001/eureka #以单机版为例,不然集群启动太慢
8) テスト
-
启動cloud-eureka-server7001、cloud-provider-payment8001、cloud-gateway-gateway9527
-
jar パッケージの導入における小さなバグ。ゲートウェイ ゲートウェイは Web 関連の依存関係を導入する必要はありません。起動時に依存関係が導入されると、エラーが報告されます。
-
アクセス手順
-
ゲートウェイを追加する前: http://localhost:8001/payment/get/4
-
ゲートウェイ http://localhost:9527/payment/get/4 を追加すると、正しくアクセスできるようになります。
-
9) ゲートウェイでルーティングを構成する 2 つの方法
方法 1: 構成ファイル yml で構成します。前の手順を参照してください。
方法 2: RouteLocator Bean をコードに挿入する
- 公式ウェブサイトのケース: https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.1.RELEASE/reference/html/#spring-cloud-circuitbreaker-filter-factory
-
Baidu の国内ニュース Web サイトには外部ネットワークが必要です: http://news.baidu.com/guonei (この Web サイトはもう存在しないようです)
-
自分で書いてください
-
百度ニュース
-
ビジネス要件: 9527 ゲートウェイを介して外部ネットワーク上の Baidu News Web サイトにアクセスする
-
コーディング
- クラウドゲートウェイ-ゲートウェイ9527
- ビジネス実装、構成、および構成クラスの内容については、以下で詳しく説明します。
-
テスト:
- プロジェクト 9527 を再開します
- http://localhost:9527/guonei、同じニュース ページが返されます
-
設定内容:
package com.angenin.springcloud.config;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class GateWayConfig {
/**
* 配置了一个id为route-name的路由规则,
* 当访问地址 http://localhost:9527/guonei时会自动转发到地址:http://news.baidu.com/guonei
* @param
* @return
*/
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder routeLocatorBuilder)
{
RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes();
routes.route("path_route_atguigu",
r -> r.path("/guonei")
.uri("http://news.baidu.com/guonei")).build();
return routes.build();
}
}
12.5 マイクロサービス名による動的ルーティングの実装
-
現在の問題: アドレスはハードコーディングされており、複数のサービス プロバイダーが存在する可能性があるため、負荷分散が必要です。
-
建築
-
デフォルトでは、ゲートウェイは、登録センターに登録されたマイクロサービス名のパスを使用して登録センターに登録されたサービス リストに基づいて作成されます。
动态路由进行转发,从而实现动态路由的功能
-
起動: 1 つの eureka7001 (cloud-eureka-server7001) + 2 つのサービス プロバイダー 8001/8002 (cloud-provider-payment8001、cloud-provider-payment8002)
-
POM: この依存関係は以前に追加されており、サービスは登録センターに登録されています
-
YML
- なお、uri のプロトコルは lb であり、Gateway のロードバランシング機能が有効であることを意味します。
- lb://serviceName は、マイクロサービスの Spring Cloud Gateway によって自動的に作成される負荷分散 URI です。
server:
port: 9527
spring:
application:
name: cloud-gateway
#网关配置:
cloud:
gateway:
discovery:
locator:
enabled: true #开启从注册中心动态创建路由的功能,利用微服务名进行路由
routes: #routes表示可以路由多个,可以为某个controller里面的所有rest接口都可以做路由
#第一个路由
- id: payment_routh #payment_route #路由的ID,没有固定规则但要求唯一,建议配合服务名
#uri: http://localhost:8001 #匹配后提供服务的路由地址 写死的
uri: lb://cloud-payment-service #匹配后提供服务的路由地址(8001 8002集群组成的微服务名称) 替换为动态的
predicates:
- Path=/payment/get/** # 断言,路径相匹配的进行路由
#第二个路由
- id: payment_routh2 #payment_route #路由的ID,没有固定规则但要求唯一,建议配合服务名
#uri: http://localhost:8001 #匹配后提供服务的路由地址 写死的
uri: lb://cloud-payment-service #匹配后提供服务的路由地址 替换为动态的
predicates:
- Path=/payment/lb/** # 断言,路径相匹配的进行路由
eureka:
instance:
hostname: cloud-gateway-service
client: #服务提供者provider注册进eureka服务列表内
service-url:
register-with-eureka: true
fetch-registry: true
defaultZone: http://eureka7001.com:7001/eureka #以单机版为例,不然集群启动太慢
- テスト
- 起動時 9527
- http://localhost:9527/payment/lb
- 8001/8002 2 ポート スイッチング
12.6 述語の使用
12.6.1 とは
- ゲートウェイ9527を開始します
- つまり、述語の下に複数の一致ルールがあります。
12.6.2 ルート述語ファクトリーとは何ですか?
-
https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.1.RELEASE/reference/html/#gateway-request-predicates-factories
-
Spring Cloud Gateway は、Spring WebFlux HandlerMapping インフラストラクチャの一部としてルート マッチングを実装します。Spring Cloud Gateway には、多くの組み込みの Route Predicate ファクトリが含まれています。これらの述語はすべて、HTTP リクエストのさまざまなプロパティと一致します。複数のルート述語ファクトリーを組み合わせることができます
-
Spring Cloud Gateway が Route オブジェクトを作成するとき、RoutePredicateFactory を使用して Predicate オブジェクトを作成し、Predicate オブジェクトを Route に割り当てることができます。Spring Cloud Gateway には、多くの組み込みのルート述語ファクトリーが含まれています。
-
これらの述語はすべて、HTTP リクエストのさまざまなプロパティと一致します。さまざまな述語ファクトリーを組み合わせて、論理積を渡すことができます。
12.6.3 一般的に使用されるルート述語
- ルート述語の後
- ルート述語の前
- ルート述語間
- クッキールート述語
- ヘッダールート述語
- ホストルート述語
- メソッドルート述語
- パス・ルート述語
- クエリルート述語
12.6.4 一般的に使用されるルート述語のデモ
1)ルート述語の後
公式ウェブサイトのケース:
spring:
cloud:
gateway:
routes:
- id: after_route
uri: https://example.org
predicates:
- After=2017-01-20T17:42:47.789-07:00[America/Denver]
質問: この設定行を直接コピーすることはできますが、必要な時間形式とそのタイムゾーンをどのように記述するのですか? ? ?
自分でテストしてください:
- テストクラス:After以降に記述される日時形式とタイムゾーンを取得することが目的です。
import java.time.ZonedDateTime;
public class T2 {
public static void main(String[] args) {
//获取默认时区的当前时间
ZonedDateTime zbj = ZonedDateTime.now(); // 默认时区
//2023-08-27T19:32:02.975+08:00[Asia/Shanghai]
System.out.println(zbj);
// 用指定时区获取当前时间(美国/纽约)
//ZonedDateTime zny = ZonedDateTime.now(ZoneId.of("America/New_York"));
//System.out.println(zny);
}
}
- yml: 次に、この時刻形式を yml 構成ファイルにコピーします。これは、lb アドレスが指定された時刻になるまで有効にならないことを意味します。2 つの条件は組み合わせて使用されます。
server:
port: 9527
spring:
application:
name: cloud-gateway
#网关配置:
cloud:
gateway:
discovery:
locator:
enabled: true #开启从注册中心动态创建路由的功能,利用微服务名进行路由
routes: #routes表示可以路由多个,可以为某个controller里面的所有rest接口都可以做路由
#第一个路由
- id: payment_routh #payment_route #路由的ID,没有固定规则但要求唯一,建议配合服务名
#uri: http://localhost:8001 #匹配后提供服务的路由地址 写死的
uri: lb://cloud-payment-service #匹配后提供服务的路由地址(8001 8002集群组成的微服务名称) 替换为动态的
predicates:
- Path=/payment/get/** # 断言,路径相匹配的进行路由
#第二个路由
- id: payment_routh2 #payment_route #路由的ID,没有固定规则但要求唯一,建议配合服务名
#uri: http://localhost:8001 #匹配后提供服务的路由地址 写死的
uri: lb://cloud-payment-service #匹配后提供服务的路由地址 替换为动态的
predicates:
- Path=/payment/lb/** # 断言,路径相匹配的进行路由
- After=2023-08-27T19:32:02.975+08:00[Asia/Shanghai] #这个匹配的请求要在指定的时间之后,路由地址lb才生效(亚洲/上海)
eureka:
instance:
hostname: cloud-gateway-service
client: #服务提供者provider注册进eureka服务列表内
service-url:
register-with-eureka: true
fetch-registry: true
defaultZone: http://eureka7001.com:7001/eureka #以单机版为例,不然集群启动太慢
- テスト:
- 現在時刻が設定されている場合は、テスト中に現在時刻が経過している必要があるため、有効になります。9527 を再起動してアクセスに成功すると、2 つのポート 8001/8002 が切り替わります。
http://localhost:9527/payment/lb
- この時刻をまだ到着していない時刻に変更します。たとえば、現在時刻が 2023.8 27.19:52 である場合、2023.8 27.20:52 に変更します。現時点では時刻は到着していないため、有効になりません。エラー http://localhost:9527/payment/
lb
- 現在時刻が設定されている場合は、テスト中に現在時刻が経過している必要があるため、有効になります。9527 を再起動してアクセスに成功すると、2 つのポート 8001/8002 が切り替わります。
2)ルート述語の前
- 使用方法は 1) ルート述語の後と同じです。
- 述語の下には、指定した時刻になるまでlbアドレスが有効にならないことを意味する項目が2つあり、組み合わせて使用します。
# 在指定的时间之前生效
- Before=2020-02-05T15:10:03.685+08:00[Asia/Shanghai] # 断言,路径相匹配的进行路由
3)ルート述語間
- 使用方法は 1) ルート述語の後と同じです。
- 2つのアイテムを一緒に使用
# 在指定的2个时间内生效
- Between=2020-02-02T17:45:06.206+08:00[Asia/Shanghai],2020-03-25T18:59:06.206+08:00[Asia/Shanghai]
4)Cookieルート述語
- 公式 Web サイトのケース:
Cookie Route Predicate には 2 つのパラメーターが必要です。1 つは Cookie 名、もう 1 つは正規表現です。
ルーティング ルールは、対応する Cookie 名の値と正規表現を取得することで照合され、一致する場合はルーティングが実行され、一致しない場合はルーティングは実行されません。
spring:
cloud:
gateway:
routes:
- id: cookie_route
uri: https://example.org
predicates:
- Cookie=chocolate, ch.p
自分でテストしてください:
- get リクエストと post リクエストを送信する方法をシミュレートしますか? ? ?
- jmeterツール
- 郵便配達員ツール (グラフィカル ツール)
- curl コマンド (基礎となるグラフィカル ツールによって使用されるコマンド)
- この場合、curl コマンドを使用してマイクロサービスをデバッグします。
- yml ファイル: 指定された時間が経過すると、Cookie 形式が満たされた場合にのみ lb パスが有効になることを示します。
#第二个路由
- id: payment_routh2 #payment_route #路由的ID,没有固定规则但要求唯一,建议配合服务名
#uri: http://localhost:8001 #匹配后提供服务的路由地址 写死的
uri: lb://cloud-payment-service #匹配后提供服务的路由地址 替换为动态的
predicates:
- Path=/payment/lb/** # 断言,路径相匹配的进行路由
- After=2023-08-27T19:32:02.975+08:00[Asia/Shanghai] #这个匹配的请求要在指定的时间之后,路由地址lb才生效(亚洲/上海)
#- Before=2020-02-05T15:10:03.685+08:00[Asia/Shanghai] #在指定时间之前生效
#- Between=2020-02-02T17:45:06.206+08:00[Asia/Shanghai],2020-03-25T18:59:06.206+08:00[Asia/Shanghai] #在指定的2个时间之内生效
- Cookie=username,zzyy #满足cookie名和正则表达式格式
-
Cookie を使用せずにアクセスするには、get リクエストを送信します。
curl http://localhost:9527/payment/lb
- 現時点では、Cookie が満たされていないため、有効になりません。
- 現時点では、Cookie が満たされていないため、有効になりません。
-
Cookie を使用してアクセスする:
curl http://localhost:9527/payment/lb --cookie "username=zzyy"
- 指定された時間が経過すると、Cookie 形式が満たされるため、lb パスが有効になり、エフェクト 8001 と 8002 が交互に表示されます。
- curl を追加すると中国語の文字化けが返される場合は、このアドレスのブログで解決策を確認してください。
https://blog.csdn.net/leedee/article/details/82685636
- 指定された時間が経過すると、Cookie 形式が満たされるため、lb パスが有効になり、エフェクト 8001 と 8002 が交互に表示されます。
5)ヘッダルート述語
- 公式サイトの場合
パラメータは属性名と正規表現の2つで、属性値が正規表現と一致した場合に実行されます。
spring:
cloud:
gateway:
routes:
- id: header_route
uri: https://example.org
predicates:
- Header=X-Request-Id, \d+
自分でテストしてみよう
- yml ファイル: lb は、リクエスト ヘッダーの一致ルールが満たされる場合にのみ有効になります (コメント アウトされているルールとコメント アウトされていないルールを明確に確認してください)。
#第二个路由
- id: payment_routh2 #payment_route #路由的ID,没有固定规则但要求唯一,建议配合服务名
#uri: http://localhost:8001 #匹配后提供服务的路由地址 写死的
uri: lb://cloud-payment-service #匹配后提供服务的路由地址 替换为动态的
predicates:
- Path=/payment/lb/** # 断言,路径相匹配的进行路由
#- After=2023-08-27T19:32:02.975+08:00[Asia/Shanghai] #这个匹配的请求要在指定的时间之后,路由地址lb才生效(亚洲/上海)
#- Before=2020-02-05T15:10:03.685+08:00[Asia/Shanghai] #在指定时间之前生效
#- Between=2020-02-02T17:45:06.206+08:00[Asia/Shanghai],2020-03-25T18:59:06.206+08:00[Asia/Shanghai] #在指定的2个时间之内生效
#- Cookie=username,zzyy #满足cookie名和正则表达式格式
- Header=X-Request-Id, \d+ # 请求头要有X-Request-Id属性并且值为整数的正则表达式
- カールテスト:
curl http://localhost:9527/payment/lb -H "X-Request-Id:123"
6)ホストルート述語
- 公式 Web サイトのドキュメント
Host Route Predicate は、パラメーターのセットと一致するドメイン名のリストを受け取ります。このテンプレートは、区切り文字として . を使用する、アント区切りのテンプレートです。
パラメータ内のホスト アドレスを一致ルールとして使用します。
テスト
- yml
- Host=**.atguigu.com #根据主机地址进行匹配
- コマンドを入力してください
- 正确:curl http://localhost:9527/payment/lb -H “ホスト: www.atguigu.com”
- 错误:curl http://localhost:9527/payment/lb -H “ホスト: java.atguigu.net”
7)メソッドルート述語
- 公式ドキュメント
自分でテストしてください:
- yml
- Method=GET #根据请求方式进行匹配
- アドレスを入力してください: 何も書かず、リクエストを取得するだけです
8)パス・ルート述語
- 公式ドキュメント
テスト
- 以前のパスの一致です 詳細は「12.4 入門設定」を参照してください ----7), 8)
9)クエリルート述語
- 公式ドキュメント
自分でテストしてみよう
- yml
- Query=username, \d+ # 要有参数名username并且值还要是整数才能路由
- 正确:http://localhost:9527/payment/lb?username=31
- 错误:http://localhost:9527/payment/lb?username=-31
10) まとめ
- 合計yml
server:
port: 9527
spring:
application:
name: cloud-gateway
#网关配置:
cloud:
gateway:
discovery:
locator:
enabled: true #开启从注册中心动态创建路由的功能,利用微服务名进行路由
routes: #routes表示可以路由多个,可以为某个controller里面的所有rest接口都可以做路由
#第一个路由
- id: payment_routh #payment_route #路由的ID,没有固定规则但要求唯一,建议配合服务名
#uri: http://localhost:8001 #匹配后提供服务的路由地址 写死的
uri: lb://cloud-payment-service #匹配后提供服务的路由地址(8001 8002集群组成的微服务名称) 替换为动态的
predicates:
- Path=/payment/get/** # 断言,路径相匹配的进行路由
#第二个路由
- id: payment_routh2 #payment_route #路由的ID,没有固定规则但要求唯一,建议配合服务名
#uri: http://localhost:8001 #匹配后提供服务的路由地址 写死的
uri: lb://cloud-payment-service #匹配后提供服务的路由地址 替换为动态的
predicates:
- Path=/payment/lb/** # 断言,路径相匹配的进行路由
#- After=2023-08-27T19:32:02.975+08:00[Asia/Shanghai] #这个匹配的请求要在指定的时间之后,路由地址lb才生效(亚洲/上海)
#- Before=2020-02-05T15:10:03.685+08:00[Asia/Shanghai] #在指定时间之前生效
#- Between=2020-02-02T17:45:06.206+08:00[Asia/Shanghai],2020-03-25T18:59:06.206+08:00[Asia/Shanghai] #在指定的2个时间之内生效
#- Cookie=username,zzyy #满足cookie名和正则表达式格式
#- Header=X-Request-Id, \d+ # 请求头要有X-Request-Id属性并且值为整数的正则表达式
#- Host=**.atguigu.com
#- Method=GET #根据请求方式进行匹配
- Query=username, \d+ # 要有参数名username并且值还要是整数才能路由
eureka:
instance:
hostname: cloud-gateway-service
client: #服务提供者provider注册进eureka服务列表内
service-url:
register-with-eureka: true
fetch-registry: true
defaultZone: http://eureka7001.com:7001/eureka #以单机版为例,不然集群启动太慢
- 率直に言うと、述語は、リクエストが処理する対応するルートを見つけられるように、一連の一致ルールを実装することです。
12.7 フィルターの使用
- GatewayFilter はゲートウェイに提供されるフィルターで、ゲートウェイに入るリクエストとマイクロサービスから返されるレスポンスを処理できます。
12.7.1 とは
ルーティング フィルターを使用すると、受信した HTTP 要求と返された HTTP 応答を変更できます。ルーティング フィルターで指定できるのは、使用するルートのみです。
Spring Cloud Gateway にはさまざまな組み込みルーティング フィルターがあり、それらはすべて GatewayFilter のファクトリ クラスによって生成されます。
12.7.2 Spring Cloud Gatewayのフィルタ
ライフサイクル、たった 2
- pre: ビジネスロジックの前
- post: ビジネス ロジックの後
タイプは 2 つだけ:
-
ゲートウェイフィルター: シングル
-
GlobalFilter: グローバル
-
詳細は公式ウェブサイトをご確認ください: https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.1.RELEASE/reference/html/#gatewayfilter-factories
12.7.3 一般的に使用される GatewayFilter (単一フィルター)
- YML
filters:
- AddRequestParameter=X-Request-Id,1024 #过滤器工厂会在匹配的请求头加上一对请求头,名称为X-Request-Id值为1024
- その他は公式サイトをチェック
12.7.4 グローバル GlobalFilter (グローバル フィルター) のカスタマイズ
1) 2 つの主要なインターフェイスの紹介
implements GlobalFilter,Ordered
2) 何ができますか?
- グローバルロギング
- 統合ゲートウェイ認証
- …
3) ケースコード
package com.angenin.springcloud.filter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.util.Date;
@Component
@Slf4j
public class MyLogGateWayFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
log.info("**************come in MyLogGateWayFilter:" + new Date());
//获取request中的uname参数
String uname = exchange.getRequest().getQueryParams().getFirst("uname");
if(uname == null){
log.info("*******用户名为null,非法用户!!");
//设置 response 状态码 因为在请求之前过滤的,so就算是返回NOT_FOUND 也不会返回错误页面
exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
//完成请求调用
return exchange.getResponse().setComplete();
}
//过滤链放行
return chain.filter(exchange);
}
@Override
public int getOrder() {
//返回值是过滤器的优先级,越小优先级越高(最小-2147483648,最大2147483648)
return 0;
}
}
4) テスト
-
起動する
-
正しい: http://localhost:9527/payment/lb?uname=z3 (8001 8002 が前後に切り替わります)
-
間違い
- パラメータ uname: http://localhost:9527/payment/lb がないため、転送は正常に使用できません。
- パラメータ uname: http://localhost:9527/payment/lb がないため、転送は正常に使用できません。
-
9527 コンソールログ
13 SpringCloud Config 分散構成センター
13.1 概要
13.1.1 分散システムが直面する構成の問題
-
マイクロサービスとは、1 つのアプリケーション内のビジネスをサブサービスに分割することを意味し、各サービスの粒度は比較的小さいため、システム内には多数のサービスが存在します。各サービスの実行には必要な構成情報が必要なため、一元化された動的な構成管理機能が不可欠です。
-
SpringCloud は、この問題を解決するために ConfigServer を提供しています。各マイクロサービスには、数百の構成ファイルを管理する独自の application.yml があります... /
(ㄒoㄒ)/~~
13.1.2 とは
-
とは
- SpringCloud Config は、マイクロサービス アーキテクチャ内のマイクロサービスに対する一元的な外部構成サポートを提供し、
各个不同微服务应用
すべての環境に構成サーバーが提供されます中心化的外部配置
。
- SpringCloud Config は、マイクロサービス アーキテクチャ内のマイクロサービスに対する一元的な外部構成サポートを提供し、
-
遊び方
- SpringCloud Config は に分かれています
服务端和客户端两部分
。 - サーバーは サーバー とも呼ばれ
分布式配置中心,它是一个独立的微服务应用
、構成サーバーに接続し、クライアントが構成情報の取得、情報の暗号化/復号化などを行うためのアクセス インターフェイスを提供するために使用されます。 - クライアントは、指定された構成センターを通じてアプリケーション リソースとビジネス関連の構成コンテンツを管理し、起動時に構成センターから構成情報を取得およびロードします。構成サーバーは、デフォルトで git を使用して構成情報を保存します。これは便利です。環境のバージョン管理構成と構成コンテンツは、git クライアント ツールを通じて簡単に管理およびアクセスできます。
- SpringCloud Config は に分かれています
-
例:
- 問題: 3 つのマイクロサービス プロジェクトの yml ファイルはすべて同じデータベースに接続されています。この時点でポート番号を変更する必要がある場合は、3 つの yml ファイルすべてを変更する必要があります。
- 解決策: パブリック構成を構成センターに抽出し、プライベート構成を独自の yml ファイルに書き込むことで、管理が容易になります。
- 以下に示すように: 運用保守エンジニアは GitHub 上の構成を変更し、それをローカルに同期し、さらにローカルで共有構成センターに同期し、それを ABC に一緒にダウンロードさせることで、運用保守エンジニアが構成を変更できるようにします。一度だけでどこでも公開できます。
13.1.3 できること
- 構成ファイルを一元管理する
- 異なる環境の異なる構成、動的な構成の更新、dev/test/prod/beta/release などの環境固有のデプロイメント
- 運用中に構成を動的に調整します。各サービスがデプロイされているマシンに構成ファイルを書き込む必要はありません。サービスは、構成センターから独自の構成情報を均一に取得します。
- 構成が変更された場合、構成の変更を検出して新しい構成を適用するためにサービスを再起動する必要はありません。
- REST インターフェイスの形式で構成情報を公開します。ポストおよびカールのアクセスとリフレッシュを使用できます...
13.1.4 GitHub と構成を統合する
- SpringCloud Config はデフォルトで構成ファイルの保存に Git を使用するため (SVN やローカル ファイルのサポートなど、他の方法もあります)、最も推奨されるのは Git であり、http/https アクセスを使用します。
13.1.5 公式ウェブサイト
- https://cloud.spring.io/spring-cloud-static/spring-cloud-config/2.2.1.RELEASE/reference/html/
13.2 Configサーバーの構成とテスト
13.2.1 GitHub環境のセットアップ
-
自分のアカウントを使用して、GitHub 上に springcloud-config という名前の新しいリポジトリ リモート ウェアハウスを作成します
-
前の手順で新しく作成した git アドレスを取得します。
https://github.com/123shuai-aa/springcloud-config.git
-
ローカル ハードディスク ディレクトリに新しい git ローカル ウェアハウスを作成し、リモート ウェアハウスのクローンをローカルに作成します。
-
ローカルウェアハウスの場所: E:\Git-bendiku\SpringCloud2020
-
コマンドラインターミナルを開きます
-
コマンド ライン ターミナルにクローン作成コマンドを入力します。
git clone https://github.com/123shuai-aa/springcloud-config.git
- この新しく作成されたリモート ライブラリにはコンテンツがないため、警告が報告されます。
- この新しく作成されたリモート ライブラリにはコンテンツがないため、警告が報告されます。
-
効果:
-
-
springcloud-config ディレクトリに 3 つの yml 設定ファイルを作成します。保存形式は UTF-8 である必要があります (デフォルトは )。
-
開発環境:config-dev.yml
-
実稼働環境: config-pro.yml
-
テスト環境: config-test.yml
-
-
config-dev.yml:
config:
info: "master branch,springcloud-config/config-dev.yml version=1"
- config-pro.yml:
config:
info: "master branch,springcloud-config/config-prod.yml version=1"
- config-test.yml:
config:
info: "master branch,springcloud-config/config-test.yml version=1"
- コマンドを使用して、これら 3 つのファイルをリモート ウェアハウスにプッシュします: (コマンド ライン ターミナルを入力する場合)
-
ローカル ライブラリのステータスを確認します: git status、3 つの yml ファイルが表示されます。
-
ステージング領域に追加: git add ファイル名
- git add config-dev.yml
- git add config-pro.yml
- git add config-test.yml
-
ローカル ライブラリを送信します: git commit -m 「ログ情報」ファイル名 (英語の記号に注意してください)
- git commit -m “init yml” config-dev.yml
- git commit -m “init yml” config-pro.yml
- git commit -m “init yml” config-test.yml
- 再度ステータスを確認すると、送信後、送信するファイルが存在しないことが表示されます。
-
リモート ライブラリのリンク アドレスは長すぎて覚えにくいため、将来コードのプッシュとプルをより便利にするために、リンクにエイリアスを付けました (
语法:git remote add 别名 远程库链接地址
)- 現在のリモート アドレス エイリアスをすべて表示します: git Remote -v
- デフォルトのエイリアスはorigin であるため、別のエイリアスを作成する必要はありません。
-
ローカル図書館ブランチをリモートウェアハウスにプッシュします。
-
構文: git Push alias Branch (デフォルトのブランチ名はメインブランチ: main)
-
git プッシュ オリジン メイン
-
ウィンドウが表示されるので、 を選択します
浏览器账号登录
。
-
GitHub アカウントのパスワードを入力してください
-
認証情報マネージャーに追加
-
コマンドラインの効果:
-
-
ブラウザの git ページを更新すると、メイン ブランチのコンテンツが GitHub によって作成されたリモート リポジトリにプッシュされたことがわかります。
-
13.2.2 構成センターモジュール Congig Server の作成
- 新しいモジュール モジュールcloud-config-center-3344を作成します。
これは、クラウドの構成センター モジュールcloudConfig Centerです。
1) モジュール名:cloud-config-center-3344
2)ポム
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>cloud2020</artifactId>
<groupId>com.angenin.springcloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-config-center-3344</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<!--config server-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
<!--eureka client(通过微服务名实现动态路由)-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--热部署-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
3)YML
- git、GitHub環境のパスワードアカウントコマンド、ideaとの連携が完了していることが前提となります。
server:
port: 3344
spring:
application:
name: cloud-config-center #注册进Eureka服务器的微服务名
cloud:
config:
server:
git:
uri: https://github.com/123shuai-aa/springcloud-config.git #git的仓库地址
search-paths: #搜索目录
- springcloud-config
label: main #读取的分支
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka #服务注册到的eureka地址
- 対応する構成
4) メインスタートアップクラス
package com.angenin.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;
@SpringBootApplication
@EnableConfigServer
public class ConfigCenterMain3344
{
public static void main(String[] args) {
SpringApplication.run(ConfigCenterMain3344.class, args);
}
}
5) Windows: ホストファイルを変更します。
- Windows でホスト ファイルを変更し、マッピングを追加します。
- 127.0.0.1 config-3344.com
6) テスト
- Config マイクロサービスを介して GitHub から構成コンテンツを取得できるかどうかをテストする
- マイクロサービス 7001、3344 の開始
- http://config-3344.com:3344/main/config-dev.yml (GitHub 上の構成ファイルにアクセスでき、SpringCloud Config を使用して GitHub 経由で構成情報を取得することに成功しました)
- この部分はこれで完了です。
13.2.3 読み取りルールの設定
公式ウェブサイト:https://cloud.spring.io/spring-cloud-static/spring-cloud-config/2.2.1.RELEASE/reference/html/#_quick_start
- つまり、GitHub ウェアハウス内の構成ファイルを読み取るためにブラウザにどのような形式のアドレスを入力できるかということです。(5種類)
そのうちの 3 つを説明します。
- 1 つ目: /{label}/{application}-{profile}.yml (ブランチ名 + ファイル名、ファイル名の間にスペーサーを入れることを推奨、上記でテストした書き込み方法を推奨)
- マスターブランチ
- http://config-3344.com:3344/main/config-dev.yml
- http://config-3344.com:3344/main/config-test.yml
- http://config-3344.com:3344/main/config-pro.yml
- 開発ブランチ
- http://config-3344.com:3344/dev/config-dev.yml
- http://config-3344.com:3344/dev/config-test.yml
- http://config-3344.com:3344/dev/config-pro.yml
- マスターブランチ
- 2 番目のタイプ: /{アプリケーション}-{プロファイル}.yml (ファイル名のみを記述します。ファイル名の間にはスペースが必要です)
- http://config-3344.com:3344/config-dev.yml
- http://config-3344.com:3344/config-test.yml
- http://config-3344.com:3344/config-pro.yml
- http://config-3344.com:3344/config-xxxx.yml (存在しない構成)、結果は次のようになります。
{}
- 3 番目のタイプ: /{application}/{profile}[/{label}] (最初のタイプの逆の操作、結果は json 形式)
-
http://config-3344.com:3344/config/dev/main
-
http://config-3344.com:3344/config/test/main
-
http://config-3344.com:3344/config/test/dev
-
用語集:
- /{名前}-{プロフィール}.yml
- /{ラベル}-{名前}-{プロファイル}.yml
- レーベル: ブランチ
- 名前: サービス名
- プロファイル: 環境 (開発/テスト/本番)
13.3 Config クライアントの構成とテスト
13.3.1 新しいcloud-config-client-3355の作成
13.3.2 POM
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>cloud2020</artifactId>
<groupId>com.angenin.springcloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-config-client-3355</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<!--config server-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<!--eureka client(通过微服务名实现动态路由)-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--热部署-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
13.3.3 ブートストラップ.yml
-
とは:
- application.yml はユーザーレベルのリソース構成アイテムです。
- bootstrap.yml はシステムレベルです。
优先级更加高
Application Context
Spring Cloud は、Spring アプリケーションの親コンテキストとして「ブートストラップ コンテキスト」を作成します。初期化中に、外部ソースBootstrap Context
から構成プロパティをロードし、構成を解析します。2 つのコンテキストは外部から取得したコンテキストを共有します。Environment
Bootstrap
プロパティは優先度が高く、デフォルトではローカル構成によって上書きされません。Bootstrap context
とApplication Context
規則が異なるため、構成からbootstrap.yml
確実に分離するために新しいファイルが追加されました。Bootstrap Context
Application Context
- bootstrap.yml は application.yml よりも前に読み込まれるため、Client モジュールの application.yml ファイルを bootstrap.yml に変更することが重要です。bootstrap.yml は application.yml よりも優先されます。
- 要約: クライアント A サービスは 2 つの構成ファイルを保持しており、1 つは構成センター 3344 との通信用の bootstrap.yml であり、もう 1 つは自身が使用するための application.yml であることがわかります。このようにして、公開されているものが読み取られます。最初に 3344 構成センターからそれを独自の bootstrap.yml に構成し、次に独自の application.yml をロードします。これらを組み合わせると、最も完全なクライアント ファイルになります。
-
コンテンツ:
server:
port: 3355
spring:
application:
name: config-client
cloud:
#Config客户端配置
config:
label: main #分支名称
name: config #配置文件名称
profile: dev #读取后缀名称 上述3个综合:master分支上config-dev.yml的配置文件被读取http://config-3344.com:3344/main/config-dev.yml
uri: http://localhost:3344 #配置中心地址
#过程:表示3355通过3344间接读取到配置的主分支下面的config-dev配置文件。
#服务注册到eureka地址
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka
- 例証します:
13.3.4 メイン起動
package com.angenin.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@EnableEurekaClient
@SpringBootApplication
public class ConfigClientMain3355 {
public static void main(String[] args) {
SpringApplication.run(ConfigClientMain3355.class,args);
}
}
13.3.5 ビジネスクラス
13.1.3 で前述したように、何ができるか:
- 分散構成センターは、REST インターフェイスの形式で構成情報を公開できます。post、curl アクセス、およびリフレッシュを行うことができます。
- 説明: 構成情報が公開されるため、3355 は REST スタイルを通じて 3344 構成センターのメッセージおよびコンテンツ構成を読み取ることができます。
package com.angenin.springcloud.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ConfigClientController {
@Value("${config.info}")
private String configInfo;
@GetMapping("/configInfo")
public String getConfigInfo() {
return configInfo;
}
}
@Value("${config.info}")
読み込まれるのはGitHubの設定ファイルのプレフィックスです
13.3.6 テスト
-
7001サービス登録センターを開始します
-
Config 構成センター 3344 マイクロサービスを開始し、セルフテストを行います。
-
http://config-3344.com:3344/main/config-pro.yml
-
http://config-3344.com:3344/main/config-dev.yml
-
-
3355 をクライアントとして起動してアクセスの準備をします
- http://localhost:3355/configInfo
- http://localhost:3355/configInfo
-
結論: GitHub 経由で構成情報を取得するための SpringCloud Config3344 へのクライアント 3355 アクセスの実装に成功しました。
13.3.7 問題はいつでも起こる、分散構成の動的更新の問題
-
Linuxの運用保守はGitHub上の設定ファイルの内容を変更して調整します
- config-dev.yml 構成を変更し、変数の経過時間やバージョン番号を追加するなど、GitHub に送信します。
- config-dev.yml 構成を変更し、変数の経過時間やバージョン番号を追加するなど、GitHub に送信します。
-
3344 ブラウザ ページを更新すると、ConfigServer 構成センターがすぐに応答したことがわかります。
-
3355 を更新したところ、ConfigClient クライアントが応答していないことがわかりました。
-
3355 再起動またはリロードしない限り変化はありません
-
運用や保守で設定ファイルを変更するたびにクライアントを再起動する必要があるほど難しいのでしょうか? ? 悪夢
13.4 Configクライアントの動的更新(手動)
- 目的: 構成が更新されるたびにクライアント マイクロサービスを再起動しないようにする
13.4.1 動的リフレッシュ変更 3355 モジュール
1) POM によるアクチュエータ監視の導入
- 上記でグラフィカルな監視の依存関係が追加されており、意味自体が変化した後に他の人が監視できるようになります。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
2) YMLを変更してモニタリングポートを公開する
server:
port: 3355
spring:
application:
name: config-client
cloud:
#Config客户端配置
config:
label: main #分支名称
name: config #配置文件名称
profile: dev #读取后缀名称 上述3个综合:master分支上config-dev.yml的配置文件被读取http://config-3344.com:3344/main/config-dev.yml
uri: http://localhost:3344 #配置中心地址
#过程:表示3355通过3344间接读取到配置的主分支下面的config-dev配置文件。
#服务注册到eureka地址
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka
# 暴露监控端点
management:
endpoints:
web:
exposure:
include: "*"
3) @RefreshScope ビジネスクラスコントローラーの変更
package com.angenin.springcloud.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RefreshScope //实现刷新功能
public class ConfigClientController {
@Value("${config.info}")
private String configInfo;
@GetMapping("/configInfo")
public String getConfigInfo() {
return configInfo;
}
}
4) テスト: 3355 は有効になりません
- 3355 構成を再起動して有効にします
- GitHub コンテンツのバージョンを再度 3 に変更します。
- セルフテスト アクセス 3344 で、コンテンツが変更されたことが判明しました -- 有効です
- http://config-3344.com:3344/main/config-dev.yml
- http://config-3344.com:3344/main/config-dev.yml
- 訪問 3355----構成は変更されましたが、まだ有効になっていません。
5) 問題を解決します: 3355 が有効になりません
-
運用および保守担当者は、3355 を更新するために Post リクエストを送信する必要があります。
- POSTリクエストである必要があります
curl -X POST "http://localhost:3355/actuator/refresh"
(コマンドラインウィンドウ)
-
もう一度 3355 にアクセスします。この時点では 3355 は再起動されていませんが、バージョン番号が変更されていることがわかり、構成が有効になっていることがわかります。
- 利点: サービスの再起動を回避する
- http://localhost:3355/configInfo
13.4.2 他に何か質問はありますか?
-
複数のマイクロサービス クライアント 3355/3366/3377 がある場合、各マイクロサービスはポスト リクエストを実行し、手動で更新する必要がありますか?
- 解決策: for ループでバッチ スクリプトを作成します。
-
通知を一度ブロードキャストすると、どこでも有効になるようにすることはできますか? 大規模に自動更新したいので方法を見つけてください
- 質問 1: 100 台のマシンの場合、通知を 1 回ブロードキャストするだけですべてのマシンに有効になり、100 回のポスト リクエストを行う必要はありません。
- 質問 2: 100 台のマシンがあり、そのうち 98 台は発効する必要があり、残りの 2 台は発効する必要がなく、元のバージョンを維持する必要があります。この種の正確な通知と正確なクリア。
-
解決策: 上記一連の問題については、SpringCloud Bus メッセージ バスを使用することで、一括通知と正確な通知を解決できます。
14 SpringCloud Bus メッセージ バス
14.1 概要
-
先ほどの説明の深化・拡張を一言で言うと
- 分散自動リフレッシュ設定機能
- Spring Cloud Bus を Spring Cloud Config とともに使用すると、構成の動的な更新を実現できます。
-
とは
- Spring Cloud Bus は、分散システム ノードを軽量メッセージング システムとリンクするために使用されるフレームワークです。
它整合了Java的事件处理机制和消息中间件的功能。
- Spring Clud Bus は、RabbitMQ と Kafka の 2 つのメッセージ ブローカーをサポートします。
- Spring Cloud Bus は、分散システム ノードを軽量メッセージング システムとリンクするために使用されるフレームワークです。
-
何ができますか
- Spring Cloud Bus は、分散エグゼキューターと同様に、分散システム間でメッセージを管理および伝達できます。分散エグゼキューターは、状態変更やイベント プッシュなどをブロードキャストするために使用でき、マイクロサービス間の通信チャネルとしても使用できます。
- Spring Cloud Bus は、分散エグゼキューターと同様に、分散システム間でメッセージを管理および伝達できます。分散エグゼキューターは、状態変更やイベント プッシュなどをブロードキャストするために使用でき、マイクロサービス間の通信チャネルとしても使用できます。
-
なぜバスと呼ばれるのでしょうか?
- バスとは何ですか
- マイクロサービス アーキテクチャを備えたシステムでは、通常、マイクロサービスアーキテクチャ
轻量级的消息代理
を構築し共用的消息主题
、システム内のすべてのマイクロサービス インスタンスを接続するために使用されます。なぜなら该主题中产生的消息会被所有实例监听和消费,所以称它为消息总线
。バス上の各インスタンスは、トピックに接続されている他のインスタンスに知らせる必要があるメッセージを簡単にブロードキャストできます。
- マイクロサービス アーキテクチャを備えたシステムでは、通常、マイクロサービスアーキテクチャ
- 基本的
- ConfigClient インスタンスはすべて、MQ 内の同じトピックをリッスンします (デフォルトは springCloudBus)。サービスがデータを更新すると、同じトピックをリッスンしている他のサービスが通知を受けて、独自の構成を更新できるように、この情報がトピックに追加されます。
- テーマなどの名詞の意味がわからない場合は、以下を確認してください。
杨哥B站ActiveMQ课程:https://www.bilibili.com/video/av55976700?from=search&seid=15010075915728605208
- バスとは何ですか
14.2 RabbitMQの環境設定
- このコースでは Windows 環境に RabbitMQ をインストールしますが、ここでは Linux 環境に RabbitMQ をインストールする場合を例に説明します。
- インストール手順を表示します: https://blog.csdn.net/aa35434/article/details/126634371
- RabbitMQ バックエンド管理インターフェイスにログインします。
http://192.168.10.140:15672/
- ユーザー名: 管理者
- パスワード: 123456
- 効果:
14.3 SpringCloud Bus はグローバル ブロードキャストを動的に更新します
- まず適切な RabbitMQ 環境を用意する必要があります
14.3.1 3355 をテンプレートとして使用して別の 3366 を作成する
- ブロードキャスト効果を実証し、複雑さを高めてから、3355 をテンプレートとして使用して 3366 を作成します。
1) 新しいcloud-config-client-3366を作成します。
1)ポム
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>cloud2020</artifactId>
<groupId>com.angenin.springcloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-config-client-3366</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<!--config server-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<!--eureka client(通过微服务名实现动态路由)-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--热部署-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
2)YML
server:
port: 3366
spring:
application:
name: config-client
cloud:
#Config客户端配置
config:
label: main #分支名称
name: config #配置文件名称
profile: dev #读取后缀名称 上述3个综合:master分支上config-dev.yml的配置文件被读取http://config-3344.com:3344/main/config-dev.yml
uri: http://localhost:3344 #配置中心地址
#过程:表示3366通过3344间接读取到配置的主分支下面的config-dev配置文件。
#服务注册到eureka地址
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka
# 暴露监控端点
management:
endpoints:
web:
exposure:
include: "*"
3) メイン起動
package com.angenin.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@EnableEurekaClient
@SpringBootApplication
public class ConfigClientMain3366 {
public static void main(String[] args) {
SpringApplication.run(ConfigClientMain3366.class,args);
}
}
4)コントローラー
package com.angenin.springcloud.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RefreshScope
public class ConfigClientController {
@Value("${server.port}")
private String serverPort;
@Value("${config.info}")
private String configInfo;
@GetMapping("/configInfo")
public String configInfo() {
return "serverPort: "+serverPort+"\t\n\n configInfo: "+configInfo;
}
}
14.3.2 デザイン思考とテクノロジーの選択
-
メッセージ バスを使用してクライアント/バス/リフレッシュをトリガーし、すべてのクライアントの構成をリフレッシュします
- つまり、クライアント 3355 の 1 つをトリガーし、3355 が通知を 3366 にブロードキャストします。
- つまり、クライアント 3355 の 1 つをトリガーし、3355 が通知を 3366 にブロードキャストします。
-
メッセージ バスを使用して、サーバー ConfigServer の /bus/refresh エンドポイントをトリガーし、すべてのクライアントの構成を更新します。
- つまり、設定センター 3344 へのトリガー、および 3344 から 3355 および 3366 へのブロードキャスト通知です。
- つまり、設定センター 3344 へのトリガー、および 3344 から 3355 および 3366 へのブロードキャスト通知です。
-
図 2 のアーキテクチャの方が明らかに適していますが、図 1 が適さない理由は次のとおりです。
- マイクロサービス自体はビジネス モジュールであり、構成の更新を担当すべきではないため、マイクロサービスの単一責任が崩れます。
- マイクロサービスの各ノードのパリティを破棄します。
- 一定の制限があります。たとえば、マイクロサービスを移行するとネットワーク アドレスが変更されることがよくありますが、その際に自動的に更新したい場合はさらに変更を加えます。
14.3.3 cloud-config-center-3344 の変更
服务端
メッセージ バスのサポートをcloud-config-center-3344 構成センターに追加します。
- POM
<!-- 添加rabbitMQ的消息总线支持包 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
<!--凡事要暴露监控刷新的操作,3344的pom文件一定要引入actuator依赖,之前已经添加过了-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
- YML
server:
port: 3344
spring:
application:
name: cloud-config-center #注册进Eureka服务器的微服务名
cloud:
config:
server:
git:
uri: https://github.com/123shuai-aa/springcloud-config.git #git的仓库地址
search-paths: #搜索目录
- springcloud-config
label: main #读取的分支
#rabbitmq相关配置
rabbitmq:
host: 192.168.10.140 #linux上的主机ip
port: 5672 #15672是图形管理界面的端口,5672是client访问端口
username: admin
password: 123456
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka #服务注册到的eureka地址
#rabbitmq相关配置,暴露bus刷新配置的端点
#凡事要暴露监控刷新的操作,3344的pom文件一定要引入actuator依赖
management:
endpoints: #暴露bus刷新配置的端点
web:
exposure:
include: 'bus-refresh'
14.3.4 cloud-config-client-3355 の変更
客户端
メッセージ バスのサポートをcloud-config-client-3355 に追加します
- POM
<!-- 添加rabbitMQ的消息总线支持包 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
<!--凡事要暴露监控刷新的操作,3344的pom文件一定要引入actuator依赖,之前已经添加过了-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
- YML
server:
port: 3355
spring:
application:
name: config-client
cloud:
#Config客户端配置
config:
label: main #分支名称
name: config #配置文件名称
profile: dev #读取后缀名称 上述3个综合:master分支上config-dev.yml的配置文件被读取http://config-3344.com:3344/main/config-dev.yml
uri: http://localhost:3344 #配置中心地址
#过程:表示3355通过3344间接读取到配置的主分支下面的config-dev配置文件。
#rabbitmq相关配置
rabbitmq:
host: 192.168.10.140 #linux上的主机ip
port: 5672 #15672是图形管理界面的端口,5672是client访问端口
username: admin
password: 123456
#服务注册到eureka地址
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka
# 暴露监控端点
management:
endpoints:
web:
exposure:
include: "*"
14.3.5 cloud-config-client-3366 の変更
客户端
メッセージ バスのサポートをcloud-config-client-3366 に追加します
- POM
<!-- 添加rabbitMQ的消息总线支持包 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
<!--凡事要暴露监控刷新的操作,3344的pom文件一定要引入actuator依赖,之前已经添加过了-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
- YML
server:
port: 3366
spring:
application:
name: config-client
cloud:
#Config客户端配置
config:
label: main #分支名称
name: config #配置文件名称
profile: dev #读取后缀名称 上述3个综合:master分支上config-dev.yml的配置文件被读取http://config-3344.com:3344/main/config-dev.yml
uri: http://localhost:3344 #配置中心地址
#过程:表示3366通过3344间接读取到配置的主分支下面的config-dev配置文件。
#rabbitmq相关配置
rabbitmq:
host: 192.168.10.140 #linux上的主机ip
port: 5672 #15672是图形管理界面的端口,5672是client访问端口
username: admin
password: 123456
#服务注册到eureka地址
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka
# 暴露监控端点
management:
endpoints:
web:
exposure:
include: "*"
14.3.6 テスト
-
開始 7001、3344、3355、3366
-
運用保守エンジニア
-
Github 上の構成ファイルを変更してバージョン番号を増やします
-
POST リクエストを送信 (
刷新的是3344配置中心
)-
curl -X POST “http://localhost:3344/actuator/bus-refresh”
-
一度送信すればどこでも効果的
-
-
-
構成センター
- http://config-3344.com:3344/main/config-dev.yml
- http://config-3344.com:3344/main/config-dev.yml
-
クライアント
-
http://localhost:3355/configInfo
-
http://localhost:3366/configInfo
-
サービスを再起動せずに、再度構成情報を取得したところ、更新されていました。
-
-
一度変更するとブロードキャスト通知が適用され、どこでも有効になります
-
RabbitMQ バックエンド管理インターフェイスにログインします。
- 以前に説明した概念:
- 以前に説明した概念:
14.4 SpringCloud Bus は固定小数点通知を動的に更新します
14.1 ビジネス要件
- 全員に通知するのではなく、特定のポイントだけを通知したい。
- 3355のみに通知
- 通知なし 3366
- 簡単な文
- すべてではなく特定のインスタンスを指定して有効にします
- 公式:
http://localhost:配置中心的端口号/actuator/bus-refresh/{destination}
- /bus/refresh リクエストは特定のサービス インスタンスではなく構成サーバーに送信され、宛先パラメーター クラスを通じて構成を更新する必要があるサービスまたはインスタンスを指定します。
14.2 テストケース
場合
-
ここでは、例としてポート 3355 で実行されている config-client を更新します。
- 3355のみに通知
- 通知なし 3366
-
GitHub設定ファイルを変更する
-
更新:
curl -X POST "http://localhost:3344/actuator/bus-refresh/config-client:3355"
-
つまり、リフレッシュ 3344 を使用して、指定されたサービスに通知します。 3355
-
バスリフレッシュ
-
設定クライアント:3355:
-
-
効果: 3344、3355 リフレッシュ、3366 リフレッシュなし。(再起動なし)
http://config-3344.com:3344/main/config-dev.yml
http://localhost:3355/configInfo
http://localhost:3366/configInfo
14.3 概要
- 通知の概要すべて
15 SpringCloud Stream メッセージドライバー
15.1 メッセージ駆動型の概要
15.1.1 ストリームが導入された理由
-
シーン:
- 現在のシステムは、フロントエンド----「Javaバックエンド----」ビッグデータプラットフォームの3つの部分に分けることができます。現在、JavaバックエンドはRabbitMQを使用し、ビッグデータプラットフォームはKafkaを使用しています。このようにして、スイッチング、メンテナンスが行われます。と開発が実装されていますが、立ち上がるのがさらに面倒です。
- 現在のシステムは、フロントエンド----「Javaバックエンド----」ビッグデータプラットフォームの3つの部分に分けることができます。現在、JavaバックエンドはRabbitMQを使用し、ビッグデータプラットフォームはKafkaを使用しています。このようにして、スイッチング、メンテナンスが行われます。と開発が実装されていますが、立ち上がるのがさらに面倒です。
-
目的:
- 特定の MQ の詳細に注意を払わなくなる新しいテクノロジーは生まれていますか? 必要なのは、アダプテーション バインディング メソッドを使用して、さまざまな MQ を自動的に切り替えるだけです-----SpringCloudStream
-
一般的に使用されるメッセージ ミドルウェア:
- アクティブMQ
- ラビットMQ
- ロケットMQ
- Kafka (ビッグデータによく使用されます)
15.1.1 とは
-
SpringCloudStreamとは
- Spring Cloud Stream の正式な定義は、メッセージ駆動型のマイクロサービスを構築するためのフレームワークです。
- アプリケーションは、入力または出力を通じて Spring Cloud Stream のバインダー オブジェクトと対話します。
- バインディングは設定を通じて行われ、Spring Cloud Stream のバインダー オブジェクトがメッセージ ミドルウェアとの対話を担当します。
- したがって、メッセージ駆動型アプローチを便利に使用するには、Spring Cloud Stream と対話する方法を理解するだけで済みます。
- Spring Integration を使用してメッセージ ブローカー ミドルウェアに接続し、メッセージ イベントの駆動を実現します。
- Spring Cloud Stream は、パブリッシュ/サブスクライブ、コンシューマー グループ、パーティションの 3 つの中心概念を参照して、一部のベンダーのメッセージ ミドルウェア製品にパーソナライズされた自動構成の実装を提供します。
-
目前仅支持RabbitMQ、Kafka。
-
一言で言えば、基盤となるメッセージ ミドルウェアの違いを保護し、スイッチング コストを削減し、メッセージ プログラミング モデルを統一します。
-
公式ウェブサイト:
-
https://spring.io/projects/spring-cloud-stream#overview
- Spring Cloud Stream は、共有メッセージング システムに接続されたスケーラブルなイベント駆動型マイクロサービスを構築するためのフレームワークです。このフレームワークは、publish/永続性をサポートするサブスクライブ、コンシューマ グループ、およびメッセージ パーティショニング
-
公式ドキュメント: https://cloud.spring.io/spring-cloud-static/spring-cloud-stream/3.0.1.RELEASE/reference/html/
-
Spring Cloud Stream 中国語取扱説明書
- https://m.wang1314.com/doc/webapp/topic/20971999.html
- https://m.wang1314.com/doc/webapp/topic/20971999.html
-
15.1.2 デザイン思考
-
標準MQ
消息
メッセージ:情報コンテンツはメディアを通じて生産者と消費者の間で伝達されます。- メッセージ チャネル MessageChannel: メッセージは特定のチャネルを通過する必要があります。
通道
- メッセージ チャネル内のメッセージはどのように消費されますか? 送受信処理の責任者は誰ですか?
- MessageHandler メッセージ プロセッサによってサブスクライブされる、メッセージ チャネル MessageChannel のサブインターフェイス SubscribableChannel
-
クラウド ストリームを使用する理由
- たとえば、RabbitMQ と Kafka を使用します。これら 2 つのメッセージ ミドルウェアのアーキテクチャの違いにより、RabbitMQ には Exchange があり、Kafka には Topic パーティションと Partitions パーティションがあります。これらのミドルウェアの違いにより、実際のプロジェクト開発では特定の問題が発生しました。 2 つのメッセージ キューの 1 つを使用しており、その後のビジネス ニーズに備えて別のメッセージ キューに移行したいと考えていますが、システムと結合されているため、間違いなく大惨事になります。現時点では、springcloud Stream が分離する方法を提供します
一大堆东西都要重新推倒重新做
。
- なぜストリームは根本的な違いを統合できるのでしょうか?
- バインダーの概念がない場合、SpringBoot アプリケーションがメッセージ ミドルウェアと直接対話する場合、各メッセージ ミドルウェアの本来の目的が異なるため、実装の詳細はまったく異なります
应用程序与消息中间件细节之间的隔离。
。チャネル チャネルがアプリケーションに公開されるため、アプリケーションはさまざまなメッセージ ミドルウェアの実装を考慮する必要がなくなります。 通过定义绑定器Binder作为中间层,实现了应用程序与消息中间件细节之间的隔离。
- バインダーの概念がない場合、SpringBoot アプリケーションがメッセージ ミドルウェアと直接対話する場合、各メッセージ ミドルウェアの本来の目的が異なるため、実装の詳細はまったく異なります
Binder
-
バインダーの概念がない場合、SpringBoot アプリケーションがメッセージ ミドルウェアと直接対話する必要がある場合、各メッセージ ミドルウェアの本来の目的が異なるため、実装の詳細は大きく異なります。バインダーを中間層として定義することで、それは完全に実装されています
应用程序与消息中间件细节之间的隔离
。Stream によるメッセージ ミドルウェアのさらなるカプセル化により、コード層がミドルウェアを認識しなくなり、ミドルウェアを動的に切り替える (rabbitmq が kafka に切り替わる) こともできるため、マイクロサービス開発が高度に分離され、サービス自体にさらに注意を向けることができます。 -
通过定义绑定器Binder作为中间层,实现了应用程序与消息中间件细节之间的隔离。
-
BinderはメッセージコンテナのプロデューサとコンシューマをバインドするためのBindingを生成でき、INPUTとOUTPUTの2種類があり、INPUTはコンシューマ、OUTPUTはプロデューサに対応します。
-
INPUTはコンシューマに対応します
-
OUTPUTはプロデューサーに対応します
-
- たとえば、RabbitMQ と Kafka を使用します。これら 2 つのメッセージ ミドルウェアのアーキテクチャの違いにより、RabbitMQ には Exchange があり、Kafka には Topic パーティションと Partitions パーティションがあります。これらのミドルウェアの違いにより、実際のプロジェクト開発では特定の問題が発生しました。 2 つのメッセージ キューの 1 つを使用しており、その後のビジネス ニーズに備えて別のメッセージ キューに移行したいと考えていますが、システムと結合されているため、間違いなく大惨事になります。現時点では、springcloud Stream が分離する方法を提供します
-
Stream でのメッセージ通信方式はパブリッシュ/サブスクライブ モデルに従います。
- 話題のトピック放送
- RabbitMQ は Exchange スイッチです
- カクファで話題です
- 話題のトピック放送
15.1.3 Spring Cloud Streamの標準処理ルーチン
- バインダー
- 非常に便利な接続ミドルウェア、シールドの違い
- チャネル
- チャネルはキューを抽象化したものです。メッセージ通信システムでは、チャネルは保存と転送の媒体です。キューはチャネルを通じて構成されます。
- ソースとシンク
- 単純に考えると、参照オブジェクトは Spring Cloud Stream そのものであり、Stream からのメッセージのパブリッシュが出力 (プロデューサー)、メッセージの受信が入力 (コンシューマー) となります。
15.1.4 API のコーディングと共通のアノテーション
構成 | 説明する |
---|---|
ミドルウェア | ミドルウェア。現在は FRabbitMQ と Kafka のみをサポートしています |
バインダー | Binder はアプリケーションとメッセージミドルウェアの間のカプセル化です。現在、KafKa と RabbitMQ の Binder が実装されています。Binder を介してミドルウェアを簡単に接続し、メッセージの種類を動的に変更できます (Kafka のトピックとRabbitMQ の交換)これらはすべてこれは設定ファイルを通じて実現できます |
@入力 | 注釈は、受信したメッセージがアプリケーションに入る入力チャネルを識別します。 |
@出力 | アノテーションは、パブリッシュされたメッセージがアプリケーションから送信される出力チャネルを識別します。 |
@StreamListener | リスニング キュー。コンシューマ キューからメッセージを受信するために使用されます。 |
@EnableBinding | チャネル Channel と Exchange が結合されていることを指します。 |
15.2 ケースの説明
- RabbitMQ 環境は問題ありません
- プロジェクト内に 3 つの新しいサブモジュールを作成します
- Cloud-stream-rabbitmq-provider8801、プロデューサーとしてメッセージを送信するためのモジュール
- Cloud-stream-rabbitmq-consumer8802、メッセージ受信モジュールとして
- メッセージ受信モジュールとしてのcloud-stream-rabbitmq-consumer8803
15.3 メッセージ駆動型プロデューサー
15.3.1 新しいモジュール:cloud-stream-rabbitmq-provider8801
15.3.2 POM
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>cloud2020</artifactId>
<groupId>com.angenin.springcloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-stream-rabbitmq-provider8801</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</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-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-stream-rabbit</artifactId>
</dependency>
<!--基础配置-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
15.3.3 YML
- 爆発的な人気でも使用に影響なし
server:
port: 8801
spring:
application:
name: cloud-stream-provider
cloud:
stream:
binders: # 在此处配置要绑定的rabbitmq的服务信息;
defaultRabbit: # 表示定义的名称,用于于binding整合
type: rabbit # 消息组件类型
environment: # 设置rabbitmq的相关的环境配置
spring:
rabbitmq:
host: 192.168.10.140
port: 5672
username: admin
password: 123456
bindings: # 服务的整合处理
output: # 这个名字是一个通道的名称 生产者使用output,消费者使用input
destination: studyExchange # 表示要使用的Exchange名称定义
content-type: application/json # 设置消息类型,本次为json,文本则设置“text/plain”
binder: defaultRabbit # 设置要绑定的消息服务的具体设置
eureka:
client: # 客户端进行Eureka注册的配置
service-url:
defaultZone: http://localhost:7001/eureka
instance:
lease-renewal-interval-in-seconds: 2 # 设置心跳的时间间隔(默认是30秒)
lease-expiration-duration-in-seconds: 5 # 如果现在超过了5秒的间隔(默认是90秒)
instance-id: send-8801.com # 在信息列表时显示主机名称
prefer-ip-address: true # 访问的路径变为IP地址
15.3.4 メイン起動クラス StreamMQMain8801
package com.angenin.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class StreamMQMain8801 {
public static void main(String[] args) {
SpringApplication.run(StreamMQMain8801.class,args);
}
}
15.3.5 ビジネスクラス
1) メッセージ送信インターフェース
package com.angenin.springcloud.service;
public interface IMessageProvider {
String send() ;
}
2) 送信メッセージインターフェース実装クラス
package com.angenin.springcloud.service.impl;
import com.angenin.springcloud.service.IMessageProvider;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.messaging.Source;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.messaging.MessageChannel;
import javax.annotation.Resource;
import java.util.UUID;
/**
* 不再是以前crud操作数据库了:业务类上使用@service了,类里面注入dao层对象
* 现在操作的是消息中间件Rabbitmq:使用的是 SpringCloud Stream消息驱动中的注解
*/
@EnableBinding(Source.class) // 可以理解为定义消息的推送管道
public class MessageProviderImpl implements IMessageProvider {
@Resource
private MessageChannel output; // 消息的发送管道
@Override
public String send() {
//定义发送的消息
String serial = UUID.randomUUID().toString();
//使用绑定器将消息绑定起来
output.send(MessageBuilder.withPayload(serial).build());
System.out.println("***serial: "+serial);
return null;
}
}
3)コントローラー
package com.angenin.springcloud.controller;
import com.angenin.springcloud.service.IMessageProvider;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@RestController
public class SendMessageController {
@Resource
private IMessageProvider messageProvider;
//业务:每调用一次就发送一次流水号到Rabbitmq
@GetMapping(value = "/sendMessage")
public String sendMessage() {
return messageProvider.send();
}
}
15.3.6 テスト
- 7001エウレカスタート
- RabbitMQを起動する
- スタート8801
- Rabbitmq 管理インターフェイスにアクセスしてください: http://192.168.10.140:15672
- 対応する構成:
- Rabbitmq 管理インターフェイスにアクセスしてください: http://192.168.10.140:15672
- アクセス
- http://localhost:8801/sendMessage
- リクエストが複数回発生しました:
- System.out... バックグラウンドログの出力情報:
- Rabbitmq 管理インターフェイスで送信されたメッセージのピーク値を確認でき、上記の統合構成が成功したことを示します。
15.4 メッセージ駆動型コンシューマ
15.4.1 新しいモジュール:cloud-stream-rabbitmq-consumer8802
15.4.2 POM
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>cloud2020</artifactId>
<groupId>com.angenin.springcloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-stream-rabbitmq-consumer8802</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</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-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-stream-rabbit</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--基础配置-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
15.4.3 YML
- プロデューサ 8801 との唯一の違いは、プロデューサ 8801 が出力を使用し、コンシューマ 8802 が入力を使用することです。もちろん名前は違います。
server:
port: 8802
spring:
application:
name: cloud-stream-consumer
cloud:
stream:
binders: # 在此处配置要绑定的rabbitmq的服务信息;
defaultRabbit: # 表示定义的名称,用于于binding整合
type: rabbit # 消息组件类型
environment: # 设置rabbitmq的相关的环境配置
spring:
rabbitmq:
host: 192.168.10.140
port: 5672
username: admin
password: 123456
bindings: # 服务的整合处理
input: # 这个名字是一个通道的名称 生产者使用output,消费者使用input
destination: studyExchange # 表示要使用的Exchange名称定义
content-type: application/json # 设置消息类型,本次为对象json,如果是文本则设置“text/plain”
binder: defaultRabbit # 设置要绑定的消息服务的具体设置
eureka:
client: # 客户端进行Eureka注册的配置
service-url:
defaultZone: http://localhost:7001/eureka
instance:
lease-renewal-interval-in-seconds: 2 # 设置心跳的时间间隔(默认是30秒)
lease-expiration-duration-in-seconds: 5 # 如果现在超过了5秒的间隔(默认是90秒)
instance-id: receive-8802.com # 在信息列表时显示主机名称
prefer-ip-address: true # 访问的路径变为IP地址
15.4.4 メイン起動クラス StreamMQMain8802
package com.angenin.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class StreamMQMain8802
{
public static void main(String[] args)
{
SpringApplication.run(StreamMQMain8802.class,args);
}
}
15.4.5 ビジネスクラス
package com.angenin.springcloud.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.annotation.StreamListener;
import org.springframework.cloud.stream.messaging.Sink;
import org.springframework.messaging.Message;
import org.springframework.stereotype.Component;
@Component
@EnableBinding(Sink.class) //指信道channel和exchange绑定在一起
public class ReceiveMessageListener {
@Value("${server.port}")
private String serverPort;
@StreamListener(Sink.INPUT) //监听队列,用于消费者的队列的消息接收
public void input(Message<String> message) {
System.out.println("消费者1号,----->接受到的消息: "+message.getPayload()+"\t port: "+serverPort);
}
}
15.4.6 8801 によるメッセージの送信と 8802 によるメッセージの受信をテストする
- 開始 7001、Rabbitmq、8801、8802
- http://localhost:8801/sendMessage
- Rabbitmq 管理インターフェイスを表示します。
- メッセージプロデューサーがメッセージを送信
- メッセージコンシューマがメッセージを受信する
15.5 グループの消費と持続性
15.1 8802 コンシューマに従って、コピーを複製し、8803 コンシューマを実行します
-
クラウドストリーム-rabbitmq-consumer8803
-
ディレクトリ構造:
-
ポンポン
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>cloud2020</artifactId>
<groupId>com.angenin.springcloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-stream-rabbitmq-consumer8803</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</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-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-stream-rabbit</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--基础配置-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
- YML
server:
port: 8803
spring:
application:
name: cloud-stream-consumer
cloud:
stream:
binders: # 在此处配置要绑定的rabbitmq的服务信息;
defaultRabbit: # 表示定义的名称,用于于binding整合
type: rabbit # 消息组件类型
environment: # 设置rabbitmq的相关的环境配置
spring:
rabbitmq:
host: 192.168.10.140
port: 5672
username: admin
password: 123456
bindings: # 服务的整合处理
input: # 这个名字是一个通道的名称 生产者使用output,消费者使用input
destination: studyExchange # 表示要使用的Exchange名称定义
content-type: application/json # 设置消息类型,本次为对象json,如果是文本则设置“text/plain”
binder: defaultRabbit # 设置要绑定的消息服务的具体设置
eureka:
client: # 客户端进行Eureka注册的配置
service-url:
defaultZone: http://localhost:7001/eureka
instance:
lease-renewal-interval-in-seconds: 2 # 设置心跳的时间间隔(默认是30秒)
lease-expiration-duration-in-seconds: 5 # 如果现在超过了5秒的间隔(默认是90秒)
instance-id: receive-8803.com # 在信息列表时显示主机名称
prefer-ip-address: true # 访问的路径变为IP地址
- メインのスタートアップクラス
package com.angenin.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class StreamMQMain8803 {
public static void main(String[] args) {
SpringApplication.run(StreamMQMain8803.class,args);
}
}
- ビジネスクラス
package com.angenin.springcloud.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.annotation.StreamListener;
import org.springframework.cloud.stream.messaging.Sink;
import org.springframework.messaging.Message;
import org.springframework.stereotype.Component;
@Component
@EnableBinding(Sink.class)
public class ReceiveMessageListener
{
@Value("${server.port}")
private String serverPort;
@StreamListener(Sink.INPUT)
public void input(Message message)
{
System.out.println("消费者2号,------->接收到的消息:" + message.getPayload()+"\t port: "+serverPort);
}
}
15.2 起動
- RabbitMQ を開始する
- 7001サービス登録を開始する
- 8801 メッセージの作成を開始する
- 8802 メッセージの消費を開始する
- 8803 メッセージの消費を開始する
15.3 実行後に 2 つの問題が発生する
- 繰り返し消費する問題がある
- メッセージの永続化の問題
15.4 消費量
現在、8802/8803を同時に入手しているのですが、繰り返し消費してしまう問題があります。
-
http://localhost:8801/sendMessage: プロデューサ 8801 がメッセージを送信し、コンシューマ 8802 と 8803 の両方がメッセージを受信したことがわかりました。
-
の解き方
分组和持久化属性group
-
制作実績例
-
デフォルトでは、8802 と 8803 は異なるグループであり、繰り返し使用できます。
15.5 グループ化
原理
- マイクロサービス アプリケーションを同じグループに配置すると、メッセージがいずれかのアプリケーションによって 1 回だけ消費されるようになります。
不同的组是可以消费的,同一个组内会发生竞争关系,只有其中一个可以消费。
8802/8803は別のグループになっており、2つのグループは異なります。
-
グループ:atguiguA、atguiguB
-
8802 YML の変更:
group: atguiguA
-
8803 YML の変更:
group: atguiguB
-
再起動 8802、8803 が有効になります
-
自分たちで設定します
- 高可用性と負荷分散を実現するために、分散マイクロサービス アプリケーションは実際に複数のインスタンスをデプロイします。この例では、Yang Ge は 2 つのコンシューマー マイクロサービス (8802/8803) を開始しました。ほとんどの場合、プロデューサーが特定のマイクロサービスにメッセージを送信するとき、私たちはのみ2 つのアプリケーションを起動する上記の例によれば、それらは同じアプリケーションに属していますが、メッセージは 2 回消費されます。この問題を解決するために、 Spring Cloud Stream では という概念が提供されています
消费组
。
- 高可用性と負荷分散を実現するために、分散マイクロサービス アプリケーションは実際に複数のインスタンスをデプロイします。この例では、Yang Ge は 2 つのコンシューマー マイクロサービス (8802/8803) を開始しました。ほとんどの場合、プロデューサーが特定のマイクロサービスにメッセージを送信するとき、私たちはのみ2 つのアプリケーションを起動する上記の例によれば、それらは同じアプリケーションに属していますが、メッセージは 2 回消費されます。この問題を解決するために、 Spring Cloud Stream では という概念が提供されています
-
結論:またはリピート消費
-
プロデューサーがメッセージを送信し、3 回クリックします
-
プロデューサーコンソール 8801
-
コンシューマーコンソール 8802
-
コンシューマーコンソール 8803
-
8802/8803 が同じグループになり、2 つのグループは同じになります
-
グループ: アトギグA
-
8802 YML の変更: atguiguA
-
8803 YML の変更: atguiguA
-
再起動が有効になります:
-
自分で設定します。
-
Rabbitmq 管理インターフェイスを見ると、atguiguA と atguiguB という 2 つのグループが見つかりました。atguiguB は以前の履歴レコードであり、それとは何の関係もありません。
-
atguigu グループ A には 8802 と 8803 という 2 つのコンシューマーがいます。このとき、グループ A にメッセージが送信され、毎回競合が発生します。同じグループ内の 1 つのインスタンスのみがメッセージを取得できるため、繰り返しの消費が回避されます。
-
atguiguA をクリックすると、内部に 2 人の消費者がいることがわかります。
-
「guiguB」をクリックします: コンシューマの数は 0 です
-
-
結論: 同じグループ内の複数のマイクロサービス インスタンスのうち、一度に取得できるのは 1 つだけです
-
プロデューサーがメッセージを送信し、2 回クリックします
-
プロデューサーコンソール 8801
-
コンシューマーコンソール 8802
-
コンシューマーコンソール 8803
-
-
8802/8803 はポーリング グループ化を実装しており、コンシューマが 1 つだけ存在する場合、
8801 モジュールによって送信されたメッセージは 8802 または 8803 のいずれかでのみ受信できるため、繰り返しの消費が回避されます。
15.6 持久化
-
上記により、繰り返し消費の問題が解決され、持続性が見られます。
-
8802/8803 を停止し、8802 のグループを削除します: atguiguA
- 8803: atguiguA のグループグループは削除されていません。
- 8803: atguiguA のグループグループは削除されていません。
-
8801 は最初に 4 つのメッセージを Rabbitmq に送信します。
http://localhost:8801/sendMessage
-
最初に 8802 を開始します。グループ属性の設定はなく、メッセージはバックグラウンドで出力されません。
-
8803 を再度起動し、グループ属性を構成すると、MQ 上のメッセージがバックグラウンドで出力されます。
-
概要: コンシューマは、さまざまな問題によりダウンしています。この時点で、プロデューサはメッセージの送信を続け、コンシューマを再起動します。コンシューマが Rabbitmq で消費されていないメッセージを消費する場合、コンシューマがまだ消費されていないメッセージを
配置了分组
消費する場合障害の問題によりメッセージが消費され、メッセージが失われます。会
没有配置分组
不会
16 SpringCloud Sleuth 分散リクエストリンク追跡
16.1 概要
16.1 なぜこの技術が登場したのでしょうか?
- なぜこの技術が登場したのでしょうか?解決する必要がある問題は何ですか?
- マイクロサービス フレームワークでは、クライアントによって開始されたリクエストは、バックエンド システム内の複数の異なるサービス ノードによって呼び出され、最終的なリクエスト結果が共同して生成されます。以前の各リクエストは、複雑な分散サービス呼び出しチェーンを形成します。高い遅延またはエラーが発生します。リンク内のどのリンクでも、最終的にリクエスト全体が失敗します。
- したがって、マイクロサービス アーキテクチャでは、呼び出されるリンクが増えるにつれて、サービス A から実行したステップ数、各ステップにかかる時間、リンク呼び出しの完了後に実行したステップ数を知る必要があります。多くのマイクロサービスが使用され、どのノードが渡されたか。
- 非常に大規模なシステム向けの分散リクエスト リンク追跡。これは、80 が 8001 を呼び出し、8001 が 8002 を呼び出すなど、非常に多くのマイクロサービス モジュールがある場合に使用する必要があり、リンクが形成されます。リンク内のリンクに障害が発生した場合、Sleuth を使用してリンクを追跡できます。障害のあるリンクを見つけます。 。
15.2 とは
-
https://github.com/spring-cloud/spring-cloud-sleuth
-
Spring Cloud Sleuth は完全なサービス追跡ソリューションを提供します
-
分散システムで追跡ソリューションを提供し、zipkin と互換性があります
-
sleuth は追跡を担当し、zipkin は表示を担当します。
16.3 解像度
- リンクデータを送信すると、Webページ形式で通話効果が表示されます。
16.2 リンク監視を設定する手順
16.2.1 ジップキン
1) ダウンロード
-
バージョン F 以降、SpringCloud では Zipkin Server サーバーを独自に構築する必要がなくなり、jar パッケージを呼び出すだけで済みます。
-
https://repo1.maven.org/maven2/io/zipkin/zipkin-server/
-
zipkin-server-2.24.3-exec.jar
2) ジャーを実行します
- 入力するコマンド
- 入力: java -jar zipkin-server-2.24.3-exec.jar
3) コンソールを実行します
-
http://localhost:9411/zipkin/
-
用語
- 完全な通話リンク
- リクエスト リンクを表します。リンクはトレース ID によって一意に識別され、スパンは開始されたリクエスト情報を識別します。各スパンは親 ID によって関連付けられます。
- リクエスト リンクを表します。リンクはトレース ID によって一意に識別され、スパンは開始されたリクエスト情報を識別します。各スパンは親 ID によって関連付けられます。
- 上の写真は何ですか
- リンクはトレース ID によって一意に識別され、スパンは開始された要求情報を識別し、各スパンは親 ID によって関連付けられます。
- リンク全体の依存関係は次のとおりです。
- リンクはトレース ID によって一意に識別され、スパンは開始された要求情報を識別し、各スパンは親 ID によって関連付けられます。
- 用語集
- トレース: ツリー構造に似た Span コレクション。一意の識別子を持つ通話リンクを表します。
- スパン: 呼び出しリンクのソースを示します。スパンは情報の要求であると一般に理解されています。
- 完全な通話リンク
16.2.2 サービスプロバイダー
1)クラウドプロバイダー支払い8001
- 新規プロジェクト作成の手間を考慮して、ここでは新規プロジェクトを作成せず、以前のプロジェクトをそのまま使用することにします。
2)ポム
- 依存関係を追加する
<!--包含了sleuth+zipkin-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>
3)YML
spring:
application:
#微服务名称,将此服务项目入住到注册中心,那么就需要给此项目取个名字
name: cloud-payment-service
zipkin:
base-url: http://localhost:9411 # zipkin 地址
sleuth:
sampler:
probability: 1 #采样率值介于0到1之间,1则表示全部采集(一般不为1,不然高并发性能会有影响)
4) ビジネスクラスのPaymentController
- 先ほど書いたコントロール層にテストメソッドを追加します。
@GetMapping("/payment/zipkin")
public String paymentZipkin() {
return "hi ,i'am paymentzipkin server fall back,welcome to atguigu,O(∩_∩)O哈哈~";
}
16.2.3 サービス利用者(呼び出し元)
1)クラウド消費者注文80
- 新規プロジェクト作成の手間を考慮して、ここでは新規プロジェクトを作成せず、以前のプロジェクトをそのまま使用することにします。
2)ポム
- この依存関係も導入します
<!-- 引入sleuth + zipkin -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>
3)YML
spring:
application:
name: cloud-order-service
zipkin:
base-url: http://localhost:9411 # zipkin 地址
sleuth:
sampler:
# 采样率值 介于0-1之间 ,1表示全部采集
probability: 1
4) ビジネスクラスのOrderController
- 先ほど書いたコントロール層にテストメソッドを追加します。
// ====================> zipkin+sleuth
@GetMapping("/consumer/payment/zipkin")
public String paymentZipkin() {
String result = restTemplate.getForObject("http://localhost:8001"+"/payment/zipkin/", String.class);
return result;
}
16.2.4 テスト
-
eureka7001/8001/80を順次起動
-
80 はテストのために 8001 を複数回呼び出します。
http://localhost/consumer/payment/zipkin
-
ブラウザを開いて、http://localhost:9411 にアクセスします。
-
次のインターフェースが表示されます
-
痕跡を見つける
-
依存関係を表示する
-