SpringCloud マイクロサービス アーキテクチャ --- 基本

1. マイクロサービスを理解する

1.1. サービスアーキテクチャの進化

1.1.1. モノリシックアーキテクチャ

モノリシック アーキテクチャ: ビジネスのすべての機能が 1 つのプロジェクトで開発され、展開用に 1 つのパッケージにパッケージ化されます。

ここに画像の説明を挿入

モノリシック アーキテクチャの長所と短所は次のとおりです。

アドバンテージ:

  • シンプルな構造
  • 導入コストが低い

欠点:

  • 高度な結合 (維持とアップグレードが困難)

1.1.2、分散アーキテクチャ

分散アーキテクチャ: システムはビジネス機能に応じて分割され、各ビジネス機能モジュールはサービスと呼ばれる独立したプロジェクトとして開発されます。

ここに画像の説明を挿入

分散アーキテクチャの長所と短所:

アドバンテージ:

  • サービス結合を減らす
  • サービスのアップグレードと拡張に貢献

欠点:

  • サービスコールの関係が複雑

分散アーキテクチャによりサービスの結合は軽減されますが、サービスを分割する際には考慮すべき問題がまだ多くあります。

  • サービス分割の粒度を定義するにはどうすればよいですか?
  • サービスクラスターアドレスを維持するにはどうすればよいですか?
  • サービス間のリモート呼び出しを実装するにはどうすればよいですか?
  • サービスの健全性ステータスをどのように認識するか?

人々は分散アーキテクチャを制約するための一連の効果的な標準を開発する必要があります。

1.1.3. マイクロサービス

マイクロサービスのアーキテクチャ上の特徴:

  • 単一の責任: マイクロサービス分割の粒度はより小さく、各サービスは固有のビジネス機能に対応するため、単一の責任を実現します。
  • 自律性: 独立したチーム、独立したテクノロジー、独立したデータ、独立した展開と配信
  • サービス指向: サービスは、言語やテクノロジーに依存しない、統一された標準インターフェイスを提供します。
  • 強力な分離: サービス コールは分離され、耐障害性があり、連鎖的な問題を回避するために機能が低下します。

ここに画像の説明を挿入

マイクロサービスの上記の特性は、実際に分散アーキテクチャの標準を設定し、サービス間の結合をさらに軽減し、サービスの独立性と柔軟性を提供します。高い凝集性と低い結合性を実現します。

したがって、マイクロサービスは、適切に設計されたアーキテクチャを備えた分散アーキテクチャ ソリューションと考えることができます

しかし、計画はどのように実行されるべきでしょうか? どのテクノロジースタックを選択すればよいでしょうか? 世界中のインターネット企業は、独自のマイクロサービス実装ソリューションを積極的に試しています。

中でもJava分野で最も注目を集めているのがSpring Cloudが提供するソリューションだ。

1.1.4. 概要

モノリシックアーキテクチャの特徴?

  • シンプルで便利、高度に結合されているが拡張性が低く、小規模なプロジェクトに適しています。例: 学生管理システム

分散アーキテクチャの特徴?

  • 疎結合で拡張性は良いが、構造が複雑で難しい。JD.com や Taobao などの大規模なインターネット プロジェクトに適しています

マイクロサービス: 優れた分散アーキテクチャ ソリューション

  • 利点: 分割の粒度が小さく、サービスの独立性が高く、結合度が低い
  • 短所: 構造が非常に複雑で、運用保守、監視、導入の難易度が高くなる
  • SpringCloud は、さまざまな優れたマイクロサービス機能コンポーネントを統合した、マイクロサービス アーキテクチャのワンストップ ソリューションです

1.2. マイクロサービス技術の比較

1.2.1. マイクロサービスの構造

マイクロサービス ソリューションを実装するには技術的なフレームワークが必要であり、世界中のインターネット企業が独自のマイクロサービス実装技術を積極的に試しています。中国で最もよく知られているのは SpringCloud と Alibaba の Dubbo です。

ここに画像の説明を挿入

1.2.2. マイクロサービスの比較

ここに画像の説明を挿入

ここに画像の説明を挿入

1.3、スプリングクラウド

SpringCloud は現在、中国で最も広く使用されているマイクロサービス フレームワークです。公式ウェブサイトのアドレス:https://spring.io/projects/spring-cloud。

SpringCloud は、さまざまなマイクロサービス機能コンポーネントを統合し、SpringBoot に基づいてこれらのコンポーネントの自動アセンブリを実現するため、すぐに使用できる優れたエクスペリエンスを提供します。

ここに画像の説明を挿入

2. マイクロサービスの分割とリモート呼び出し

2.1. サービス分割の原則

  • 異なるマイクロサービス、同じビジネスを繰り返し開発しない
  • マイクロサービス データは独立しており、他のマイクロサービスのデータベースにはアクセスしません
  • マイクロサービスは、他のマイクロサービスが呼び出すためのインターフェイスとしてビジネスを公開できます。

ここに画像の説明を挿入

2.2. サービス分割の例

Cloud-demo: 親プロジェクト、依存関係を管理する

  • order-service: 注文マイクロサービス、注文関連のビジネスを担当します。
  • user-service: ユーザー マイクロサービス。ユーザー関連のビジネスを担当します。

必須:

  • 注文マイクロサービスとユーザー マイクロサービスの両方に、互いに独立した独自のデータベースが必要です
  • 注文サービスとユーザー サービスの両方が、Restful インターフェイスを外部に公開します
  • オーダー サービスがユーザー情報をクエリする必要がある場合、ユーザー サービスの Restful インターフェイスのみを呼び出すことができ、ユーザー データベースをクエリすることはできません。

2.2.1. SQL ステートメントのインポート

2.2.2. デモプロジェクトのインポート

3. エウレカ登録センター

3.1、エウレカ原理

ここに画像の説明を挿入

消費者はサービスプロバイダーに関する具体的な情報をどのように入手すればよいでしょうか?

  • サービス提供者はサービス開始時に自身の情報をeurekaに登録します
  • エウレカはこの情報を保存します
  • 消費者はサービス名に従って eureka からプロバイダー情報を取得します

サービスプロバイダーが複数ある場合、消費者はどのように選択すればよいでしょうか?

  • サービスコンシューマは負荷分散アルゴリズムを使用してサービスリストからサービスを選択します

消費者はサービス提供者の健康状態をどのように認識しているのでしょうか?

  • サービス プロバイダーは、ヘルス ステータスを報告するために 30 秒ごとに EurekaServer にハートビート リクエストを送信します。
  • eurekaはレコードサービスリスト情報を更新し、異常なハートビートを削除します
  • 消費者は最新情報を入手できる

Eureka アーキテクチャには、2 種類のマイクロサービス ロールがあります。

  • EurekaServer: サーバー、登録センター

    • サービス情報を記録する
    • ハートビートモニタリング
  • EurekaClient: クライアント

    • プロバイダー: サービスプロバイダー (例: ユーザーサービス)

      • エウレカサーバーに自分の情報を登録する
      • 30 秒ごとにハートビートを EurekaServer に送信します
    • Consumer: サービス消費者 (例: order-service)

      • サービス名に従ってEurekaServerからサービスリストを取得します。

      • サービスリストに基づいて負荷分散を行い、マイクロサービスを選択した後にリモート呼び出しを開始します。

3.2. EurekaServerの構築

3.2.1. eureka-server サービスの作成

3.2.2. eureka 依存関係の導入

SpringCloud によって eureka に提供されるスターター依存関係を導入します。

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>

3.2.3、スタートアップクラスの書き込み

eureka-server サービスの起動クラスを作成するには、必ず @EnableEurekaServer アノテーションを追加して、eureka の登録センター機能を有効にしてください。

package cn.test.eureka;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

@SpringBootApplication
@EnableEurekaServer
public class EurekaApplication {
    
    
    public static void main(String[] args) {
    
    
        SpringApplication.run(EurekaApplication.class, args);
    }
}

3.2.4. 設定ファイルの書き込み

次の内容を含む application.yml ファイルを作成します。

server:
  port: 10086
spring:
  application:
    name: eureka-server
eureka:
  client:
    service-url: 
      defaultZone: http://127.0.0.1:10086/eureka

3.2.5. サービスの開始

マイクロサービスを開始し、ブラウザーでアクセスします: http://127.0.0.1:10086

次の結果が成功することを確認してください。

ここに画像の説明を挿入

3.3. サービス登録

3.3.1. 依存関係の導入

user-service の pom ファイルに、次の eureka-client 依存関係を導入します。

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

3.3.2. 設定ファイル

user-service で、application.yml ファイルを変更し、サービス名と eureka アドレスを追加します。

spring:
  application:
    name: userservice
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:10086/eureka

3.3.3. 複数のユーザーサービスインスタンスの開始

サービスに複数のインスタンスがあるシナリオを示すために、SpringBoot スタートアップ構成を追加し、ユーザー サービスを開始します。

3.4. サービスディスカバリ

3.4.1. 依存関係の導入

前に述べたように、サービス検出とサービス登録はすべて eureka-client 依存関係にカプセル化されているため、この手順はサービス登録と一致します。

order-service の pom ファイルに、次の eureka-client 依存関係を導入します。

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

3.4.2. 設定ファイル

サービス検出では、エウレカ アドレスも知る必要があるため、2 番目のステップはサービス登録と一致しており、エウレカ情報を構成します。

order-service で、application.yml ファイルを変更し、サービス名と eureka アドレスを追加します。

spring:
  application:
    name: orderservice
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:10086/eureka

3.4.3. サービスプルとロードバランシング

最後に、eureka-server から user-service サービスのインスタンス リストを取得し、負荷分散を実装します。

ただし、これらのアクションを実行する必要はなく、いくつかの注釈を追加するだけで済みます。

order-service の OrderApplication で、 @LoadBalanced アノテーションを RestTemplate Bean に追加します。

Spring は、サービス名 userservice に従って eureka-server 側からインスタンス リストを取得し、負荷分散を完了するのに自動的に役立ちます。

3.5. 概要

エウレカサーバーを構築する

  • eureka-server 依存関係を導入する

  • @EnableEurekaServer アノテーションを追加

  • application.ymlでeurekaアドレスを設定します。

サービス登録

  • eureka クライアント依存関係を導入する

  • application.ymlでeurekaアドレスを設定します。

サービスディスカバリ

  • eureka クライアント依存関係を導入する
  • application.ymlでeurekaアドレスを設定します。
  • @LoadBalanced アノテーションを RestTemplate に追加
  • サービスプロバイダーのサービス名によるリモート呼び出し

4. リボン負荷分散の原理

4.1. 負荷分散の原理

Spring Cloud の最下層は、実際にはリボンと呼ばれるコンポーネントを使用して負荷分散を実装します。

ここに画像の説明を挿入

4.2. ソースコードの追跡

サービス名を入力するだけでアクセスできるのはなぜですか? 事前に IP とポートを取得する必要もあります。

明らかに、誰かがサービス名に基づいてサービス インスタンスの IP とポートを取得するのを手伝ってくれました。つまりLoadBalancerInterceptor、このクラスは RestTemplate リクエストをインターセプトし、サービス ID に従って Eureka からサービス リストを取得し、負荷分散アルゴリズムを使用して実際のサービス アドレス情報を取得し、サービス ID を置き換えます。

ソースコードの追跡を行います。

4.2.1、LoadBalancerIntercepor

ここに画像の説明を挿入
ここでの intercept メソッドがユーザーの HttpRequest リクエストをインターセプトし、いくつかのことを実行することがわかります。

  • request.getURI(): リクエスト URI を取得します。この場合は http://user-service/user/8 です。
  • originalUri.getHost(): URI パスのホスト名を取得します。これは実際にはサービス ID です。user-service
  • this.loadBalancer.execute(): サービス ID とユーザーのリクエストを処理します。

こちらthis.loadBalancerLoadBalancerClientそのタイプで、引き続きフォローしていきます。

4.2.2、ロードバランサークライアント

引き続き実行メソッドに従います。

ここに画像の説明を挿入
コードは次のようなものです:

  • getLoadBalancer(serviceId): サービス ID に従って ILoadBalancer を取得します。ILoadBalancer はサービス ID を eureka に取り、サービス リストを取得して保存します。
  • getServer(loadBalancer): 組み込みの負荷分散アルゴリズムを使用して、サービス リストから 1 つを選択します。この例では、ポート 8082 上のサービスが取得されたことがわかります。

リリース後、再度アクセスしてトレースすると、取得した値が 8081 であることがわかりました。

ここに画像の説明を挿入

案の定、負荷分散は達成されています。

4.2.3、負荷分散戦略 IRule

先ほどのコードでは、アクセス サービスが負荷分散を行うメソッドを使用していることがわかりますgetServer

ここに画像の説明を挿入

私たちはフォローアップを続けます:
ここに画像の説明を挿入

ソース コードのchooseServer メソッドをトレースし続けると、次のようなコードが見つかりました。

ここに画像の説明を挿入

このルールが誰であるかを見てみましょう:
ここに画像の説明を挿入

ここでのルールのデフォルト値は RoundRobinRule です。クラスの紹介を参照してください。

ここに画像の説明を挿入
それが投票の意味ではないでしょうか。

この時点で、負荷分散プロセス全体が明らかになりました。

4.2.4. 概要

SpringCloudRibbon の最下層はインターセプターを使用して、RestTemplate によって送信されたリクエストをインターセプトし、アドレスを変更します。画像でまとめるとこうなります。

ここに画像の説明を挿入

基本的なプロセスは次のとおりです。

  • RestTemplate リクエストをインターセプト http://userservice/user/1
  • ibbonLoadBalancerClient は、リクエスト URL からサービス名を取得します。これは user-service です。
  • DynamicServerListLoadBalancer は、ユーザーサービスに従って eureka からサービスリストを取得します。
  • eureka はリスト、localhost:8081、localhost:8082 を返します。
  • IRule は組み込みの負荷分散ルールを使用します。リストから 1 つを選択します (localhost:8081 など)。
  • ibbonLoadBalancerClient はリクエスト アドレスを変更し、userservice を localhost:8081 に置き換え、http://localhost:8081/user/1 を取得して、実際のリクエストを開始します。

4.3. 負荷分散戦略

4.3.1、負荷分散戦略

負荷分散のルールは IRule インターフェイスで定義され、IRule にはさまざまな実装クラスがあります。

ここに画像の説明を挿入

さまざまなルールの意味は次のとおりです。

組み込みの負荷分散ルールクラス ルールの説明
ラウンドロビンルール サービスのリストをポーリングしてサーバーを選択するだけです。これは、リボンのデフォルトの負荷分散ルールです。
可用性フィルタリングルール 次の 2 つのサーバーは無視してください。 (1) デフォルトでは、このサーバーが 3 回接続に失敗すると、このサーバーは「短絡」状態に設定されます。短絡状態は 30 秒間続き、再び接続に失敗すると、短絡の継続時間は幾何級数的に増加します。(2) 同時実行性が高すぎるサーバー。サーバーの同時接続数が多すぎる場合、AvailabilityFilteringRule ルールで構成されたクライアントもそれを無視します。同時接続数の上限は、クライアントの ..ActiveConnectionsLimit プロパティによって構成できます。
WeightedResponseTimeRule 各サーバーに重み値を割り当てます。サーバーの応答時間が長いほど、このサーバーの重みは低くなります。このルールはサーバーをランダムに選択し、この重み値はサーバーの選択に影響します。
ゾーン回避ルール サーバーの選択は、その地域で利用可能なサーバーに基づいて行われます。ゾーンを使用してサーバーを分類します。このゾーンは、コンピューター室、ラックなどとして理解できます。次に、ゾーン内の複数のサービスをポーリングします。
BestAvailableルール 短絡しているサーバーを無視し、同時実行性の低いサーバーを選択します。
ランダムルール 利用可能なサーバーをランダムに選択します。
再試行ルール 再試行メカニズムの選択ロジック

デフォルトの実装は、ポーリング スキームである ZoneAvoidanceRule です。

4.3.2、カスタム負荷分散戦略

負荷分散ルールは、IRule 実装を定義することで変更できます。方法は 2 つあります。

  1. コード メソッド: order-service の OrderApplication クラスで、新しい IRule を定義します。
@Bean
public IRule randomRule(){
    
    
    return new RandomRule();
}
  1. 構成ファイルによる方法: order-service の application.yml ファイルで、新しい構成を追加すると、ルールを変更することもできます。
userservice: # 给某个微服务配置负载均衡规则,这里是userservice服务
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule # 负载均衡规则 

通常、デフォルトの負荷分散ルールは変更せずに使用されることに注意してください。

4.4. 遅延ロード

リボンはデフォルトで遅延読み込みを使用します。つまり、LoadBalanceClient は最初にアクセスされたときにのみ作成され、要求時間は非常に長くなります。

ハンガー ロードは、最初の訪問にかかる時間を短縮するために、プロジェクトの開始時に作成されます。次の構成を通じてハンガー ロードを有効にします。

ribbon:
  eager-load:
    enabled: true
    clients: userservice

4.5. 概要

リボンの負荷分散ルール

  • ルールインターフェイスはIRuleです

  • デフォルトの実装は ZoneAvoidanceRule で、ゾーンに従ってサービス リストを選択し、ポーリングします。

カスタム負荷分散方法

  • コード方式: 柔軟な構成ですが、変更時に再パッケージ化してリリースする必要があります

  • 構成方法: 直感的で便利、再パッケージ化して公開する必要はありませんが、グローバル構成は不可能です

飢えの負荷

  • スターベーションロードを有効にする

  • スターベーション ロード用のマイクロサービス名を指定します

5. ナコセ登録センター

5.1. Nacos の理解とインストール

5.1.1、Windowsのインストール

5.1.1.1. インストールパッケージのダウンロード

Nacos の GitHub ページには、コンパイルされた Nacos サーバーまたはソース コードをダウンロードするためのダウンロード リンクがあります。

GitHub ホームページ: https://github.com/alibaba/nacos

GitHub のリリース ダウンロード ページ: https://github.com/alibaba/nacos/releases

図に示すように:

ここに画像の説明を挿入

5.1.1.2、解凍

図に示すように、このパッケージを中国語以外のディレクトリに解凍します。

ここに画像の説明を挿入

ディレクトリの説明:

  • bin: 起動スクリプト
  • conf: 設定ファイル

5.1.1.3、ポート設定

Nacos のデフォルトのポートは 8848 です。コンピュータ上の他のプロセスがポート 8848 を占有している場合は、最初にプロセスを閉じてみてください。

ポート 8848 を占有しているプロセスを閉じることができない場合は、 nacos の conf ディレクトリに入り、構成ファイル内のポートを変更することもできます。

ここに画像の説明を挿入

5.1.1.4、開始

起動は非常に簡単で、bin ディレクトリに入ります。構造は次のとおりです。

ここに画像の説明を挿入

次に、次のコマンドを実行します。

  • Windowsコマンド:

    startup.cmd -m standalone
    

実行後の効果は以下の通りです。

ここに画像の説明を挿入

5.1.1.5. アクセス

ブラウザにアドレスを入力します: http://127.0.0.1:8848/nacos:

ここに画像の説明を挿入
次のように入力すると、デフォルトのアカウントとパスワードは両方とも nacos になります。

ここに画像の説明を挿入

5.1.2、Linuxのインストール

5.1.2.1、JDKのインストール

Nacos は JDK に依存して実行されるため、JDK をインデックス Linux にインストールする必要があります。

jdk インストール パッケージをアップロードします。

ディレクトリにアップロードします。例:/usr/local/

次に、解凍​​します。

tar -xvf jdk-8u144-linux-x64.tar.gz

次に名前をjavaに変更します

環境変数を構成します。

export JAVA_HOME=/usr/local/java
export PATH=$PATH:$JAVA_HOME/bin

環境変数を設定します。

source /etc/profile

5.1.2.2. インストールパッケージのアップロード

図に示すように:

ここに画像の説明を挿入

Linux サーバーのディレクトリ (たとえば、次の/usr/local/srcディレクトリの下) にアップロードします。

ここに画像の説明を挿入

5.1.2.3、解凍

インストールパッケージを解凍するコマンド:

tar -xvf nacos-server-1.4.1.tar.gz

次に、インストール パッケージを削除します。

rm -rf nacos-server-1.4.1.tar.gz

ディレクトリ内の最終的なスタイル:
ここに画像の説明を挿入

ディレクトリ内:
ここに画像の説明を挿入

5.1.2.4、ポート設定

窓と同じようなもの

5.1.2.5、開始

nacos/bin ディレクトリで、Nacos を起動するコマンドを入力します。

sh startup.sh -m standalone

5.2. Nacos クイックスタート

Nacos は SpringCloudAlibaba のコンポーネントであり、SpringCloudAlibaba も SpringCloud で定義されたサービス登録およびサービス検出の仕様に従います。したがって、マイクロサービスに Nacos を使用する場合と Eureka を使用する場合に大きな違いはありません。

主な違いは次のとおりです。

  • さまざまなものに依存します
  • サービスアドレスが異なります

5.2.1. 依存関係の導入

Cloud-demo 親プロジェクトの pom ファイル<dependencyManagement>に SpringCloudAlibaba の依存関係を導入します。

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-alibaba-dependencies</artifactId>
    <version>2.2.6.RELEASE</version>
    <type>pom</type>
    <scope>import</scope>
</dependency>

次に、user-service と order-service の pom ファイルに nacos-discovery 依存関係を導入します。

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

: eureka の依存関係をコメントアウトすることを忘れないでください。

5.2.2. nacos アドレスの設定

user-service と order-service の application.yml に nacos アドレスを追加します。

spring:
  cloud:
    nacos:
      server-addr: localhost:8848

: eureka のアドレスをコメントアウトすることを忘れないでください。

5.2.3、再起動

マイクロサービスを再起動した後、nacos 管理ページにログインすると、マイクロサービスの情報を確認できます。

ここに画像の説明を挿入

要約:

ナコスサービス構築

  • インストールパッケージをダウンロードする
  • 解凍する
  • bin ディレクトリでコマンドを実行します:startup.cmd -mstandalone

Nacos サービスの登録または検出

  • nacos.discovery 依存関係を導入する
  • nacos アドレス spring.cloud.nacos.server-addr を構成する

5.3、Nacos サービスの階層型ストレージ モデル

サービス複数のインスタンスを持つことができます (ユーザー サービスなど)。

  • 127.0.0.1:8081
  • 127.0.0.1:8082
  • 127.0.0.1:8083

たとえば、これらのインスタンスが全国のさまざまなコンピューター室に分散されている場合は、次のようになります。

  • 127.0.0.1:8081、上海コンピュータ室
  • 127.0.0.1:8082、上海コンピューター室
  • 127.0.0.1:8083、杭州コンピューター室

Nacos は、同じコンピュータ ルーム内のインスタンスを 1 つのクラスタに分割します。

つまり、ユーザー サービスはサービスです。サービスには、杭州や上海などの複数のクラスターを含めることができます。各クラスターには複数のインスタンスを含めることができ、図に示すように階層モデルを形成できます。

ここに画像の説明を挿入

マイクロサービスが相互にアクセスする場合は、ローカル アクセスの方が高速であるため、できる限り同じクラスター インスタンスにアクセスする必要があります。他のクラスターにアクセスできるのは、クラスターが使用できない場合のみです。例えば:

ここに画像の説明を挿入

杭州のコンピューター ルームのオーダー サービスは、同じコンピューター ルームのユーザー サービスへのアクセスを優先する必要があります。

要約:

Nacos サービスの階層型ストレージ モデル

  • 最初のレベルは userservice などのサービスです。
  • 2 番目のレベルは杭州や上海などのクラスターです。
  • 3 番目のレベルは、ユーザーサービスを展開する杭州のコンピューター室のサーバーなどのインスタンスです。

インスタンスのクラスタープロパティを設定する方法

  • application.yml ファイルを変更し、 spring.cloud.nacos.discovery.cluster-name プロパティを追加します。

5.3.1. ユーザーサービス用のクラスターの設定

user-service の application.yml ファイルを変更し、クラスター構成を追加します。

spring:
  cloud:
    nacos:
      server-addr: localhost:8848
      discovery:
        cluster-name: HZ # 集群名称

2 つのユーザー サービス インスタンスを再起動すると、nacos コンソールに次の結果が表示されます。
ここに画像の説明を挿入
ユーザー サービスの起動設定を再度コピーし、プロパティを追加します。

-Dserver.port=8083 -Dspring.cloud.nacos.discovery.cluster-name=SH

構成を次の図に示します。
ここに画像の説明を挿入

UserApplication3 を起動した後、nacos コンソールを再度確認します。
ここに画像の説明を挿入

5.3.2. 同じクラスター優先度でのロードバランシング

デフォルトでは、ZoneAvoidanceRule同じクラスターの優先順位に基づいて負荷分散を実現することはできません。

そこでNacosでは、NacosRule同一クラスタ内のインスタンスを優先的に選択できる実装を提供します。

1) order-service のクラスター情報を構成する

order-service の application.yml ファイルを変更し、クラスター構成を追加します。

spring:
  cloud:
    nacos:
      server-addr: localhost:8848
      discovery:
        cluster-name: HZ # 集群名称

2) 負荷分散ルールを変更する

order-service の application.yml ファイルを変更し、負荷分散ルールを変更します。

userservice:
  ribbon:
    NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule # 负载均衡规则 

NacosRule 負荷分散戦略

  • 同じクラスター内のサービス インスタンスのリストに優先順位を付ける
  • ローカル クラスターはプロバイダーを見つけることができないため、他のクラスターに移動してプロバイダーを探し、警告が報告されます。
  • 使用可能なインスタンスのリストを決定した後、ランダムな負荷分散を使用してインスタンスを選択します。

5.4. ウェイト設定

実際の展開では、次のようなシナリオが表示されます。

サーバー機器のパフォーマンスは異なります。パフォーマンスが優れているインスタンスもあれば、パフォーマンスが低いインスタンスもあります。パフォーマンスが高いマシンがより多くのユーザーのリクエストを処理できることを期待しています。

ただし、デフォルトでは、NacosRule はマシンのパフォーマンスを考慮せずに、同じクラスター内でランダムに選択されます。

そこでNacosではアクセス頻度を制御するためのウェイト設定を用意しており、ウェイトが大きいほどアクセス頻度が高くなります。

nacos コンソールで、ユーザー サービス インスタンスのリストを見つけて、[編集] をクリックすると、重みを変更できます。
ここに画像の説明を挿入
ポップアップ編集ウィンドウで、重みを変更します。
ここに画像の説明を挿入

: 重みが 0 に変更されると、インスタンスは決して訪問されなくなります。

5.5. Nacos 環境の隔離

Nacos は、環境分離を実装するための名前空間を提供します。

  • nacos には複数の名前空間が存在する可能性があります
  • 名前空間の下にグループ、サービスなどを含めることができます。
  • 異なる名前空間は相互に分離されます。たとえば、異なる名前空間内のサービスは相互に認識されません。

ここに画像の説明を挿入

5.5.1. ネームスペースの作成

デフォルトでは、すべてのサービス、データ、グループは public という名前の同じ名前空間にあります。

ここに画像の説明を挿入

ページ上の「追加」ボタンをクリックして名前空間を追加できます。

ここに画像の説明を挿入
次に、フォームに記入します。

ここに画像の説明を挿入

ページ上に新しい名前空間が表示されます。

ここに画像の説明を挿入

5.5.2. マイクロサービスの名前空間の設定

マイクロサービスの名前空間の構成は、構成を変更することによってのみ実現できます。

たとえば、order-service の application.yml ファイルを変更します。

spring:
  cloud:
    nacos:
      server-addr: localhost:8848
      discovery:
        cluster-name: HZ
        namespace: 492a7d5d-237b-46a1-a99a-fa8e98e4b0f9 # 命名空间,填ID

order-service を再起動した後、コンソールにアクセスすると、次の結果が表示されます。

ここに画像の説明を挿入
ここに画像の説明を挿入

この時点で、order-service にアクセスすると、名前空間が異なるため、userservice が見つからず、コンソールにエラーが報告されます。

ここに画像の説明を挿入

要約:

ナコス環境の隔離

  • 各名前空間には一意の ID があります
  • サービスが名前空間を設定するときは、名前の代わりに ID を書き込みます
  • 異なる名前空間にあるサービスは相互に認識されません

5.6 ナコスとエウレカの違い

Nacos サービス インスタンスは 2 つのタイプに分類されます。

  • 一時インスタンス: インスタンスが一定期間以上停止している場合、デフォルトのタイプであるサービス リストから削除されます。

  • 非一時インスタンス: インスタンスがダウンしてもサービス リストから削除されず、永続インスタンスと呼ぶこともできます。

サービス インスタンスを永続インスタンスとして構成します。

spring:
  cloud:
    nacos:
      discovery:
        ephemeral: false # 设置为非临时实例

Nacos と Eureka の全体的な構造は、サービス登録、サービス プル、ハートビート待機など似ていますが、いくつかの違いがあります。

ここに画像の説明を挿入

  • ナコスとエウレカの共通点

    • サービス登録とサービスプルの両方をサポートします
    • どちらもサービス プロバイダーの健全性検出のためのハートビート方式をサポートしています
  • ナコスとエウレカの違い

    • Nacos は、サーバーがプロバイダーのステータスをアクティブに検出することをサポートします。一時インスタンスはハートビート モードを採用し、非一時インスタンスはアクティブ検出モードを採用します。
    • 異常なハートビートのある一時的なインスタンスは削除されますが、一時的ではないインスタンスは削除されません
    • Nacos はサービス リスト変更のメッセージ プッシュ モードをサポートし、サービス リストはよりタイムリーに更新されます。
    • Nacos クラスターはデフォルトで AP モードを採用します。クラスター内に非一時インスタンスがある場合は CP モードが採用され、Eureka は AP モードを採用します。

6. Nacos 構成管理

6.1. 統合構成管理

デプロイされるマイクロサービスのインスタンスが数十、数百に達すると、マイクロサービスの構成を 1 つずつ変更すると、気が狂い、間違いが発生しやすくなります。すべてのインスタンスの構成を一元管理できる、統合された構成管理ソリューションが必要です。

ここに画像の説明を挿入
一方では、Nacos は構成を集中管理でき、他方では、構成が変更された場合、適時にマイクロサービスに通知して構成のホット アップデートを実現できます。

6.1.1. nacos に設定ファイルを追加する

nacos で構成を管理するにはどうすればよいですか?
ここに画像の説明を挿入

次に、ポップアップ フォームに構成情報を入力します。
ここに画像の説明を挿入

注: プロジェクトのコア構成は、ホット アップデート構成が必要な場合にのみ nacos によって管理する必要があります。変更されない一部の構成は、マイクロサービス内でローカルに保存することをお勧めします。

6.1.2. マイクロサービスから設定をプルする

プロジェクトの起動を完了するには、マイクロサービスは nacos で管理されている構成をプルし、ローカルの application.yml 構成とマージする必要があります。

しかし、application.yml がまだ読み込まれていない場合、nacos のアドレスはどうやってわかるのでしょうか?

したがって、Spring では新しい構成ファイル、bootstrap.yaml ファイルが導入され、application.yml の前に読み取られます。プロセスは次のとおりです。

ここに画像の説明を挿入

1) nacos-config 依存関係を導入する

まず、user-service サービスに nacos-config のクライアント依存関係を導入します。

<!--nacos配置管理依赖-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>

2) bootstrap.yaml を追加します。

次に、次の内容を含む bootstrap.yaml ファイルを user-service に追加します。

spring:
  application:
    name: userservice # 服务名称
  profiles:
    active: dev #开发环境,这里是dev 
  cloud:
    nacos:
      server-addr: localhost:8848 # Nacos地址
      config:
        file-extension: yaml # 文件后缀名

ここで、nacos アドレスは spring.cloud.nacos.server-addr に従って取得され、次に次に従って取得されます。

${spring.application.name}-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}ファイル ID として、構成を読み取ります。

この例では、次のようになりますuserservice-dev.yaml

ここに画像の説明を挿入

3) nacos 設定の読み取り

ビジネス ロジックを user-service の UserController に追加し、pattern.dateformat 構成を読み取ります。

ここに画像の説明を挿入

完全なコード:

@Slf4j
@RestController
@RequestMapping("/user")
public class UserController {
    
    

    @Autowired
    private UserService userService;

    @Value("${pattern.dateformat}")
    private String dateformat;
    
    @GetMapping("now")
    public String now(){
    
    
        return LocalDateTime.now().format(DateTimeFormatter.ofPattern(dateformat));
    }
    // ...略
}

ページにアクセスすると、次の効果がわかります。

ここに画像の説明を挿入

要約:

構成を Nacos 管理者に引き渡す手順

  • Nacos に設定ファイルを追加する
  • マイクロサービスに nacos 構成の依存関係を導入する
  • bootstrap.yml をマイクロサービスに追加し、nacos アドレス、現在の環境、サービス名、ファイル拡張子を構成します。これらは、プログラムの開始時に nacos からどのファイルを読み取るかを決定します。

6.2. 設定のホットアップデート

私たちの最終的な目標は、nacos の構成を変更して、マイクロサービスが再起動せずに構成を有効にできるようにすること、つまり構成のホット アップデートです。

構成のホット アップデートを実現するには、次の 2 つの方法を使用できます。

6.2.1. 方法 1

@Value によって挿入された変数が配置されているクラスにアノテーション @RefreshScope を追加します。

ここに画像の説明を挿入

6.2.2. 方法 2

@Value アノテーションの代わりに @ConfigurationProperties アノテーションを使用します。

user-service サービスで、patternern.dateformat プロパティを読み取るクラスを追加します。

@Component
@Data
@ConfigurationProperties(prefix = "pattern")
public class PatternProperties {
    
    
    private String dateformat;
}

UserController で @Value の代わりにこのクラスを使用します。

ここに画像の説明を挿入

完全なコード:

@Slf4j
@RestController
@RequestMapping("/user")
public class UserController {
    
    

    @Autowired
    private UserService userService;

    @Autowired
    private PatternProperties patternProperties;

    @GetMapping("now")
    public String now(){
    
    
        return LocalDateTime.now().format(DateTimeFormatter.ofPattern(patternProperties.getDateformat()));
    }

    // 略
}

要約:

Nacos 構成が変更された後、次の方法でマイクロサービスをホット アップデートできます。

  • @Value アノテーションを介して挿入され、 @RefreshScope と組み合わせて更新されます
  • @ConfigurationProperties を通じて挿入され、自動的に更新されます

予防:

  • すべての構成が構成センターに配置するのに適しているわけではないため、保守が面倒です

  • いくつかの主要なパラメータと実行時に調整する必要があるパラメータを nacos 構成センターに入れることをお勧めします。これらは通常カスタム構成です。

6.3、設定の共有

実際、マイクロサービスが開始されると、nacos に移動して複数の構成ファイルを読み取ります。次に例を示します。

  • [spring.application.name]-[spring.profiles.active].yaml例: userservice-dev.yaml

  • [spring.application.name].yaml、例: userservice.yaml

[spring.application.name].yaml環境を含まないため

ケースを通して構成共有をテストしてみましょう

6.3.1. 環境共有設定の追加

nacos に userservice.yaml ファイルを追加します。

ここに画像の説明を挿入

6.3.2. ユーザーサービスでの共有設定の読み取り

ユーザー サービス サービスで、新しく追加されたプロパティを読み取るように PatternProperties クラスを変更します。
ここに画像の説明を挿入

user-service サービスで、UserController を変更し、メソッドを追加します。
ここに画像の説明を挿入

6.3.3. 異なるプロファイルで 2 つの UserApplication を実行する

スタートアップ項目 UserApplication2 を変更し、そのプロファイル値を変更します。

このように、UserApplication(8081)で使用されるプロファイルはdev、UserApplication2(8082)で使用されるプロファイルはtestとなります。

UserApplication と UserApplication2 を起動します

http://localhost:8081/user/prop にアクセスすると、結果は次のようになります。
ここに画像の説明を挿入

http://localhost:8082/user/prop にアクセスすると、結果は次のようになります。
ここに画像の説明を挿入

開発環境とテスト環境の両方が属性 envSharedValue の値を読み取っていることがわかります。

6.3.4. 共有の優先順位の設定

nacos とサービスローカルが同時に同じ属性を持つ場合、優先度は高と低に分かれます
ここに画像の説明を挿入

デフォルトでマイクロサービスによって読み取られる構成ファイル:

  • [サービス名]-[spring.profile.active].yaml、デフォルト構成
  • [サービス名].yaml、複数環境共有

さまざまなマイクロサービスで共有される構成ファイル:

  • 共有構成によって指定される
  • extension-configs で指定

優先順位:

  • 環境設定 > サービス名.yaml > 拡張構成 > 拡張構成 > 共有構成 > ローカル構成

6.2. Nacos クラスターの構築

6.2.1. クラスタ構成図

公式の Nacos クラスター図:

ここに画像の説明を挿入

これには 3 つの nacos ノードと、ロード バランサー プロキシ 3 Nacos が含まれています。ここでロードバランサーはnginxを使用できます。

計画されているクラスター構造は次のとおりです。

ここに画像の説明を挿入

3 つの nacos ノードのアドレス:

ノード ip ポート
ナコス1 192.168.150.1 8845
ナコス2 192.168.150.1 8846
ナコス3 192.168.150.1 8847

6.2.2. クラスターの構築

クラスターを構築するための基本的な手順は次のとおりです。

  • データベースを構築し、データベーステーブル構造を初期化します。
  • nacos インストール パッケージをダウンロードする
  • nacosを設定する
  • nacos クラスターを開始する
  • nginxリバースプロキシ

6.2.2.1. データベースの初期化

Nacos のデフォルト データは、実稼働環境で利用可能なデータベースではない組み込みデータベース Derby に保存されます。

公式に推奨されるベスト プラクティスは、マスター/スレーブを備えた高可用性データベース クラスターを使用することです。ここでは、シングルポイント データベースを例として説明します。

まず新しいデータベースを作成し、nacos という名前を付けて、次の SQL をインポートします。

CREATE TABLE `config_info` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `data_id` varchar(255) NOT NULL COMMENT 'data_id',
  `group_id` varchar(255) DEFAULT NULL,
  `content` longtext NOT NULL COMMENT 'content',
  `md5` varchar(32) DEFAULT NULL COMMENT 'md5',
  `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
  `src_user` text COMMENT 'source user',
  `src_ip` varchar(50) DEFAULT NULL COMMENT 'source ip',
  `app_name` varchar(128) DEFAULT NULL,
  `tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段',
  `c_desc` varchar(256) DEFAULT NULL,
  `c_use` varchar(64) DEFAULT NULL,
  `effect` varchar(64) DEFAULT NULL,
  `type` varchar(64) DEFAULT NULL,
  `c_schema` text,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_configinfo_datagrouptenant` (`data_id`,`group_id`,`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_info';

/******************************************/
/*   数据库全名 = nacos_config   */
/*   表名称 = config_info_aggr   */
/******************************************/
CREATE TABLE `config_info_aggr` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `data_id` varchar(255) NOT NULL COMMENT 'data_id',
  `group_id` varchar(255) NOT NULL COMMENT 'group_id',
  `datum_id` varchar(255) NOT NULL COMMENT 'datum_id',
  `content` longtext NOT NULL COMMENT '内容',
  `gmt_modified` datetime NOT NULL COMMENT '修改时间',
  `app_name` varchar(128) DEFAULT NULL,
  `tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_configinfoaggr_datagrouptenantdatum` (`data_id`,`group_id`,`tenant_id`,`datum_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='增加租户字段';


/******************************************/
/*   数据库全名 = nacos_config   */
/*   表名称 = config_info_beta   */
/******************************************/
CREATE TABLE `config_info_beta` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `data_id` varchar(255) NOT NULL COMMENT 'data_id',
  `group_id` varchar(128) NOT NULL COMMENT 'group_id',
  `app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',
  `content` longtext NOT NULL COMMENT 'content',
  `beta_ips` varchar(1024) DEFAULT NULL COMMENT 'betaIps',
  `md5` varchar(32) DEFAULT NULL COMMENT 'md5',
  `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
  `src_user` text COMMENT 'source user',
  `src_ip` varchar(50) DEFAULT NULL COMMENT 'source ip',
  `tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_configinfobeta_datagrouptenant` (`data_id`,`group_id`,`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_info_beta';

/******************************************/
/*   数据库全名 = nacos_config   */
/*   表名称 = config_info_tag   */
/******************************************/
CREATE TABLE `config_info_tag` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `data_id` varchar(255) NOT NULL COMMENT 'data_id',
  `group_id` varchar(128) NOT NULL COMMENT 'group_id',
  `tenant_id` varchar(128) DEFAULT '' COMMENT 'tenant_id',
  `tag_id` varchar(128) NOT NULL COMMENT 'tag_id',
  `app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',
  `content` longtext NOT NULL COMMENT 'content',
  `md5` varchar(32) DEFAULT NULL COMMENT 'md5',
  `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
  `src_user` text COMMENT 'source user',
  `src_ip` varchar(50) DEFAULT NULL COMMENT 'source ip',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_configinfotag_datagrouptenanttag` (`data_id`,`group_id`,`tenant_id`,`tag_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_info_tag';

/******************************************/
/*   数据库全名 = nacos_config   */
/*   表名称 = config_tags_relation   */
/******************************************/
CREATE TABLE `config_tags_relation` (
  `id` bigint(20) NOT NULL COMMENT 'id',
  `tag_name` varchar(128) NOT NULL COMMENT 'tag_name',
  `tag_type` varchar(64) DEFAULT NULL COMMENT 'tag_type',
  `data_id` varchar(255) NOT NULL COMMENT 'data_id',
  `group_id` varchar(128) NOT NULL COMMENT 'group_id',
  `tenant_id` varchar(128) DEFAULT '' COMMENT 'tenant_id',
  `nid` bigint(20) NOT NULL AUTO_INCREMENT,
  PRIMARY KEY (`nid`),
  UNIQUE KEY `uk_configtagrelation_configidtag` (`id`,`tag_name`,`tag_type`),
  KEY `idx_tenant_id` (`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_tag_relation';

/******************************************/
/*   数据库全名 = nacos_config   */
/*   表名称 = group_capacity   */
/******************************************/
CREATE TABLE `group_capacity` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `group_id` varchar(128) NOT NULL DEFAULT '' COMMENT 'Group ID,空字符表示整个集群',
  `quota` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '配额,0表示使用默认值',
  `usage` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '使用量',
  `max_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个配置大小上限,单位为字节,0表示使用默认值',
  `max_aggr_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '聚合子配置最大个数,,0表示使用默认值',
  `max_aggr_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个聚合数据的子配置大小上限,单位为字节,0表示使用默认值',
  `max_history_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '最大变更历史数量',
  `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_group_id` (`group_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='集群、各Group容量信息表';

/******************************************/
/*   数据库全名 = nacos_config   */
/*   表名称 = his_config_info   */
/******************************************/
CREATE TABLE `his_config_info` (
  `id` bigint(64) unsigned NOT NULL,
  `nid` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `data_id` varchar(255) NOT NULL,
  `group_id` varchar(128) NOT NULL,
  `app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',
  `content` longtext NOT NULL,
  `md5` varchar(32) DEFAULT NULL,
  `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `src_user` text,
  `src_ip` varchar(50) DEFAULT NULL,
  `op_type` char(10) DEFAULT NULL,
  `tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段',
  PRIMARY KEY (`nid`),
  KEY `idx_gmt_create` (`gmt_create`),
  KEY `idx_gmt_modified` (`gmt_modified`),
  KEY `idx_did` (`data_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='多租户改造';


/******************************************/
/*   数据库全名 = nacos_config   */
/*   表名称 = tenant_capacity   */
/******************************************/
CREATE TABLE `tenant_capacity` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `tenant_id` varchar(128) NOT NULL DEFAULT '' COMMENT 'Tenant ID',
  `quota` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '配额,0表示使用默认值',
  `usage` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '使用量',
  `max_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个配置大小上限,单位为字节,0表示使用默认值',
  `max_aggr_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '聚合子配置最大个数',
  `max_aggr_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个聚合数据的子配置大小上限,单位为字节,0表示使用默认值',
  `max_history_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '最大变更历史数量',
  `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_tenant_id` (`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='租户容量信息表';


CREATE TABLE `tenant_info` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `kp` varchar(128) NOT NULL COMMENT 'kp',
  `tenant_id` varchar(128) default '' COMMENT 'tenant_id',
  `tenant_name` varchar(128) default '' COMMENT 'tenant_name',
  `tenant_desc` varchar(256) DEFAULT NULL COMMENT 'tenant_desc',
  `create_source` varchar(32) DEFAULT NULL COMMENT 'create_source',
  `gmt_create` bigint(20) NOT NULL COMMENT '创建时间',
  `gmt_modified` bigint(20) NOT NULL COMMENT '修改时间',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_tenant_info_kptenantid` (`kp`,`tenant_id`),
  KEY `idx_tenant_id` (`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='tenant_info';

CREATE TABLE `users` (
	`username` varchar(50) NOT NULL PRIMARY KEY,
	`password` varchar(500) NOT NULL,
	`enabled` boolean NOT NULL
);

CREATE TABLE `roles` (
	`username` varchar(50) NOT NULL,
	`role` varchar(50) NOT NULL,
	UNIQUE INDEX `idx_user_role` (`username` ASC, `role` ASC) USING BTREE
);

CREATE TABLE `permissions` (
    `role` varchar(50) NOT NULL,
    `resource` varchar(255) NOT NULL,
    `action` varchar(8) NOT NULL,
    UNIQUE INDEX `uk_role_permission` (`role`,`resource`,`action`) USING BTREE
);

INSERT INTO users (username, password, enabled) VALUES ('nacos', '$2a$10$EuWPZHzz32dJN7jexM34MOeYirDdFAZm2kuWj7VEOJhhZkDrxfvUu', TRUE);

INSERT INTO roles (username, role) VALUES ('nacos', 'ROLE_ADMIN');

6.2.2.2. nacosのダウンロード

nacos には GitHub にダウンロード アドレスがあります: https://github.com/alibaba/nacos/tags。任意のバージョンを選択してダウンロードできます。

6.2.2.3、Nacosの構成

図に示すように、このパッケージを中国語以外のディレクトリに解凍します。
ここに画像の説明を挿入

ディレクトリの説明:

  • bin: 起動スクリプト
  • conf: 設定ファイル

nacos の conf ディレクトリに入り、構成ファイルcluster.conf.exampleを変更し、名前をcluster.confに変更します。

次に、コンテンツを追加します。

127.0.0.1:8845
127.0.0.1.8846
127.0.0.1.8847

次に、application.properties ファイルを変更し、データベース構成を追加します。

spring.datasource.platform=mysql

db.num=1

db.url.0=jdbc:mysql://127.0.0.1:3306/nacos?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC
db.user.0=root
db.password.0=123

6.2.2.4、開始

nacos フォルダーを 3 回コピーし、nacos1、nacos2、nacos3 という名前を付けます。

次に、3 つのフォルダー内の application.properties をそれぞれ変更します。

ナコス1:

server.port=8845

ナコス2:

server.port=8846

ナコス3:

server.port=8847

次に、3 つの nacos ノードをそれぞれ起動します。

startup.cmd

6.2.2.5、nginxリバースプロキシ

nginx インストール パッケージを見つけて、中国語以外のディレクトリに抽出します。

conf/nginx.conf ファイルを変更します。構成は次のようになります。

upstream nacos-cluster {
    server 127.0.0.1:8845;
	server 127.0.0.1:8846;
	server 127.0.0.1:8847;
}

server {
    listen       80;
    server_name  localhost;

    location /nacos {
        proxy_pass http://nacos-cluster;
    }
}

次に、ブラウザで http://localhost/nacos にアクセスします。

コード内の application.yml ファイル構成は次のとおりです。

spring:
  cloud:
    nacos:
      server-addr: localhost:80 # Nacos地址

6.2.2.6. 最適化

  • 実際の導入では、リバースプロキシとして機能するnginxサーバーのドメイン名を設定する必要があります。これにより、後でサーバーを移行する場合にnacosクライアントの構成を変更する必要がありません。

  • Nacos の各ノードは、災害復旧と分離のために複数の異なるサーバーに展開する必要があります。

要約:

クラスターの構築手順:

  • MySQL クラスターを構築し、データベース テーブルを初期化する
  • nacosをダウンロードして解凍します。
  • クラスタ構成(ノード情報)、データベース構成の変更
  • 複数の nacos ノードを個別に起動する
  • nginxリバースプロキシ

セブン、リモート通話を装う

まず、RestTemplate を使用してリモート呼び出しを開始するために使用したコードを見てみましょう。
ここに画像の説明を挿入

以下の問題があります。

• コードの可読性が低く、一貫性のないプログラミング エクスペリエンス

• 複雑なパラメータを含む URL は保守が困難です

Feign は宣言型 http クライアントです。公式アドレス: https://github.com/OpenFeign/feign

その役割は、http リクエストの送信をエレガントに実装し、上記の問題を解決するのに役立ちます。

7.1、Feign が RestTemplate を置き換える

Fegin を使用する手順は次のとおりです。

7.1.1. 依存関係の導入

order-service サービスの pom ファイルに偽の依存関係を導入します。

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

7.1.2. 注釈の追加

order-service のスタートアップ クラスにアノテーションを追加して、Feign の機能を有効にします。

ここに画像の説明を挿入

7.1.3、Feign クライアントを作成する

次の内容を含む新しいインターフェイスを order-service に作成します。

@FeignClient("userservice")
public interface UserClient {
    
    
    @GetMapping("/user/{id}")
    User findById(@PathVariable("id") Long id);
}

このクライアントは主に SpringMVC アノテーションに基づいて、次のようなリモート呼び出し情報を宣言します。

  • サービス名: ユーザーサービス
  • リクエストメソッド:GET
  • リクエストパス: /user/{id}
  • リクエストパラメータ: 長い ID
  • 戻り値の型: ユーザー

このように、Feign は、RestTemplate を使用せずに http リクエストを送信するのに役立ちます。

7.1.4. テスト

order-service の OrderService クラスの queryOrderById メソッドを変更し、RestTemplate の代わりに Feign クライアントを使用します。

ここに画像の説明を挿入

よりエレガントに見えませんか。

7.1.5. 概要

Feign を使用する手順:

①依存関係を導入する

② @EnableFeignClients アノテーションを追加

③ FeignClientインターフェースを書く

④ RestTemplateの代わりにFeignClientに定義されたメソッドを使用する

7.2、カスタム構成

Feign は、次の表に示すように、多くのカスタム構成をサポートできます。

タイプ 効果 説明する
偽りのロガーレベル ログレベルの変更 4 つの異なるレベルが含まれます: NONE、BASIC、HEADERS、FULL
feign.codec.Decoder 応答結果のパーサー json 文字列を Java オブジェクトに解析するなど、http リモート呼び出しの結果を解析します。
feign.codec.Encoder リクエストパラメータのエンコーディング http リクエスト経由で送信するためのリクエスト パラメータをエンコードする
ふりをする。契約 サポートされている注釈形式 デフォルトはSpringMVCのアノテーションです
ふりをする。リトライアー 失敗時の再試行メカニズム リクエスト失敗時の再試行メカニズム。デフォルトは「いいえ」ですが、リボンの再試行が使用されます。

通常はデフォルト値で十分ですが、カスタマイズする場合は、カスタム @Bean を作成してデフォルト Bean をオーバーライドするだけです。

以下では、例としてログを使用して、構成をカスタマイズする方法を示します。

7.2.1. 設定ファイル方式

構成ファイルに基づいて feign のログ レベルを変更すると、単一のサービスを対象にすることができます。

feign:  
  client:
    config: 
      userservice: # 针对某个微服务的配置
        loggerLevel: FULL #  日志级别 

すべてのサービスをターゲットにすることもできます。

feign:  
  client:
    config: 
      default: # 这里用default就是全局配置,如果是写服务名称,则是针对某个微服务的配置
        loggerLevel: FULL #  日志级别 

ログレベルは次の 4 種類に分類されます。

  • NONE: ログ情報を記録しません。これがデフォルト値です。
  • BASIC: リクエストメソッド、URL、レスポンスステータスコード、実行時間のみをログに記録します。
  • HEADERS: BASICをベースに、リクエストとレスポンスのヘッダ情報を追加記録します。
  • FULL: ヘッダー情報、リクエスト本文、メタデータを含む、すべてのリクエストとレスポンスの詳細を記録します。

7.2.2、Javaコードメソッド

Java コードに基づいてログ レベルを変更することもできます。最初にクラスを宣言し、次に Logger.Level オブジェクトを宣言します。

public class DefaultFeignConfiguration  {
    
    
    @Bean
    public Logger.Level feignLogLevel(){
    
    
        return Logger.Level.BASIC; // 日志级别为BASIC
    }
}

グローバルに有効にしたい場合は、スタートアップ クラスの @EnableFeignClients アノテーションに追加します。

@EnableFeignClients(defaultConfiguration = DefaultFeignConfiguration .class) 

ローカルで有効な場合は、対応する @FeignClient アノテーションに入れます。

@FeignClient(value = "userservice", configuration = DefaultFeignConfiguration .class) 

要約:

Feign のログ構成:

  • 1 つ目の方法は、feign.client.config.xxx.loggerLevel ファイルを構成することです。

    • xxx がデフォルトの場合、グローバルを意味します
    • xxx が userservice などのサービス名である場合、サービスを表します。
  • 2 番目の方法は、Java コードで Logger.Level Bean を構成することです。

    • @EnableFeignClients アノテーションで宣言されている場合、グローバルを表します。
    • @FeignClient アノテーションで宣言されている場合、サービスを表します。

7.3、偽の使用の最適化

Feign の最下層は http リクエストを開始し、他のフレームワークに依存します。その基礎となるクライアント実装には次のものが含まれます。

  • URLConnection: デフォルトの実装、接続プーリングをサポートしません

  • Apache HttpClient: 接続プールのサポート

  • OKHttp: 接続プールのサポート

したがって、Feign のパフォーマンスの最適化には主に以下が含まれます。

  • デフォルトの URLConnection の代わりに接続プールを使用する
  • ログレベル、できれば基本またはなし

ここでは、Apache の HttpClient を使用してデモンストレーションします。

7.3.1. 依存関係の導入

order-service の pom ファイルに Apache の HttpClient 依存関係を導入します。

<!--httpClient的依赖 -->
<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-httpclient</artifactId>
</dependency>

7.3.2、接続プールの構成

order-service の application.yml に設定を追加します。

feign:
  client:
    config:
      default: # default全局的配置
        loggerLevel: BASIC # 日志级别,BASIC就是基本的请求和响应信息
  httpclient:
    enabled: true # 开启feign对HttpClient的支持
    max-connections: 200 # 最大的连接数
    max-connections-per-route: 50 # 每个路径的最大连接数

要約する

  • ログレベルとしてベーシックを使用してみてください

  • URLConnection の代わりに HttpClient または OKHttp を使用してください

    • feign-httpClient 依存関係を導入する

    • 構成ファイルは httpClient 機能を有効にし、接続プールのパラメータを設定します。

7.4. ベストプラクティス

いわゆる最近の実践とは、使用プロセス中に要約された経験、つまりそれを使用する最良の方法を指します。

自己調査によると、Feign のクライアントはサービス プロバイダーのコントローラー コードと非常によく似ていることがわかりました。

偽のクライアント:

ここに画像の説明を挿入

ユーザーコントローラー:

ここに画像の説明を挿入

この繰り返しのコーディングを簡素化する方法はあるでしょうか?

7.4.1. 継承方法

同じコードは継承を通じて共有できます。

1) API インターフェースを定義し、定義メソッドを使用し、SpringMVC アノテーションに基づいてステートメントを作成します。

2) Feign クライアントとコントローラーの両方がインターフェースを統合します
ここに画像の説明を挿入

アドバンテージ:

  • 単純
  • コードシェア

欠点:

  • サービスプロバイダーとサービスコンシューマーは密接に結合されています

  • パラメータリストのアノテーションマッピングは継承されないため、メソッド、パラメータリスト、アノテーションをコントローラで再度宣言する必要があります。

7.4.2. 抽出方法

Feign の Client を独立したモジュールとして抽出し、インターフェイスに関連する POJO とデフォルトの Feign 設定をこのモジュールに組み込み、すべてのコンシューマに提供します。

たとえば、UserClient、User、および Feign のデフォルト構成はすべて feign-api パッケージに抽出され、この依存関係パッケージを参照することですべてのマイクロサービスを直接使用できます。

ここに画像の説明を挿入

要約:

Feign のベスト プラクティス:

  • コントローラーと FeignClient に同じインターフェイスを継承させる
  • すべてのコンシューマーが使用できるように、FeignClient、POJO、および Feign のデフォルト構成を 1 つのプロジェクトに定義します。

7.4.3. 抽出ベースのベストプラクティスの実装

7.4.3.1. 抽出

まず、feign-api という名前のモジュールを作成します。

feign-api で、feign のスターター依存関係を導入します。

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

次に、order-service に記述された UserClient、User、DefaultFeignConfiguration がすべて feign-api プロジェクトにコピーされます

7.4.3.2. order-service での feign-api の使用

まず、order-service 内の UserClient、User、DefaultFeignConfiguration などのクラスまたはインターフェイスを削除します。

order-service の pom ファイルに feign-api の依存関係を導入します。

<dependency>
    <groupId>cn.test.demo</groupId>
    <artifactId>feign-api</artifactId>
    <version>1.0</version>
</dependency>

order-service の上記 3 つのコンポーネントに関連するパッケージのインポート部分をすべて変更し、feign-api でパッケージをインポートするように変更します。

7.4.3.3、テストの再開

再起動後、サービスがエラーを報告したことが判明しました。

これは、UserClient が cn.test.feign.clients パッケージの下にあるためです。

order-service の @EnableFeignClients アノテーションは、同じパッケージ内ではなく cn.test.order パッケージの下にあるため、UserClient をスキャンできません。

7.4.3.4、スキャンパッケージの問題を解決する

方法 1:

Feign がスキャンする必要があるパッケージを指定します。

@EnableFeignClients(basePackages = "cn.test.feign.clients")

方法 2:

ロードする必要があるクライアント インターフェイスを指定します。

@EnableFeignClients(clients = {
    
    UserClient.class})

異なるパッケージの FeignClient をインポートするには 2 つの方法があります。

  • @EnableFeignClients アノテーションにbasePackagesを追加して、FeignClientが配置されているパッケージを指定します
  • @EnableFeignClients アノテーションにクライアントを追加して、特定の FeignClient のバイトコードを指定します

要約:

ベスト プラクティス方法 2 を実装する手順は次のとおりです。

  • まず feign-api という名前のモジュールを作成し、次に feign のスターター依存関係を導入します。
  • order-service に記述された UserClient、User、DefaultFeignConfiguration を feign-api プロジェクトにコピーします
  • order-service に feign-api の依存関係を導入する
  • order-service の上記 3 つのコンポーネントに関連するインポート部分をすべて変更し、feign-api でパッケージをインポートするように変更します。
  • テストを再開する

8. ゲートウェイサービス ゲートウェイ

Spring Cloud Gateway は、Spring 5.0、Spring Boot 2.0、Project Reactor などのリアクティブ プログラミングやイベント フロー技術をベースに開発された Spring Cloud の新しいプロジェクトで、シンプルかつ効果的な統合 API ルート管理手法を提供することを目的としています。

8.1. ゲートウェイが必要な理由

ゲートウェイはサービスの門番であり、すべてのマイクロサービスの統一された入り口です。

ゲートウェイの中核となる機能特性は次のとおりです

  • リクエストルーティング
  • アクセス制御
  • 制限する

アーキテクチャ図:

[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-jD806LhV-1681478872549)(assets/image-20210714210131152.png)]

アクセス制御: マイクロサービスのエントリ ポイントとして、ゲートウェイはユーザーがリクエストに適格かどうかを確認し、適格でない場合はリクエストをインターセプトする必要があります。

ルーティングと負荷分散: すべてのリクエストは最初にゲートウェイを通過する必要がありますが、ゲートウェイはビジネスを処理せず、特定のルールに従ってリクエストをマイクロサービスに転送します。このプロセスはルーティングと呼ばれます。もちろん、ルーティング対象のサービスが複数ある場合には、負荷分散も必要になります。

電流制限: リクエスト トラフィックが多すぎる場合、ゲートウェイは、過度のサービス プレッシャーを避けるために、ダウンストリーム マイクロサービスが受け入れることができる速度に従ってリクエストを解放します。

Spring Cloud には 2 種類のゲートウェイ実装があります。

  • ゲートウェイ
  • ズル

Zuul はサーブレットベースの実装であり、ブロッキング プログラミングに属します。Spring Cloud Gateway は Spring 5 で提供される WebFlux をベースにしており、応答性の高いプログラミングの実装であり、パフォーマンスが向上しています。

要約:

ゲートウェイの役割:

  • ユーザー要求に対して ID 認証と権限検証を実行する
  • ユーザーリクエストをマイクロサービスにルーティングし、負荷分散を実装する
  • ユーザーリクエストを制限する

8.2、ゲートウェイのクイックスタート

次に、ゲートウェイの基本的なルーティング機能を説明します。基本的な手順は次のとおりです。

  1. SpringBoot プロジェクト ゲートウェイを作成し、ゲートウェイの依存関係を導入する
  2. スタートアップクラスを書く
  3. 基本的な構成とルーティング ルールを作成する
  4. テスト用のゲートウェイ サービスを開始する

8.2.1. ゲートウェイサービスの作成と依存関係の導入

サービスを作成し、依存関係を導入します。

<!--网关-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!--nacos服务发现依赖-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

8.2.2. スタートアップクラスの書き込み

@SpringBootApplication
public class GatewayApplication {
    
    

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

8.2.3. 基本的な設定とルーティングルールを記述する

次の内容を含む application.yml ファイルを作成します。

server:
  port: 10010 # 网关端口
spring:
  application:
    name: gateway # 服务名称
  cloud:
    nacos:
      server-addr: localhost:8848 # nacos地址
    gateway:
      routes: # 网关路由配置
        - id: user-service # 路由id,自定义,只要唯一即可
          # uri: http://127.0.0.1:8081 # 路由的目标地址 http就是固定地址
          uri: lb://userservice # 路由的目标地址 lb就是负载均衡,后面跟服务名称
          predicates: # 路由断言,也就是判断请求是否符合路由规则的条件
            - Path=/user/** # 这个是按照路径匹配,只要以/user/开头就符合要求

Pathルールに一致するすべてのリクエストを、uriパラメーターで指定されたアドレスにプロキシします。

/user/**この例では、最初のリクエストをプロキシし、 lb://userservicelb はロード バランシングであり、サービス名に従ってサービス リストをプルし、ロード バランシングを実現します。

8.2.4、テストの再開

ゲートウェイを再起動します。 http://localhost:10010/user/1 にアクセスすると、ルールに準拠し/user/**、リクエストが uri: http://userservice/user/1 に転送され、結果が得られます。

8.2.5. ゲートウェイルーティングのフローチャート

アクセスプロセス全体は次のとおりです。

ここに画像の説明を挿入

要約:

ゲートウェイの構築手順:

  1. プロジェクトを作成し、nacos サービスの検出とゲートウェイの依存関係を導入します。

  2. 基本的なサービス情報、nacos アドレス、ルーティングを含む application.yml を構成します。

ルーティング設定には次のものが含まれます。

  1. ルート ID: ルートの一意の識別子

  2. ルーティング宛先 (uri): ルーティングの宛先アドレス、http は固定アドレスを表し、lb はサービス名に基づく負荷分散を表します。

  3. ルーティングアサーション(述語):ルーティングを判断するためのルール、

  4. ルート フィルター (フィルター): リクエストまたはレスポンスを処理します。

8.3. アサーションファクトリー

ゲートウェイルートで設定できる内容は次のとおりです。

  • ルート ID: ルートの一意の識別子
  • uri: ルーティング先、lb と http の両方をサポート
  • 述語: ルーティング アサーション。リクエストが要件を満たしているかどうかを判断します。要件を満たしている場合、リクエストはルーティング先に転送されます。
  • フィルタ: ルーティング フィルタ、リクエストまたは応答の処理

設定ファイルに記述するアサーション ルールは単なる文字列であり、Predicate Factory によって読み取られて処理され、ルーティング判断の条件に変換されます。

たとえば、Path=/user/** はパスに従って照合されます。このルールは次のように決定されます。

org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactoryクラスへ

処理のために、Spring Cloud Gateway には次のようなアサーション ファクトリが十数個あります。

名前 説明する
ある時点以降のリクエストです - 後=2037-01-20T17:42:47.789-07:00[アメリカ/デンバー]
ある時点より前のリクエストです - Before=2031-04-13T15:14:47.433+08:00[アジア/上海]
特定の 2 時点より前のリクエストです - 間=2037-01-20T17:42:47.789-07:00[アメリカ/デンバー]、2037-01-21T17:42:47.789-07:00[アメリカ/デンバー]
クッキー リクエストには特定の Cookie が含まれている必要があります - クッキー=チョコレート、ch.p
ヘッダ リクエストには特定のヘッダーが含まれている必要があります - ヘッダー=X-リクエストID、\d+
ホスト リクエストは特定のホスト (ドメイン名) にアクセスするものでなければなりません - ホスト= .somehost.org、 .anotherhost.org
方法 リクエストメソッドを指定する必要があります - メソッド=GET,POST
リクエストのパスは指定されたルールに準拠する必要があります - パス=/red/{セグメント}、/blue/**
クエリ リクエストパラメータには指定されたパラメータが含まれている必要があります - クエリ=名前、ジャック、または - クエリ=名前
リモートアドレス リクエスタの IP は指定された範囲内にある必要があります - RemoteAddr=192.168.1.1/24
重さ 重み付け処理

Path のルーティング エンジニアリングをマスターするだけで済みます。

8.4. フィルターファクトリー

GatewayFilter はゲートウェイに提供されるフィルターで、ゲートウェイに入るリクエストとマイクロサービスから返される応答を処理できます。

ここに画像の説明を挿入

8.4.1. ルーティングフィルターの種類

Spring は 31 の異なるルート フィルター ファクトリを提供します。例えば:

名前 説明する
リクエストヘッダーの追加 現在のリクエストにリクエストヘッダーを追加します
リクエストヘッダーの削除 リクエストからリクエストヘッダーを削除します
応答ヘッダーの追加 応答結果に応答ヘッダーを追加します。
レスポンスヘッダーの削除 応答結果から削除された応答ヘッダーがあります
リクエストレートリミッター リクエストの量を制限する

8.4.2. リクエストヘッダーフィルター

AddRequestHeader を例に挙げて説明します。

要件: userservice に入るすべてのリクエストにリクエスト ヘッダーを追加します。Truth=test は本当に素晴らしいです!

ゲートウェイ サービスの application.yml ファイルを変更し、ルート フィルタリングを追加するだけです。

spring:
  cloud:
    gateway:
      routes:
      - id: user-service 
        uri: lb://userservice 
        predicates: 
        - Path=/user/** 
        filters: # 过滤器
        - AddRequestHeader=Truth, test is freaking awesome! # 添加请求头

現在のフィルターは userservice ルートの下に書き込まれるため、userservice にアクセスするリクエストに対してのみ有効です。

8.4.3、デフォルトのフィルタ

すべてのルートに有効にしたい場合は、デフォルトでフィルター ファクトリを記述できます。形式は次のとおりです。

spring:
  cloud:
    gateway:
      routes:
      - id: user-service 
        uri: lb://userservice 
        predicates: 
        - Path=/user/**
      default-filters: # 默认过滤项
      - AddRequestHeader=Truth, test is freaking awesome! 

8.4.4 概要

フィルターの役割は何ですか?

① リクエストヘッダーの追加など、ルーティングリクエストまたはレスポンスを処理します。

② ルートの下に設定されたフィルタは、現在のルートのリクエストに対してのみ有効です

defaultFilters の役割は何ですか?

①全経路に有効なフィルタ

8.5. グローバルフィルター

上次学习的过滤器,网关提供了31种,但每一种过滤器的作用都是固定的。如果我们希望拦截请求,做自己的业务逻辑则没办法实现。

8.5.1、全局过滤器作用

全局过滤器的作用也是处理一切进入网关的请求和微服务响应,与GatewayFilter的作用一样。区别在于GatewayFilter通过配置定义,处理逻辑是固定的;而GlobalFilter的逻辑需要自己写代码实现。

定义方式是实现GlobalFilter接口。

public interface GlobalFilter {
    
    
    /**
     *  处理当前请求,有必要的话通过{@link GatewayFilterChain}将请求交给下一个过滤器处理
     *
     * @param exchange 请求上下文,里面可以获取Request、Response等信息
     * @param chain 用来把请求委托给下一个过滤器 
     * @return {@code Mono<Void>} 返回标示当前过滤器业务结束
     */
    Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain);
}

在filter中编写自定义逻辑,可以实现下列功能:

  • 登录状态判断
  • 权限校验
  • 请求限流等

8.5.2、自定义全局过滤器

需求:定义全局过滤器,拦截请求,判断请求的参数是否满足下面条件:

  • 参数中是否有authorization,

  • authorization参数值是否为admin

如果同时满足则放行,否则拦截

实现:

在gateway中定义一个过滤器:

@Order(-1)
@Component
public class AuthorizeFilter implements GlobalFilter {
    
    
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    
    
        // 1.获取请求参数
        MultiValueMap<String, String> params = exchange.getRequest().getQueryParams();
        // 2.获取authorization参数
        String auth = params.getFirst("authorization");
        // 3.校验
        if ("admin".equals(auth)) {
    
    
            // 放行
            return chain.filter(exchange);
        }
        // 4.拦截
        // 4.1.禁止访问,设置状态码
        exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
        // 4.2.结束处理
        return exchange.getResponse().setComplete();
    }
}

全局过滤器的作用是什么?

  • 对所有路由都生效的过滤器,并且可以自定义处理逻辑

实现全局过滤器的步骤?

  • 实现GlobalFilter接口
  • 添加@Order注解或实现Ordered接口
  • 编写处理逻辑

8.5.3、过滤器执行顺序

请求进入网关会碰到三类过滤器:当前路由的过滤器、DefaultFilter、GlobalFilter

请求路由后,会将当前路由过滤器和DefaultFilter、GlobalFilter,合并到一个过滤器链(集合)中,排序后依次执行每个过滤器:

ここに画像の説明を挿入

排序的规则是什么呢?

  • 每一个过滤器都必须指定一个int类型的order值,order值越小,优先级越高,执行顺序越靠前
  • GlobalFilter通过实现Ordered接口,或者添加@Order注解来指定order值,由我们自己指定
  • 路由过滤器和defaultFilter的order由Spring指定,默认是按照声明顺序从1递增。
  • 当过滤器的order值一样时,会按照 defaultFilter > 路由过滤器 > GlobalFilter的顺序执行。

詳細については、ソース コードを参照してください。

org.springframework.cloud.gateway.route.RouteDefinitionRouteLocator#getFilters()方法としては、まずdefaultFiltersをロードし、次に特定のルートのフィルタをロードしてマージします。

org.springframework.cloud.gateway.handler.FilteringWebHandler#handle()このメソッドはグローバル フィルターをロードし、前のフィルターとマージした後の順序に従って並べ替え、フィルター チェーンを編成します。

概要:
ルーティング フィルター、defaultFilter、グローバル フィルターの実行順序は?

  • 注文値が小さいほど優先度が高くなります
  • 順序値が同じ場合、順序は最初にdefaultFilter、次にローカルルーティングフィルタ、最後にグローバルフィルタになります。

8.6. クロスドメインの問題

8.6.1. クロスドメイン問題とは

クロスドメイン: 一貫性のないドメイン名はクロスドメインであり、主に次のようなものがあります。

  • 異なるドメイン名: www.taabao.com、www.taabao.org、www.jd.com、miaosha.jd.com

  • 同じドメイン名、異なるポート: localhost:8080 と localhost8081

クロスドメインの問題: ブラウザーは、リクエストの発信者がサーバーに対してクロスドメイン Ajax リクエストを行うことを禁止しており、リクエストはブラウザーによって傍受されます。

解決策: CORS、これは以前に学習したはずなので、ここでは繰り返しません。知らない友達はhttps://www.ruanyifeng.com/blog/2016/04/cors.htmlをチェックしてください。

8.6.2. クロスドメイン問題のシミュレーション

localhost:8090 から localhost:10010 にアクセスすると、ポートが異なります。これは明らかにクロスドメイン要求です。

8.6.3. クロスドメインの問題を解決する

ゲートウェイ サービスの application.yml ファイルに、次の構成を追加します。

spring:
  cloud:
    gateway:
      # 。。。
      globalcors: # 全局的跨域处理
        add-to-simple-url-handler-mapping: true # 解决options请求被拦截问题
        corsConfigurations:
          '[/**]':
            allowedOrigins: # 允许哪些网站的跨域请求 
              - "http://localhost:8090"
            allowedMethods: # 允许的跨域ajax的请求方式
              - "GET"
              - "POST"
              - "DELETE"
              - "PUT"
              - "OPTIONS"
            allowedHeaders: "*" # 允许在请求中携带的头信息
            allowCredentials: true # 是否允许携带cookie
            maxAge: 360000 # 这次跨域检测的有效期

8.7. 制限フィルター

電流制限: リクエストが多すぎることによるサーバーの過負荷やダウンタイムを避けるために、アプリケーション サーバーのリクエストを制限します。一般的な電流制限アルゴリズムは 2 つあります。

  • カウンタ アルゴリズム(ウィンドウ カウンタ アルゴリズム、スライディング ウィンドウ カウンタ アルゴリズムを含む)
  • 漏れやすいバケツ
  • トークンバケットアルゴリズム(トークンバケット)

ここに画像の説明を挿入

ここに画像の説明を挿入

ここに画像の説明を挿入

おすすめ

転載: blog.csdn.net/shuai_h/article/details/130140455