5. Eurekaサービスの登録と検出
5.1 概要図
5.2 エウレカの基礎知識
- 質問: なぜサービス登録センターを使用する必要があるのですか? 80 コンシューマを使用して 8081 ジェネレータを直接呼び出すことはできないのですか? ? ?
- 回答: 単一のコンシューマを呼び出す場合は問題ありませんが、コンシューマが多数ある場合は統一して管理する必要があります。
- 例: 患者は途中で外来診療所に登録することなく、マンツーマンの専門家サービスを受けるために私立病院に通います。患者が多い場合でも、このマイクロサービスは提供できますか? この専門家はまだアカウントを持っていますか? 今日、何人の患者がこの専門家アカウントを通過しましたか? 許可フロー制御などを監視する必要があります。この時点で、病院は次のことを行う必要があります。サービスとしての外来患者登録簿を持っています。
5.2.1 サービスガバナンスとは何ですか
-
Spring Cloud は、Netflix が開発した Eureka モジュールをカプセル化し、サービス ガバナンスを実装します。
-
従来の RPC リモート呼び出しフレームワークでは、各サービス間の依存関係の管理と管理がより複雑であるため、サービス呼び出し、負荷分散、フォールト トレランスなどを実現するサービス間の依存関係を管理するサービス ガバナンスが必要です。 .、サービスの発見と登録を実現します。
5.2.2 サービス登録とは
-
エウレカはCS設計アーキテクチャを採用しており、サービス登録機能のサーバーとなるエウレカサーバーがサービス登録センターとなります。システム内の他のマイクロサービスは、Eureka クライアントを使用して Eureka Server に接続し、ハートビート接続を維持します。このようにして、システム保守担当者はEureka Server を使用して、システム内の各マイクロサービスが正常に実行されているかどうかを監視できます。
-
サービスの登録と検出には、登録センターがあります。サーバーが起動すると、サービスアドレス、通信アドレスなどの現在のサーバー情報がエイリアス方式で登録センターに登録されます。相手側 (コンシューマ サービス プロバイダー) は、エイリアスを使用して登録センターから実際のサービス通信アドレスを取得し、ローカル RPC 呼び出しを実装します。RPC リモート呼び出しフレームワークの中心的な設計思想は、登録センターにあります。登録センターにより管理される 各サービス間の依存関係(サービスガバナンスの概念)どの RPC リモート フレームワークにも、サービス アドレス関連情報 (インターフェイス アドレス) を保存する登録センターがあります。
5.2.3 エウレカの 2 つのコンポーネント
1) エウレカサーバーはサービス登録サービスを提供します
- 各マイクロサービス ノードは、設定を通じて開始された後、EurekaServer に登録されます。このようにして、EurekaServer のサービス レジストリには、利用可能なすべてのサービス ノードの情報が保存されます。サービス ノードの情報は、インターフェイスで直感的に確認できます。
- 例: 不動産会社にお金を支払い、コミュニティの基本情報を記入します。
2) EurekaClient は登録センター経由でアクセスします
- これは、Eureka Server との対話を簡素化するために使用される Java クライアントであり、ラウンドロビン ロード アルゴリズムを使用するロード バランサも組み込まれています。アプリケーションの起動後、ハートビートが Eureka Server に送信されます (デフォルトの間隔は 30 秒)。Eureka Server が複数のハートビート サイクル内にノードのハートビートを受信しない場合、EurekaServer はサービス レジストリからサービス ノードを削除します (デフォルトでは 90 秒)。
- 例: 不動産管理会社は、お金を受け取るまではコミュニティにサービスを提供しませんが、数か月以内にその後のお金を受け取らない場合は、コミュニティへのサービスを提供しなくなります。
5.3 単一マシン Eureka の構築手順
5.3.1 現在のシステムアーキテクチャ
- コンシューマ、プロデューサー、公共プロジェクト、およびサービス レジストリ。
5.3.2 IDEA が eurekaServer サービス登録センターを生成
- 同様の不動産会社
1)建モジュール:cloud-eureka-server7001
2) POMの変更
- Springcloud シーズン1とシーズン2の比較説明(この動画)
<!-- eureka新旧版本 -->
<!-- 以前的老版本(2018)-->
<dependency>
<groupid>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<!-- 现在新版本(2020.2)--><!-- 我们使用最新的 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
- 完全な pom.xml ファイルを作成します。これは新しいプロジェクトであるため、すべての依存関係を追加する必要があります。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 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-eureka-server7001</artifactId>
<dependencies>
<!-- eureka-server -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</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-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>
4) YMLを書く
- リソースディレクトリに新しい application.yml ファイルを作成します。
server:
port: 7001
eureka:
instance:
hostname: localhost #eureka服务端的实例名称
client:
#false表示不向注册中心注册自己(想注册也可以,不过没必要)
register-with-eureka: false
#false表示自己端就是注册中心,职责就是维护服务实例,并不需要去检索服务
fetch-registry: false
service-url:
#设置与eurekaServer交互的地址查询服务和注册服务都需要依赖这个地址,就是上面配置的eureka服务端的实例名称和端口号
defaultZone: http://${
eureka.instance.hostname}:${
server.port}/eureka/
5) メイン起動
- Java パッケージの下に新しい com.angenin.springcloud.EurekaMain7001 を作成します。
- このプロジェクトはサービス登録センターへの登録に使用されるため、ビジネス クラスを記述する必要はありません。
package com.angenin.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer // 表示它是服务注册中心
public class EurekaMain7001 {
public static void main(String[] args) {
SpringApplication.run(EurekaMain7001.class, args);
}
}
6) テスト
- このプロジェクトを開始し、ブラウザに http://localhost:7001/ と入力します。
5.3.3 EurekaClient: 8001 を登録センターに登録する
- EurekaClient cloud-provider-payment8001 は EurekaServer に登録され、Shang Silicon Valley School の外部教育サービスと同様のサービス プロバイダーになります。
1) 8001 支払いモジュール プロジェクトを変更する
- ここのプロバイダーは、以前に作成した cloud-provider-payment8001 モジュールのままですが、次の変更が加えられています。
2) POM を変更する
Springcloud シーズン1とシーズン2の比較説明(この動画)
<!--以前老版本,别再使用-->
<!-- 以前的老版本(2018)-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
<dependency>
<!--现在新版本,当前使用-->
<!-- 现在新版本(2020.2)--><!-- 我们使用最新的 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<dependency>
- 完全な pom ファイル: これは、変更前に追加された 8001 プロジェクトの依存関係であるため、ここに eureka-client の依存関係を追加するだけで済みます。
<?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-payment8001</artifactId>
<dependencies>
<!-- 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>
<!--boot指标监控依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<!--子工程写了版本号,就使用子工程的版本号,如果没写版本,找父工程中规定的版本号-->
<version>1.1.20</version>
</dependency>
<!--mysql-connector-java-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--jdbc-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</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: 8001
spring:
application:
#微服务名称,将此服务项目入住到注册中心,那么就需要给此项目取个名字
name: cloud-payment-service
#数据库配置
datasource:
#引入的数据库驱动类型
type: com.alibaba.druid.pool.DruidDataSource
#mysql5.x的没有cj
driver-class-name: com.mysql.jdbc.Driver
#记得先创建数据库
url: jdbc:mysql://localhost:3306/db2020?useUnicode=true&characterEncoding=utf-8&useSSL=false
username: root
password: root
eureka:
client:
#true表示向注册中心注册自己,默认为true
register-with-eureka: true
#是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
fetch-registry: true
service-url: #入住到哪个主机上面的哪个端口,即设置与 Eureka Server 交互的地址
defaultZone: http://localhost:7001/eureka
#mybatis配置
mybatis:
mapper-locations: classpath:mapper/*.xml #mapper.xml文件的位置
type-aliases-package: com.angenin.springcloud.entities #所有Entity别名类所在包(所有实体类所在的包)
4) メインのスタートアップ クラスを変更する
package com.angenin.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@EnableEurekaClient //表示这个项目是eureka的客户端。
@SpringBootApplication
public class PaymentMain8001 {
public static void main(String[] args) {
SpringApplication.run(PaymentMain8001.class, args);
}
}
5) テスト
- まず EurekaServer 登録センターを起動し、次に 8001 プロデューサーを起動します。
- 8001 プロジェクトが登録センターに正常に登録されたことがわかります。
6) マイクロサービス登録名の構成手順
- yml ファイル内の application.name (8001) は、登録センターに登録されたときのアプリケーション名 (7001) です。
7) 自己保護メカニズム
- 詳しい説明は後ほど
5.3.4 EurekaClient: 登録センターに 80 を登録する
- EurekaClient cloud-consumer-order80 は EurekaServer に登録され、授業を利用するためにシャン シリコン バレーに来る学生と同様のサービス コンシューマーになります。
1) 80 消費者注文モジュールを変更する
- ここでのコンシューマーは、以前に作成されたcloud-consumer-order80モジュールのままですが、次の変更が加えられています。
2) ポンポンを変更する
<!-- eureka-client -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
3) ymlを変更する
#访问一个网站时,默认是80端口,给用户80端口,用户就可以不用加端口直接访问页面
server:
port: 80
spring:
application:
name: cloud-order-service
eureka:
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://localhost: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 OrderMain80 {
public static void main(String[] args) {
SpringApplication.run(OrderMain80.class, args);
}
}
5) テスト
- まずはEurekaServer、7001サービスを起動します
- 次に、サービス プロバイダー プロバイダー、8001 サービスを開始します。
- クエリのテスト:
http://localhost/consumer/payment/get/4
、クエリは引き続き成功する可能性があります。
5.4 クラスターエウレカの構築手順
5.4.1 Eureka クラスターの原理の説明
- 質問: マイクロサービス RPC リモート サービス呼び出しのコアは何ですか?
- 高可用性とは、登録センターが 1 つしかないことを想像してください。これが失敗すると大惨事になります ( ̄▽ ̄)" と、サービス環境全体が利用できなくなります。
- 解決策: Eureka 登録センター クラスターを構築して、負荷分散とフォールト トレランスを実現します。
- エウレカクラスターを自分で理解する:お互いに登録してお互いを監視する
5.4.2 EurekaServerクラスタ環境の構築手順
1)建モジュール:cloud-eureka-server7002
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-eureka-server7002</artifactId>
<dependencies>
<!-- eureka-server -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</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-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) マッピング構成ホストを変更する
- 現在、2 つのマシン (Eureka) があります。各マシンは、構成ファイルで独自のサーバーのホスト名を構成する必要があります。ローカルであるため、localhost と呼ばれます。この時点では、2 つのマシンは localhost で構成されているため、重複した名前は区別できないため、127.0.0.1 が 2 つの異なるドメイン名にマッピングされるように、hosts ファイルを変更して区別する必要があります。
- 実際の物理マシンにはラップトップが 1 台しかないため、同じアドレスをマッピングするために異なるポート番号を使用します。7001 はマシン No. 1 をシミュレートし、7002 はマシン No. 2 をシミュレートします。
#Eureka集群配置
127.0.0.1 eureka7001.com
127.0.0.1 eureka7002.com
4) YML を書く (以前はスタンドアロン)
以前のスタンドアロン構成フォーム:
- eurekaサーバーのインスタンス名:localhostと記載
- アドレス: プロジェクト設定ファイルに設定されている IP とポート番号を記述します。
server:
port: 7001
eureka:
instance:
hostname: localhost #eureka服务端的实例名称
client:
#false表示不向注册中心注册自己(想注册也可以,不过没必要)
register-with-eureka: false
#false表示自己端就是注册中心,职责就是维护服务实例,并不需要去检索服务
fetch-registry: false
service-url:
#设置与eurekaServer交互的地址查询服务和注册服务都需要依赖这个地址,就是上面配置的eureka服务端的实例名称和端口号
defaultZone: http://${
eureka.instance.hostname}:${
server.port}/eureka/
ここで、両方のクラスター構成方法を変更する必要があります: 相互登録
-
eureka サーバーのインスタンス名: hosts ファイルに設定された 2 つの異なるドメイン名を区別するために記述されます。
-
アドレス:別のプロジェクト設定ファイルに設定されているIPとポート番号を記述します。
-
クラスターの最初の Eureka 構成ファイルを変更します。
server:
port: 7001
eureka:
instance:
hostname: eureka7001.com #eureka服务端的实例名称
client:
#false表示不向注册中心注册自己(想注册也可以,不过没必要)
register-with-eureka: false
#false表示自己端就是注册中心,职责就是维护服务实例,并不需要去检索服务
fetch-registry: false
service-url:
#设置与eurekaServer交互的地址查询服务和注册服务都需要依赖这个地址,就是上面配置的eureka服务端的实例名称和端口号
defaultZone: http://eureka7002.com:7002/eureka/
- クラスターの 2 番目の Eureka 構成ファイルを変更します。
server:
port: 7002
eureka:
instance:
hostname: eureka7002.com #eureka服务端的实例名称
client:
#false表示不向注册中心注册自己(想注册也可以,不过没必要)
register-with-eureka: false
#false表示自己端就是注册中心,职责就是维护服务实例,并不需要去检索服务
fetch-registry: false
service-url:
#设置与eurekaServer交互的地址查询服务和注册服务都需要依赖这个地址,就是上面配置的eureka服务端的实例名称和端口号
defaultZone: http://eureka7001.com:7001/eureka/
5) メイン起動
- 7002 のメイン起動クラスを追加します。
package com.angenin.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer // 表示它是服务注册中心
public class EurekaMain7002 {
public static void main(String[] args) {
SpringApplication.run(EurekaMain7002.class, args);
}
}
6) テスト
-
http://eureka7001.com:7001
、最初のステーションにアクセスし、1 が 2 を指していることを確認します。
-
http://eureka7002.com:7002
、2 番目のステーションにアクセスし、2 が 1 を指していることを確認します。
5.4.3 決済サービス 8001 マイクロサービスを上記の 2 つの Eureka クラスター構成に公開する
yml設定ファイルを変更する
- 以前のスタンドアロン バージョン
- これでクラスターのバージョンが
#微服务建议一定要写服务端口号和微服务名称
server:
#端口号
port: 8001
spring:
application:
#微服务名称,将此服务项目入住到注册中心,那么就需要给此项目取个名字
name: cloud-payment-service
#数据库配置
datasource:
#引入的数据库驱动类型
type: com.alibaba.druid.pool.DruidDataSource
#mysql5.x的没有cj
driver-class-name: com.mysql.jdbc.Driver
#记得先创建数据库
url: jdbc:mysql://localhost:3306/db2020?useUnicode=true&characterEncoding=utf-8&useSSL=false
username: root
password: root
eureka:
client:
#true表示向注册中心注册自己,默认为true
register-with-eureka: true
#是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
fetch-registry: true
service-url: #入住到哪个主机上面的哪个端口,即设置与 Eureka Server 交互的地址
#defaultZone: http://localhost:7001/eureka #单机版
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/ # 集群版
#mybatis配置
mybatis:
mapper-locations: classpath:mapper/*.xml #mapper.xml文件的位置
type-aliases-package: com.angenin.springcloud.entities #所有Entity别名类所在包(所有实体类所在的包)
5.4.4 Order Service 80 マイクロサービスを上記の 2 つの Eureka クラスター構成に公開する
yml設定ファイルを変更する
-
以前のスタンドアロン バージョン
-
これでクラスターのバージョンが
#访问一个网站时,默认是80端口,给用户80端口,用户就可以不用加端口直接访问页面
server:
port: 80
spring:
application:
name: cloud-order-service
eureka:
client:
register-with-eureka: true
fetch-registry: true
service-url:
#defaultZone: http://localhost:7001/eureka #单机版
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka # 集群版
5.4.5 テスト 01
-
まずはEurekaServer、7001/7002サービスを起動します
-
サービスプロバイダーを再度開始するには、8001
-
消費者を再び活性化するには、80
-
http://eureka7001.com:7001
、検出サービスがクラスターに登録されています
-
http://eureka7002.com:7002
、クラスターに登録されていることもわかりました
-
http://localhost/consumer/payment/get/4
、検索に成功しました。
-
完成したアーキテクチャは次のとおりです。
- 2 つの登録センターで構成されるクラスターは相互に登録し、プロデューサーはコンシューマーを呼び出してサービスを登録センターに公開します。
- 2 つの登録センターで構成されるクラスターは相互に登録し、プロデューサーはコンシューマーを呼び出してサービスを登録センターに公開します。
5.4.6 決済事業者8001クラスタ環境構築
- つまり、2 番目のプロデューサー プロジェクト、コンテンツ、および最初の 8001 を追加します。
1) 新しいクラウドプロバイダー支払いを作成8002
2) POMの変更
- 追加された依存関係は 8001 と一致しています。
<?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-payment8002</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<!-- 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>
<!--boot指标监控依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<!--子工程写了版本号,就使用子工程的版本号,如果没写版本,找父工程中规定的版本号-->
<version>1.1.20</version>
</dependency>
<!--mysql-connector-java-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--jdbc-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</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を書く
- 8001のymlファイルをコピーし、ポート番号を8002に変更します。
#微服务建议一定要写服务端口号和微服务名称
server:
#端口号
port: 8002
spring:
application:
#微服务名称,将此服务项目入住到注册中心,那么就需要给此项目取个名字
name: cloud-payment-service
#数据库配置
datasource:
#引入的数据库驱动类型
type: com.alibaba.druid.pool.DruidDataSource
#mysql5.x的没有cj
driver-class-name: com.mysql.jdbc.Driver
#记得先创建数据库
url: jdbc:mysql://localhost:3306/db2020?useUnicode=true&characterEncoding=utf-8&useSSL=false
username: root
password: root
eureka:
client:
#true表示向注册中心注册自己,默认为true
register-with-eureka: true
#是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
fetch-registry: true
service-url: #入住到哪个主机上面的哪个端口,即设置与 Eureka Server 交互的地址
#defaultZone: http://localhost:7001/eureka #单机版
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/ # 集群版
#mybatis配置
mybatis:
mapper-locations: classpath:mapper/*.xml #mapper.xml文件的位置
type-aliases-package: com.angenin.springcloud.entities #所有Entity别名类所在包(所有实体类所在的包)
4) メイン起動
package com.angenin.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@EnableEurekaClient //表示这个项目是eureka的客户端。
@SpringBootApplication
public class PaymentMain8002 {
public static void main(String[] args) {
SpringApplication.run(PaymentMain8002.class, args);
}
}
5) 業種
- 8001のビジネスクラス(コントローラー、サービス、Dao、マッパー)をコピーします。
- コピーされたディレクトリ
6) 8001/8002のコントローラを変更する
- 2 つのプロデューサーから構成されるクラスターになっているため、外部に公開される名前は同じです。
- それでは、コンシューマ 80 はプロデューサ クラスタ サービス (8001、8002) のどれを呼び出すのでしょうか? ? ?
- @value アノテーションを使用して構成ファイルのポート番号をコードに挿入し、出力することで、呼び出し時にポート番号に基づいてどのプロデューサが使用されているかを知ることができます。
- 両方のプロデューサー コントロール層を変更する必要があります。
package com.angenin.springcloud.controller;
import com.angenin.springcloud.entities.CommonResult;
import com.angenin.springcloud.entities.Payment;
import com.angenin.springcloud.service.PaymentService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
@RestController
@Slf4j //日志
public class PaymentController {
@Resource
private PaymentService paymentService;
@Value("${server.port}")
private String serverPort;//添加serverPort
//前后端分离,所以不能直接返回对象,数据要先经过CommonResult封装再返回
@PostMapping("/payment/create")
public CommonResult<Payment> create(@RequestBody Payment payment){
int result = paymentService.create(payment);
log.info("******插入的数据为:" + payment);
log.info("******插入结果:" + result);
if(result > 0){
//插入成功
return new CommonResult(200, "插入数据库成功,serverPort:"+serverPort, result);
}else{
return new CommonResult(444, "插入数据库失败,serverPort:"+serverPort,null);
}
}
@GetMapping("/payment/get/{id}")
public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id){
Payment payment = paymentService.getPaymentById(id);
log.info("******查询结果:" + payment);
if(payment != null){
//查询成功
return new CommonResult(200, "查询成功,serverPort:"+serverPort, payment);
}else{
return new CommonResult(444, "没有对应记录,查询ID:" + id,null);
}
}
}
7) テスト
- 7001 と 7002 を最初に開始します
- 起動時 8001/8002
- ついに80
効果発動 - 2台のエウレカ管理ページにアクセス(
http://eureka7001.com:7001/、http://eureka7002.com:7002/
)
- コンシューマ 80 を介してプロデューサ クラスタを呼び出すと、すべての呼び出しがプロデューサ 8001 に対して行われることがわかります。私たちは、URL アドレスがコンシューマ 80 の制御層コードにハードコーディングされていると考えました。(
http://localhost/consumer/payment/get/4
)
- 解決策: スタンドアロン バージョンでは URL アドレスが書き込まれますが、クラスターでは統一されたサービス名が公開されるため、URL をクラスター サービス名に変更する必要があります。
- つまり、構成ファイルで以前に設定されたサービス名です。
package com.angenin.springcloud.controller;
import com.angenin.springcloud.entities.CommonResult;
import com.angenin.springcloud.entities.Payment;
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 org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
@RestController
@Slf4j
public class OrderController {
//public static final String PAYMENT_URL = "http://localhost:8001"; 单机
public static final String PAYMENT_URL = "http://CLOUD-PAYMENT-SERVICE";
@Resource
private RestTemplate restTemplate;
//因为浏览器只支持get请求,为了方便这里就用get
@GetMapping("/consumer/payment/create")
public CommonResult<Payment> create(Payment payment){
log.info("********插入的数据:" + payment);
//postForObject分别有三个参数:请求地址,请求参数,返回的对象类型----写操作
return restTemplate.postForObject(PAYMENT_URL + "/payment/create", payment, CommonResult.class);
}
@GetMapping("/consumer/payment/get/{id}")
public CommonResult<Payment> getPayment(@PathVariable("id") Long id){
log.info("********查询的id:" + id);
//getForObject两个参数:请求地址,返回的对象类型----读操作
return restTemplate.getForObject(PAYMENT_URL + "/payment/get/" + id, CommonResult.class);
}
}
- 80 を再起動し、再度テストします。
http://localhost/consumer/payment/get/4
- 結果として例外が表示されます。その理由は、プロデューサー クラスターがマイクロサービス名を外部に公開しているものの、クラスター内のどの特定のプロデューサーがサービスを使用しているかを識別できないためです。
- 解決策: @LoadBalanced アノテーションを使用して、RestTemplate に負荷分散機能を付与します。
- 5.4.7 ロードバランシングを表示
5.4.7 負荷分散
package com.angenin.springcloud.config;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class ApplicationContextConfig {
//往容器中添加一个RestTemplate
//RestTemplate提供了多种便捷访问远程http访问的方法
@Bean
@LoadBalanced //使用@LoadBalanced注解赋予RestTemplate负载均衡的能力
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
5.4.8 テスト 02
- 80が変更されているため、再起動して再度訪問する必要があります。
http://localhost/consumer/payment/get/4
- 効果: 更新されるたびに、8001 と 8002 が切り替わります。
- 注: デフォルトの負荷分散はポーリング メカニズムです。
- 後ほどお話しますが、リボンの負荷分散機能はデフォルトでポーリングになっています。
- リボンとエウレカの統合後、コンシューマはアドレスやポート番号を気にすることなくサービスを直接呼び出すことができ、サービスにはロード機能も追加されました。
5.4.9 ここまでのアーキテクチャ図
- 2 つの登録センターで構成されるクラスターが相互に登録します
- 2 つのプロデューサーで構成され、登録センターに登録されたクラスター
- 1 人の消費者が登録センターに登録しました。
- Consumer 80 は、Producer 8001 と 8002 で構成されるクラスターを呼び出します。
5.5 アクチュエーターのマイクロサービス情報が改善されました
- ありでもなしでもペアリングできるのでおすすめです。
5.5.1 ホスト名:サービス名の変更
1) 現状の問題点
- ホスト名が含まれます。仕様の要件に従って、サービス名のみが公開され、ホスト名は含まれません。
2) クラウドプロバイダー支払い8001/8002を変更します。
#微服务建议一定要写服务端口号和微服务名称
server:
#端口号
port: 8001
spring:
application:
#微服务名称,将此服务项目入住到注册中心,那么就需要给此项目取个名字
name: cloud-payment-service
#数据库配置
datasource:
#引入的数据库驱动类型
type: com.alibaba.druid.pool.DruidDataSource
#mysql5.x的没有cj
driver-class-name: com.mysql.jdbc.Driver
#记得先创建数据库
url: jdbc:mysql://localhost:3306/db2020?useUnicode=true&characterEncoding=utf-8&useSSL=false
username: root
password: root
eureka:
client:
#true表示向注册中心注册自己,默认为true
register-with-eureka: true
#是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
fetch-registry: true
service-url: #入住到哪个主机上面的哪个端口,即设置与 Eureka Server 交互的地址
#defaultZone: http://localhost:7001/eureka #单机版
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/ # 集群版
instance: #重点,和client平行
instance-id: payment8001 # 每个提供者的id不同,显示的不再是默认的项目名
#mybatis配置
mybatis:
mapper-locations: classpath:mapper/*.xml #mapper.xml文件的位置
type-aliases-package: com.angenin.springcloud.entities #所有Entity别名类所在包(所有实体类所在的包)
3) 改造後
- 再起動 8001,8002 (
http://eureka7001.com:7001/
)
5.5.2 アクセス情報に IP 情報プロンプトがある
1) 現状の問題点
-
リンクをクリックすると、左下隅に IP アドレスのプロンプトが表示されません
-
新版本的默认带ip显示
-
注: これら 2 つの依存関係をインポートした後、その効果は IP が完成している場合にのみ有効になります。
2) クラウドプロバイダー支払い8001/8002を変更します。
instance: #重点,和client平行
instance-id: payment8001 # 每个提供者的id不同,显示的不再是默认的项目名
prefer-ip-address: true #访问路径可以显示ip地址
3) 改造後
5.6 サービスの検出Discovery
- eurekaに登録されているマイクロサービスは、サービスディスカバリを通じてサービスに関する情報を取得できます。
- つまり、ホスト名、ポート番号など、eureka に正常に登録されたこれらのマイクロサービスの情報を取得します。
5.6.1 cloud-provider-payment8001 のコントローラーを変更する
- 8001 を例にとると、8002 の方法は同じなので、ここでは変更しません。
package com.angenin.springcloud.controller;
import com.angenin.springcloud.entities.CommonResult;
import com.angenin.springcloud.entities.Payment;
import com.angenin.springcloud.service.PaymentService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
@RestController
@Slf4j //日志
public class PaymentController {
@Resource
private PaymentService paymentService;
@Value("${server.port}")
private String serverPort;//添加serverPort
@Resource
private DiscoveryClient discoveryClient; //springframework的DiscoveryClient(不要导错包了)
@GetMapping("/payment/discovery")
public Object discovery(){
//获取服务列表的信息(即:在Eureka中注册过登录好的微服务有哪些,显示所有注册过的微服务名称)
List<String> services = discoveryClient.getServices();
for (String element : services) {
log.info("*******element:" + element);
}
// 根据微服务的名称进一步获得该微服务的信息
List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
for (ServiceInstance instance : instances) {
//getServiceId服务器id getHost主机名称 getPort端口号 getUri地址
log.info(instance.getServiceId() + "\t" + instance.getHost() + "\t" + instance.getPort() + "\t" + instance.getUri());
}
return this.discoveryClient;
}
//前后端分离,所以不能直接返回对象,数据要先经过CommonResult封装再返回
@PostMapping("/payment/create")
public CommonResult<Payment> create(@RequestBody Payment payment){
int result = paymentService.create(payment);
log.info("******插入的数据为:" + payment);
log.info("******插入结果:" + result);
if(result > 0){
//插入成功
return new CommonResult(200, "插入数据库成功,serverPort:"+serverPort, result);
}else{
return new CommonResult(444, "插入数据库失败,serverPort:"+serverPort,null);
}
}
@GetMapping("/payment/get/{id}")
public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id){
Payment payment = paymentService.getPaymentById(id);
log.info("******查询结果:" + payment);
if(payment != null){
//查询成功
return new CommonResult(200, "查询成功,serverPort:"+serverPort, payment);
}else{
return new CommonResult(444, "没有对应记录,查询ID:" + id,null);
}
}
}
5.6.2 8001 メインスタートアップクラス
package com.angenin.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@EnableEurekaClient //表示这个项目是eureka的客户端。
@SpringBootApplication
@EnableDiscoveryClient //启用发现客户端-后续详解
public class PaymentMain8001 {
public static void main(String[] args) {
SpringApplication.run(PaymentMain8001.class, args);
}
}
5.6.3 セルフテスト
-
まずはEurekaServerを起動します
-
8001 メインスタートアップクラスを再度開始します。しばらく時間がかかります。
-
http://localhost:8001/payment/discovery
-
次はセルフテストです: コンシューマ 8001 は自身の IP アドレスにアクセスします。クライアント 80 でコンシューマ アクセスが必要な場合は、このサービス インターフェイス アドレスを外部に公開するだけで済みます。その後、80 はそのようなアクセス アドレスを通じてさまざまなマイクロサービスを取得できます。情報。(よくわかりません)
5.7 エウレカの自己防衛
5.7.1 故障現象
概要:
- 保護モードは主に、クライアントのグループと Eureka Server の間にネットワーク分割があるシナリオでの保護に使用されます。保護モードに入ると、
Eureka Server将会尝试保护其服务注册表中的信息,不再删除服务注册表中的数据,也就是不会注销任何微服务。
- Eureka Server のホームページに次のプロンプトが表示された場合は、Eureka が保護モードに入ったことを意味します:
EMERGENCY! EUREKA MAY BE INCONRRECTLY CLAIMING INSTANCES ARE UP WHEN THEY'RE NOT. RENEWALS ARE LESSER THAN THRESHOLD AND HENCE THE INSTANCES ARE NOT BEING念のため期限切れです
5.7.2 原因
-
エウレカの自己防衛機構はなぜ生み出されるのか?
- ネットワークが EurekaServer に接続されていないにもかかわらず EurekaClient が正常に実行されないように、EurekaServer は EurekaClient サービスをすぐには削除しません。
-
自己保護モードとは何ですか?
- デフォルトでは、EurekaServer が一定時間内にマイクロサービス インスタンスのハートビートを受信しない場合、EurekaServer はインスタンスからログアウトします (デフォルトでは 90 秒)。しかし、ネットワーク パーティション障害 (遅延、ラグ、輻輳) が発生すると、マイクロサービスと EurekaServer は正常に通信できなくなり、マイクロサービス自体は実際には正常であるため、上記の動作は非常に危険になる可能性があります
此时本不应该注销这个微服务
。Eureka は、「自己保護モード」を通じてこの問題を解決します。EurekaServer ノードが短期間に多くのクライアントを失うと (ネットワーク分割障害が発生する可能性があります)、このノードは自己保護モードに入ります。
在自我保护模式中,Eureka Server会保护服务注册表中的信息,不再注销任何服务实例。
その設計哲学は、潜在的に健全なサービス インスタンスを盲目的にログアウトするのではなく、誤ったサービス登録情報を保持することです。一句话讲解:好死不如赖活着
- 要約すると、自己保護モードはネットワークの異常に対処するためのセキュリティ保護手段です。そのアーキテクチャ哲学は、健全なマイクロサービスを盲目的にログオフするのではなく、すべてのマイクロサービスを同時に保持する (健全なマイクロサービスと不健全なマイクロサービスの両方が保持される) ことです。自己保護モードを使用すると、Eureka クラスターをより堅牢で安定させることができます。
- デフォルトでは、EurekaServer が一定時間内にマイクロサービス インスタンスのハートビートを受信しない場合、EurekaServer はインスタンスからログアウトします (デフォルトでは 90 秒)。しかし、ネットワーク パーティション障害 (遅延、ラグ、輻輳) が発生すると、マイクロサービスと EurekaServer は正常に通信できなくなり、マイクロサービス自体は実際には正常であるため、上記の動作は非常に危険になる可能性があります
-
一言で言えば、特定の時点で特定のマイクロサービスが利用できなくなった場合、Eureka はそれをすぐにはクリーンアップしませんが、マイクロサービスの情報は保存します。
-
CAP の AP ブランチに属します
5.7.3 自己保護を禁止する方法
- デフォルトはオンです
- 登録センターとプロデューサーがクラスタ構成になったため、再起動のたびにたくさんのサービスを起動するのは面倒なので、ここでテストする場合は7001と8001を変更するだけで済みます(スタンドアロン版と同様)。その後は、テストのために 7001 と 8001 を起動するだけで済みます。
1) 登録センター eureakeServer 側 7001
- 工場出荷時のデフォルトでは、自己保護メカニズムが有効になっています。
eureka.server.enable-self-preservation=true
eureka.server.enable-self-preservation = false
自己保護モードは次の方法で無効にできます。
server:
port: 7001
eureka:
instance:
hostname: eureka7001.com #eureka服务端的实例名称
client:
#false表示不向注册中心注册自己(想注册也可以,不过没必要)
register-with-eureka: false
#false表示自己端就是注册中心,职责就是维护服务实例,并不需要去检索服务
fetch-registry: false
service-url:
#设置与eurekaServer交互的地址查询服务和注册服务都需要依赖这个地址,就是上面配置的eureka服务端的实例名称和端口号
#defaultZone: http://eureka7002.com:7002/eureka/ #集群模式
defaultZone: http://eureka7001.com:7001/eureka/ #切换为单机模式,为了方便测试自我保护机制
server: #server与client对齐
#关闭自我保护,默认为true
enable-self-preservation: false
#心跳的间隔时间,单位毫秒
eviction-interval-timer-in-ms: 2000
- 終了効果: (7001 登録センターを起動してアクセスします
http://eureka7001.com:7001/
。この時点では 7001 のみが起動されます。理由はテストの便宜上前述されています)
2) プロデューサークライアント eureakeClient 8001
- 構成
#微服务建议一定要写服务端口号和微服务名称
server:
#端口号
port: 8001
spring:
application:
#微服务名称,将此服务项目入住到注册中心,那么就需要给此项目取个名字
name: cloud-payment-service
#数据库配置
datasource:
#引入的数据库驱动类型
type: com.alibaba.druid.pool.DruidDataSource
#mysql5.x的没有cj
driver-class-name: com.mysql.jdbc.Driver
#记得先创建数据库
url: jdbc:mysql://localhost:3306/db2020?useUnicode=true&characterEncoding=utf-8&useSSL=false
username: root
password: root
eureka:
client:
#true表示向注册中心注册自己,默认为true
register-with-eureka: true
#是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
fetch-registry: true
service-url: #入住到哪个主机上面的哪个端口,即设置与 Eureka Server 交互的地址
defaultZone: http://localhost:7001/eureka #单机版
#defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/ # 集群版
instance: #重点,和client平行
instance-id: payment8001 #每个提供者的id不同,显示的不再是默认的项目名
prefer-ip-address: true #访问路径可以显示ip地址
#心跳检测与续约时间
#开发时没置小些,保证服务关闭后注册中心能即使剔除服务
#Eureka客户端向服务端发送心跳的时间间隔,单位为秒(默认是30秒)
lease-renewal-interval-in-seconds: 1
#Eureka服务端在收到最后一次心跳后等待时间上限,单位为秒(默认是90秒),超时将剔除服务
lease-expiration-duration-in-seconds: 2
#mybatis配置
mybatis:
mapper-locations: classpath:mapper/*.xml #mapper.xml文件的位置
type-aliases-package: com.angenin.springcloud.entities #所有Entity别名类所在包(所有实体类所在的包)
3) テスト
-
7001 と 8001 の両方が設定されています。
-
最初に 7001 を開始し、次に 8001 を開始します (
http://eureka7001.com:7001/
8001 サービスが 7001 登録センターに正しく挿入されていることを確認します)。
-
8001 を閉じるということは、8001 サービスが停止していることを意味するため、登録センターから直ちに削除する必要があります。
6. Zookeeper サービスの登録と検出
6.1 Eureka が更新を停止した場合はどうすればよいですか?
https://github.com/Netflix/eureka/wiki
、公式サイトを確認してください
6.2 SpringCloud は Eureka を置き換えるために Zookeeper を統合します
- 前提として、Yang 兄弟が説明した Zookeeper について明確に理解しており、(仮想マシン構成を使用して) Centos7 サーバー上で Zookeeper を正常に構成していることが前提となります。
6.2.1 登録センターの飼育員
-
コンセプト:zookeeperは登録センター機能を実現できる分散連携ツールです
-
Zookeeper サーバーが Eureka サーバーの代わりとなり、zk がサービス登録センターとして機能します
-
Linux サーバーのファイアウォールをオフにしてから、Zookeeper サーバーを起動します。
# 关闭防火墙
systemctl stop firewalld.service
# 禁止防火墙开机启动
systemctl disable firewalld.service
# 查看防火墙状态
systemctl status firewalld.service
# Zookeeper启动详情查看----Zookeeper基础操作 博客
- サービスの ping が成功したかどうかをテストする
6.2.2 サービスプロバイダー
1) 新しいクラウドプロバイダー支払いを作成8004
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-payment8004</artifactId>
<dependencies>
<!-- SpringBoot整合Web组件 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency><!-- 引入自己定义的api通用包,可以使用Payment支付Entity -->
<groupId>com.angenin.springcloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>${project.version}</version>
</dependency>
<!-- SpringBoot整合zookeeper客户端 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zookeeper-discovery</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
#8004表示注册到zookeeper服务器的支付服务提供者端口号
server:
port: 8004
spring:
application:
#服务别名----注册zookeeper到注册中心名称
name: cloud-provider-payment
cloud:
zookeeper:
#linux主机ip+zookeeper端口号
connect-string: 192.168.10.140:2181
4) メインスタートアップクラス
package com.angenin.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient//该注解用于向使用consul或者zookeeper作为注册中心时注册服务
public class PaymentMain8004 {
public static void main(String[] args) {
SpringApplication.run(PaymentMain8004.class, args);
}
}
5)コントローラー
- 注: ここで学ぶべき主なことは、Zookeeper をサービス登録センターとして統合することです。そのため、ここではテスト用のコントローラーのみを作成し、ビジネス レイヤー、データ レイヤー、操作データベースは作成しません。
package com.angenin.springcloud.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.UUID;
@Slf4j
@RestController
public class PaymentController {
@Value("${server.port}") //获取端口号
private String serverPort;
//查询端口号,8004生产者能否注册进入zookeeper,获得端口号
@RequestMapping("/payment/zk")
public String paymentzk(){
return "springcloud with zookeeper:" + serverPort + "\t" + UUID.randomUUID().toString();
}
}
6) 8004 を開始して Zookeeper に登録します
- まず、Zookeeper を起動します (デフォルトのポート番号は 2181)
# 启动Zookeeper服务端
./zkServer.sh start
#启动客户端
# 如果连接本地Zookeeper,那么ip:port可省略
./zkCli.sh -server ip:port
-
8004 サービス プロデューサーを開始するときに問題が発生します (新しいバージョンでは問題がありません 23/8/21)
-
Zookeeper のバージョンの jar パッケージの競合問題を解決する
- 理由: ビデオ内で教師がインストールした Zookeeper のバージョンはバージョン 3.4.9 で、Zookeeper の依存関係座標を導入するときのデフォルトのバージョンは 3.5.3 であるため、jar パッケージの競合が報告されます。
- 解決する:
- 方法 1: Linux システムにインストールされている Zookeeper をアンインストールし、そのバージョンと一致する Zookeeper をインストールします (推奨されません。Zookeeper は、他のシステムが使用している可能性があるため、インストール完了後に簡単に変更できません)。
- 方法 2: jar パッケージを使用してインポートを除外する
-
zk 競合を削除した後の新しい POM.xml
- 勉強中にバージョン 3.5.7 をインストールしたため、エラーは報告されなかったので、この手順は省略できます。
- 勉強中にバージョン 3.5.7 をインストールしたため、エラーは報告されなかったので、この手順は省略できます。
<?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-payment8004</artifactId>
<dependencies>
<!-- SpringBoot整合Web组件 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency><!-- 引入自己定义的api通用包,可以使用Payment支付Entity -->
<groupId>com.angenin.springcloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>${project.version}</version>
</dependency>
<!-- SpringBoot整合zookeeper客户端 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
<!--先排除自带的zookeeper3.5.3-->
<exclusions>
<exclusion>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--添加zookeeper3.4.9版本-->
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.9</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>
7) 検証試験
-
8004がzookeeperに登録されているか確認する
-
ブラウザ入力:
http://localhost:8004/payment/zk
8) 検証試験2
- 内容をさらに詳しく調べる: 紫色のボックス内の内容は、Zookeeper の基本情報です。
- このコンテンツをオンラインの JSON 解析ツール (Baidu 検索) にコピーします。
9) 考察: サービス ノードは一時的なノードですか、それとも永続的なノードですか?
- Zookeeper サーバー上には znode ノードと呼ばれるものがあり、各マイクロサービスがノードとして Zookeeper に配置されることは誰もが理解しています。
- Zookeeper ノードの分類:
- 一時ノード
- シリアル番号付きの一時ノード
- 永続ノード
- シリアル番号付きの永続ノード
- 質問: Zookeeper 登録センターに登録されているノードは一時的なノードですか、それとも永続的なノードですか? ? ?
- 答え: 一時ノード
- zkに登録したノードは一時的なノードであり、当サービスが一定時間内にハートビートを送信しない場合、zkは当サービスのznodeを削除します。自己保護メカニズムはありません。接続を再確立すると、znode-id 番号も変わります。
- zkに登録したノードは一時的なノードであり、当サービスが一定時間内にハートビートを送信しない場合、zkは当サービスのznodeを削除します。自己保護メカニズムはありません。接続を再確立すると、znode-id 番号も変わります。
6.2.3 サービス利用者
1) 新しいcloud-consumerzk-order80を作成します。
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-consumerzk-order80</artifactId>
<dependencies>
<!-- SpringBoot整合Web组件 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- SpringBoot整合zookeeper客户端 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zookeeper-discovery</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
#8004表示注册到zookeeper服务器的支付服务提供者端口号
server:
port: 80
spring:
application:
#服务别名----注册zookeeper到注册中心名称
name: cloud-consumer-order
cloud:
zookeeper:
#linux主机ip+zookeeper端口号
connect-string: 192.168.10.140:2181
4) メイン起動
package com.angenin.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient //该注解用于向使用consul或者zookeeper作为注册中心时注册服务
public class OrderZKMain80 {
public static void main(String[] args) {
SpringApplication.run(OrderZKMain80.class, args);
}
}
5) 業種
- Bean を構成する
package com.angenin.springcloud.config;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class ApplicationContextConfig {
//往容器中添加一个RestTemplate
//RestTemplate提供了多种便捷访问远程http访问的方法
@Bean
@LoadBalanced //使用@LoadBalanced注解赋予RestTemplate负载均衡的能力
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
- コントローラ
package com.angenin.springcloud.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
@RestController
@Slf4j
public class OrderZKController {
//调用服务生产者的服务名称
public static final String INVOKE_URL = "http://cloud-provider-payment";
@Resource
private RestTemplate restTemplate;
@RequestMapping("/consumer/payment/zk")
public String paymentInfo(){
//getForObject两个参数:请求地址,返回的对象类型----读操作
String result = restTemplate.getForObject(INVOKE_URL + "/payment/zk", String.class);
return result;
}
}
6) 検証試験
- Consumer 80 を起動し、登録され、登録センターに入っているかどうかを確認します。
7) テストアドレスにアクセスします
http://localhost/consumer/payment/zk
8) Zookeeper クラスターについて
- なお、zookeeperのクラスタ構成については、現在ではほとんど使われていませんが、ymlファイル内の構成も同様で、zookeeperのアドレスをリスト形式で複数記述でき、zookeeperのクラスタについては、zookeeper講座で説明しています。全体として、Zookeeper クラスターと yml ファイルの構成を協力する限り、クラスターの構築を完了できます。
9) 現在のアーキテクチャ
- 飼育員登録センター、生産者 8004、消費者 80、および 80 と 8004 の両方がサービス登録センターに登録されており、消費者 80 が生産者 8004 に電話をかけます。
7. Consul サービスの登録と検出
7.1 Consul の概要
-
とは:
https://www.consul.io/intro/index.html
- Consul は、HashiCorp によって使用されるオープンソースの分散サービス検出および構成管理システムです
Go 语言开发
。 - マイクロサービス システムにサービス ガバナンス、構成センター、制御バス、その他の機能を提供します。これらの各機能は、必要に応じて個別に使用することも、一緒に使用して包括的なサービス メッシュを構築することもでき、つまり、Consul は完全なサービス メッシュ ソリューションを提供します。
- 多くの利点があります。含まれるもの: 比較的単純な raft プロトコルに基づく、ヘルス チェックをサポート、HTTP と DNS の両方のプロトコルをサポート、データ センター全体の WAN クラスターをサポート、プラットフォーム全体にグラフィカル インターフェイスを提供し、Linux、Mac、および Windows をサポート
-
何ができますか
- サービス検出: HTTP と DNS という 2 つの検出方法を提供します。
- ヘルスモニタリング: 複数の方法をサポートし、HTTP、TCP、Docker、およびシェルスクリプトのカスタマイズされたモニタリングをサポートします。
- KVストレージ:KeyとValueの保存方法
- 複数のデータセンター: Consul は複数のデータセンターをサポートします
- ビジュアルウェブインターフェース
-
どこへ行くか: 必要なバージョンを選択してください
https://www.consul.io/downloads.html
-
遊び方
https://www.springcloud.cc/spring-cloud-consul.html
-
デフォルトのポート番号は 8500 です
7.2 Consul のインストールと実行
-
公式ウェブサイトのインストール手順:
https://learn.hashicorp.com/consul/getting-started/install.html
-
例として、Windows バージョンの Consul をダウンロードします。
-
ダウンロードが完了すると、consul.exe ファイルが 1 つだけ解凍されます。コマンド ライン ウィンドウに「cmd」と入力して、バージョン番号情報を表示します。
-
開発モードの使用を開始する
-
領事エージェント -dev
-
Consul のホームページには、次のアドレスからアクセスできます: http://localhost:8500
-
結果ページ
-
7.3 サービスプロバイダー
7.3.1 新しいモジュール支払いサービスプロバイダーの作成8006
- クラウドプロバイダーconsul-payment8006
7.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-providerconsul-payment8006</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<!-- 引入自己定义的api通用包,可以使用Payment支付Entity -->
<dependency>
<groupId>com.angenin.springcloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>${project.version}</version>
</dependency>
<!--SpringCloud consul-server -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
<!-- SpringBoot整合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>
<!--日常通用jar包配置-->
<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>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>RELEASE</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
7.3.3 YML
#consul服务端口号
server:
port: 8006
#对外暴露的服务名
spring:
application:
name: consul-provider-payment
#consul注册中心地址
cloud:
consul:
host: localhost
port: 8500
discovery:
#hostname: 127.0.0.1
service-name: ${
spring.application.name}
7.3.4 メインスタートアップクラス
package com.angenin.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient //用于启用服务注册与发现功能。
public class PaymentMain8006
{
public static void main(String[] args) {
SpringApplication.run(PaymentMain8006.class, args);
}
}
7.3.5 ビジネスコントローラー
package com.angenin.springcloud.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.UUID;
@RestController
@Slf4j
public class PaymentController
{
@Value("${server.port}")
private String serverPort;
@RequestMapping(value = "/payment/consul")
public String paymentConsul()
{
return "springcloud with consul: "+serverPort+"\t "+ UUID.randomUUID().toString();
}
}
7.3.6 検証テスト
-
領事サービス登録センターを開始し、サービス プロデューサー 8006 を開始します。
-
Consul 登録センターのホームページ (http://localhost:8500) を確認すると、サービス登録センターにプロデューサーが登録されていることがわかります。
-
http://localhost:8006/payment/consul
7.4 消費者へのサービス提供
7.4.1 新しいモジュール消費サービス注文の作成80
- クラウド消費者コンサルタント注文80
7.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-consumerconsul-order80</artifactId>
<dependencies>
<!--SpringCloud consul-server -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
<!-- SpringBoot整合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>
<!--日常通用jar包配置-->
<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>
7.4.3 YML
###consul服务端口号
server:
port: 80
spring:
application:
name: cloud-consumer-order
####consul注册中心地址
cloud:
consul:
host: localhost
port: 8500
discovery:
#hostname: 127.0.0.1
service-name: ${
spring.application.name}
7.4.4 メインスタートアップクラス
package com.angenin.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient //该注解用于向使用consul或者zookeeper作为注册中心时注册服务
public class OrderConsulMain80
{
public static void main(String[] args) {
SpringApplication.run(OrderConsulMain80.class, args);
}
}
7.4.5 Beanの設定
package com.angenin.springcloud.config;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class ApplicationContextConfig
{
@Bean
@LoadBalanced
public RestTemplate getRestTemplate()
{
return new RestTemplate();
}
}
7.4.6 コントローラー
package com.angenin.springcloud.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
@RestController
@Slf4j
public class OrderConsulController{
public static final String INVOKE_URL = "http://consul-provider-payment";
@Resource
private RestTemplate restTemplate;
@GetMapping(value = "/consumer/payment/consul")
public String paymentInfo(){
String result = restTemplate.getForObject(INVOKE_URL+"/payment/consul",String.class);
return result;
}
}
7.4.7 検証テスト
- 80 人の消費者を開始
- 領事ホームページ (http://localhost:8500) を開きます。
7.4.8 アクセステストアドレス
- http://localhost/consumer/payment/consul
7.5 3 つの登録センター間の類似点と相違点
コンポーネント名 | 言語キャップ | サービスの健全性チェック | 外部に公開されたインターフェース | Spring Cloudの統合 |
---|---|---|---|---|
ユーレカ | ジャワ | AP | 利用可能なサポート | HTTP |
領事 | 行く | CP | サポート | HTTP/DNS |
動物園の飼育員 | ジャワ | CP | サポートクライアント | 統合された |
7.5.1 キャップ
CAP 理論は、システム全体の設計戦略ではなく、データの粒度に焦点を当てています。
- C: 一貫性 (強い一貫性)
- A: 可用性
- P:パーティショントレランス(パーティションフォールトトレランス)
7.5.2 クラシック CAP グラフ
最多只能同时较好的满足两个。
- CAP 理論の核心は次のとおりです。
一个分布式系统不可能同时很好的满足一致性,可用性和分区容错性这三个需求
したがって、CAP 原則によれば、NoSQL データベースは、CA 原則を満たす、CP 原則を満たす、AP 原則を満たすという 3 つのカテゴリに分類されます。- CA - シングルポイント クラスター。一貫性と可用性を満たすシステムですが、通常は拡張性があまり強力ではありません。
- CP - 一貫性、分割耐性を満たしているが、通常は特にパフォーマンスが良くないシステム。
- AP - 可用性、パーティション許容度を満たし、一般に整合性要件が低いシステム。
1) AP アーキテクチャ (エウレカ)
- ネットワーク分断が発生した場合、可用性を確保するため、システムBが
可以返回旧值
システムの可用性を確保します。 结论:违背了一致性C的要求,只满足可用性和分区容错,即AP
- Eureka には自己保護機構が備わっています。彼が強調しているのは、AP がマイクロサービスの高可用性を確保しているということです。生きているよりは死んだほうが良いです。たとえ、時々ダウンしてしばらくオフラインになって受信できなくなっても、それは受信できません。すぐに削除されます。
2) CP アーキテクチャ (動物園飼育員/領事)
- ネットワークの分断が発生した場合、一貫性を確保するにはリクエストを拒否する必要があり、そうでないと一貫性が保証されません。
结论:违背了可用性A的要求,只满足一致性和分区容错,即CP
- サービスが停止されると、すぐに削除されます。
8 リボン負荷分散サービス呼び出し
8.1 概要
-
次の演習のために eureka クラスター環境を復元します。
- 以前は、自己保護メカニズムのテストを容易にするために (毎回すべてのサービスを開始するのは面倒です)、7001 サービス登録センターと 8001 プロデューサのみが開始されていたため、ここではシングルクリック モード設定を復元する必要があります。クラスターモードの設定。(7001ymlファイルをクラスタ構成モードに変更し、8001yml構成ファイルをクラスタモードに変更します)
- 以前は、自己保護メカニズムのテストを容易にするために (毎回すべてのサービスを開始するのは面倒です)、7001 サービス登録センターと 8001 プロデューサのみが開始されていたため、ここではシングルクリック モード設定を復元する必要があります。クラスターモードの設定。(7001ymlファイルをクラスタ構成モードに変更し、8001yml構成ファイルをクラスタモードに変更します)
-
7001 および 7002 サービス登録センター クラスターを開始します。
-
8001 および 8002 プロデューサー クラスターを開始する
-
80 コンシューマ クラスタを開始する
-
コンシューマ 80 がプロデューサ クラスタを呼び出す
-
Eureka7001 のホームページにアクセスしてください。
http://eureka7001.com:7001/
-
Eureka7002 のホームページにアクセスしてください。
http://eureka7002.com:7002/
8.1.1 とは
- Spring Cloud リボンは、Netflix リボンに基づいて実装されたセットです
客户端负载均衡的工具
。 - 簡単に言えば、Ribbon は Netflix によってリリースされたオープンソース プロジェクトであり、その主な機能は を提供することです
客户端的软件负载均衡算法和服务调用
。リボン クライアント コンポーネントは、接続タイムアウト、再試行などの一連の完全な構成項目を提供します。簡単に言うと、構成ファイル内のロード バランサー (略して LB) の背後にあるすべてのマシンをリストすると、リボンが特定のルール (単純なポーリング、ランダム接続など) に基づいてこれらのマシンに接続するのを自動的に支援します。リボンを使用すると、カスタム負荷分散アルゴリズムを簡単に実装できます。
8.1.2 公式ウェブサイトの情報
-
https://github.com/Netflix/ribbon/wiki/はじめに
-
リボンも現在メンテナンス モードになっています
-
将来の交換オプション
- 将来的には、リボンは Spring Cloud LoadBalacer に置き換えられる可能性があります。
8.1.3 できますか?
-
LB負荷分散(ロードバランス)とは
- 簡単に言えば、システムの HA (高可用性) を実現するために、ユーザーのリクエストが複数のサービスに均等に分散されます。
- 一般的な負荷分散には、ソフトウェア Nginx、LVS、ハードウェア F5 などが含まれます。
-
リボン ローカル負荷分散クライアントと Nginx サーバー負荷分散の違い
- Nginx はサーバーの負荷分散であり、すべてのクライアント リクエストが nginx に渡され、nginx がリクエストを転送します。つまり、負荷分散はサーバーによって実装されます。
- リボン ローカル ロード バランシングは、マイクロサービス インターフェイスを呼び出すときに、登録センターから登録情報サービス リストを取得し、それを JVM にローカルにキャッシュすることで、RPC リモート サービス呼び出しテクノロジをローカルに実装します。
-
LB (ロードバランシング)
- 集中型 LB : つまり、独立した LB 機能 (F5 などのハードウェア、または nginx などのソフトウェア) がサービスのコンシューマとプロバイダーの間で使用され、この機能は、アクセス要求をサーバーに転送する役割を果たします。特定のポリシー、サービスプロバイダー。
- インプロセス LB : LB ロジックをコンシューマに統合します。コンシューマはサービス登録センターから利用可能なアドレスを学習し、これらのアドレスから適切なサーバーを選択します。、これは、コンシューマーがサービス プロバイダーのアドレスを取得するための
Ribbon就属于进程内LB
単なるクラス ライブラリです。集成于消费方进程
-
前に、80 がポーリング負荷を通じて 8001/8002 にアクセスすると説明しました (デフォルトはポーリングです)。
-
一文で言うと:
负载均衡+RestTemplate调用
- クライアントの負荷分散ツールは RestTemplate と連携してリモート RPC 呼び出しを実装します。
8.2 リボン負荷分散のデモンストレーション
8.2.1 アーキテクチャの説明
- リボンは 2 つのステップで動作します
- 最初のステップは、同じエリア内で負荷の少ないサーバーを優先する EurekaServer を選択することです。
- 2 番目のステップは、ユーザーが指定したポリシーに従って、サーバーから取得したサービス登録リストからアドレスを選択することです。
- リボンは、ポーリング、ランダム、応答時間に応じた重み付けなど、さまざまな戦略を提供します。
- 概要: リボンは実際にはソフト ロード バランシング クライアント コンポーネントです。必要なリクエストを必要とする他のクライアントと組み合わせて使用できます。eureka との組み合わせは一例にすぎません。
8.2.2 POM
- 説明: リボンの依存関係はこれまで導入されていませんでしたが、なぜ負荷分散が実現できるのでしょうか。
- リボン依存関係を導入するかどうか
<!--Ribbon的依赖:因为下面这个eureka-client依赖已经只带了Ribbon的依赖,所以此依赖加不加都可以-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
8.2.3 2 番目、RestTemplate の使用
-
公式ウェブサイト
https://docs.spring.io/spring-framework/docs/5.2.2.RELEASE/javadoc-api/org/springframework/web/client/RestTemplate.html
-
getForObjectメソッド/getForEntityメソッド
-
postForObject / postForEntity
-
GETリクエストメソッド(読み込み)
-
POSTリクエストメソッド(書き込み)
-
テスト: getForEntity メソッドを使用してクエリをテストします。
//使用getForEntity方法测试查询
@GetMapping("/consumer/payment/getForEntity/{id}")
public CommonResult<Payment> getPayment2(@PathVariable("id") Long id) {
ResponseEntity<CommonResult> entity = restTemplate.getForEntity(PAYMENT_URL+"/payment/get/"+id,CommonResult.class);
//getStatusCode获取状态码,is2xxSuccessful如果是状态码是200代表成功
if(entity.getStatusCode().is2xxSuccessful()){
//如果成功了返回请求体
return entity.getBody();
}else{
return new CommonResult<>(444,"操作失败");
}
}
- 80 を再起動すると、getForEntity メソッドを使用したクエリのテストが引き続き成功することがわかりました。
8.3 リボンコアコンポーネント IRule
8.3.1 IRuleインターフェース
- IRule: 特定のアルゴリズムに従ってサービス リストからアクセスするサービスを選択します
- IRule の主要な実装クラス (Ribbon には 7 つの負荷分散アルゴリズムが付属しています)
- com.netflix.loadbalancer.RoundRobinRule: ポーリング
- com.netflix.loadbalancer.Randomルール: ランダム
- com.netflix.loadbalancer.RetryRule: 最初に RoundRobinRule 戦略に従ってサービスを取得します。サービスの取得に失敗した場合は、指定された時間内に利用可能なサービスを取得するために再試行されます。
- WeightedResponseTimeRule: RoundRobinRule の拡張機能で、応答速度が速いほど選択の重みが大きくなり、選択されやすくなります。
- BestAvailableRule: まず、複数のアクセス障害によりサーキット ブレーカー トリップ状態にあるサービスをフィルタリングして除外し、次に同時実行量が最小のサービスを選択します。
- AvailabilityFilteringRule: 最初に失敗したインスタンスをフィルターで除外し、次に同時実行性のより小さいインスタンスを選択します。
- ZoneAvoidanceRule: デフォルトのルール。サーバーが配置されているゾーンのパフォーマンスとサーバーの可用性を複合的に判断してサーバーを選択します。
8.3.2 交換方法
1)cloud-consumer-order80を変更する
2) 構成の詳細に注意してください
公式ドキュメントには明確に警告が記載されています。
- このカスタム構成クラスは、@ComponentScan によってスキャンされた現在のパッケージまたはサブパッケージの下に配置することはできません。そうしないと、カスタム構成クラスがすべてのリボン クライアントによって共有され、特別なカスタマイズの目的が達成されません。
- つまり、メインのスタートアップ クラスには @SpringBootApplication のアノテーションが付けられます。このアノテーションの最下層には、メインのスタートアップ クラスがデフォルトで配置されているパッケージおよびサブパッケージをスキャンするために使用される @ComponentScan が含まれます。現在の要件では、メインのスタートアップ クラスが配置されているパッケージまたはサブパッケージにリボン構成クラスを配置できないため、新しいパッケージを作成する必要があります。
3) 新しいパッケージを作成します: com.angenin.myrule
4) 上記のパッケージの下に新しい MySelfRule ルール クラスを作成します。
package com.angenin.myrule;
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MySelfRule {
@Bean
public IRule myrule(){
return new RandomRule(); //负载均衡规则定义为随机
}
}
5) @RibbonClient をメインのスタートアップ クラスに追加します。
package com.angenin.springcloud;
import com.angenin.myrule.MySelfRule;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.ribbon.RibbonClient;
/**
* 在启动该微服务的时候就能去加载我们的自定义Ribbon配置类,从而使配置生效,形如:
* 服务生产者的服务名(配置文件是小写,这里是大写)、配置类的类型
*/
@RibbonClient(name = "CLOUD-PAYMENT-SERVICE",configuration=MySelfRule.class)
@EnableEurekaClient
@SpringBootApplication
public class OrderMain80 {
public static void main(String[] args) {
SpringApplication.run(OrderMain80.class, args);
}
}
6) テスト
-
7001 および 7002 サービス登録センター クラスターを開始します。
-
8001 および 8002 プロデューサー クラスターを開始する
-
80 コンシューマ クラスタを開始する
-
コンシューマ 80 がプロデューサ クラスタを呼び出す
-
http://localhost/consumer/payment/get/4 (表示される結果はランダムであり、8001 と 8002 のポーリングは交互に行われなくなりました)
8.4 リボン負荷分散アルゴリズム
- デフォルトのポーリング ルールに戻す
8.4.1 ポーリングルールの原則
- ロード バランシング アルゴリズム: 残りのインターフェイスへのリクエストの数 % サーバー クラスターの総数 = 実際の呼び出し元サーバーの場所の添字、
每次服务重启动后rest接口计数从1开始
。 - サービス リスト内のクラスターの数を取得します。
List instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
- のように:
List [0] instances = 127.0.0.1:8002
List [1] instances = 127.0.0.1:8001
- 8001 + 8002 が 1 つのクラスターに結合され、合計 2 台のマシンがあり、クラスターの総数は 2 です。ポーリング アルゴリズムの原理によると、次のようになります。
- リクエストの総数が 1: 1 % 2 =1 で、対応する添え字の位置が 1 の場合、取得されるサービス アドレスは 127.0.0.1:8001 です。
- リクエストの総数が 2: 2 % 2 =0 で、対応する添え字の位置が 0 の場合、取得されるサービス アドレスは 127.0.0.1:8002 です。
- リクエストの総数が 3: 3% 2 =1 で、対応する添え字の位置が 1 の場合、取得されるサービス アドレスは 127.0.0.1:8001 です。
- リクエストの総数が 4: 4 % 2 =0 で、対応する添え字の位置が 0 の場合、取得されるサービス アドレスは 127.0.0.1:8002 です。
- 等々…
8.4.2 RoundRobinRule ポーリング ルールのソース コード
- ctrl+n で IRule インターフェイスが開きます
- ctrl+alt+b: このインターフェースの実装クラスを表示します。
- ソースコード:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package com.netflix.loadbalancer;
import com.netflix.client.config.IClientConfig;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class RoundRobinRule extends AbstractLoadBalancerRule {
//AtomicInteger原子整形类
private AtomicInteger nextServerCyclicCounter;
private static final boolean AVAILABLE_ONLY_SERVERS = true;
private static final boolean ALL_SERVERS = false;
private static Logger log = LoggerFactory.getLogger(RoundRobinRule.class);
public RoundRobinRule() {
//此时nextServerCyclicCounter是一个原子整形类,并且value为0
this.nextServerCyclicCounter = new AtomicInteger(0);
}
public RoundRobinRule(ILoadBalancer lb) {
this();
this.setLoadBalancer(lb);
}
//ILoadBalancer选择哪一个负载均衡机制,这里lb为轮询
public Server choose(ILoadBalancer lb, Object key) {
//如果传入的lb没有负载均衡,为空,那么报错
if (lb == null) {
log.warn("no load balancer");
return null;
} else {
Server server = null;
int count = 0;
//还没选到执行的server,并且选择的次数没超过10次,进行选择server
while(true) {
if (server == null && count++ < 10) {
//lb.getReachableServers获取所有状态是up的服务实例
List<Server> reachableServers = lb.getReachableServers();
//lb.getAllServers获取所有服务实例
List<Server> allServers = lb.getAllServers();
//状态为up的服务实例的数量
int upCount = reachableServers.size();
//所有服务实例的数量
int serverCount = allServers.size();
//如果up的服务实例数量为0或者服务实例为0,打印日志log.warn并返回server=null
if (upCount != 0 && serverCount != 0) {
//获取到接下来server的下标
int nextServerIndex = this.incrementAndGetModulo(serverCount);
//获取下一个server
server = (Server)allServers.get(nextServerIndex);
//如果
if (server == null) {
//线程让步,线程会让出CPU执行权,让自己或者其它的线程运行。(让步后,CPU的执行权也有可能又是当前线程)
Thread.yield();
} else {
//获取的server还活着并且还能工作,则返回该server
if (server.isAlive() && server.isReadyToServe()) {
return server;
}
//否则server改为空
server = null;
}
//进入下次循环
continue;
}
log.warn("No up servers available from load balancer: " + lb);
return null;
}
//选择次数超过10次,打印日志log.warn并返回server=null
if (count >= 10) {
log.warn("No available alive servers after 10 tries from load balancer: " + lb);
}
return server;
}
}
}
private int incrementAndGetModulo(int modulo) {
int current;
int next;
//CAS加自旋锁
//CAS(Conmpare And Swap):是用于实现多线程同步的原子指令。CAS机制当中使用了3个基本操作数:内存地址V,旧的预期值A,要修改的新值B。更新一个变量的时候,只有当变量的预期值A和内存地址V当中的实际值相同时,才会将内存地址V对应的值修改为B。
//自旋锁:是指当一个线程在获取锁的时候,如果锁已经被其它线程获取,那么该线程将循环等待,然后不断的判断锁是否能够被成功获取,直到获取到锁才会退出循环。
do {
//获取value,即0
current = this.nextServerCyclicCounter.get();
//取余,为1
next = (current + 1) % modulo;
//进行CAS判断,如果此时在value的内存地址中,如果value和current相同,则为true,返回next的值,否则就一直循环,直到结果为true
} while(!this.nextServerCyclicCounter.compareAndSet(current, next));
return next;
}
public Server choose(Object key) {
return this.choose(this.getLoadBalancer(), key);
}
public void initWithNiwsConfig(IClientConfig clientConfig) {
}
}
8.4.3 手書き: ローカル ロード バランサを自分で書いてみる (ポーリング)
- 前提条件: 原則 + JUC (CAS + スピンロックのレビュー)
- ジュクビデオ: https://www.bilibili.com/video/BV1ar4y1x727/?spm_id_from=333.999.0.0&vd_source=47cc8ff7e1b2b25a9a062c51f8b85d17
1) 7001/7002 クラスタの起動
- 7001 および 7002 クラスターの開始
2) 8001/8002 マイクロサービス変換: コントローラー
- このメソッドを 8001 および 8002 の PaymentController に追加して、カスタム ポーリングをテストします。
//用于测试自定义负载均衡的规则
@GetMapping("/payment/lb")
public String getPaymentLB(){
return serverPort;
}
3) 80 次のマイクロサービス変革
-
ApplicationContextBean はアノテーション @LoadBalance を削除します
- リボンに付属の負荷分散を削除します。機能する場合は、作成した負荷分散構成が成功したことを意味します。
- リボンに付属の負荷分散を削除します。機能する場合は、作成した負荷分散構成が成功したことを意味します。
-
ロードバランサーインターフェース
package com.angenin.springcloud.lb;
import org.springframework.cloud.client.ServiceInstance;
import java.util.List;
public interface LoadBalancer {
//传入具体实例的集合,返回选中的实例
ServiceInstance instances(List<ServiceInstance> serviceInstance);
}
- MyLBインターフェース実装クラス
package com.angenin.springcloud.lb;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
@Component //加入容器
public class MyLB implements LoadBalancer
{
//新建一个原子整形类
private AtomicInteger atomicInteger = new AtomicInteger(0);
public final int getAndIncrement() {
int current;
int next;
do {
current = this.atomicInteger.get();
//如果current是最大值,重新计算,否则加1(防止越界)
next = current >= 2147483647 ? 0 : current + 1;
//进行CAS判断,如果不为true,进行自旋
}while(!this.atomicInteger.compareAndSet(current,next));
System.out.println("*****第几次访问,次数next: "+next);
return next;
}
//负载均衡算法:rest接口第几次请求数 % 服务器集群总数量 = 实际调用服务器位置下标 ,每次服务重启动后rest接口计数从1开始。
@Override
public ServiceInstance instances(List<ServiceInstance> serviceInstances)
{
//进行取余
int index = getAndIncrement() % serviceInstances.size();
//返回选中的服务实例
return serviceInstances.get(index);
}
}
- オーダーコントローラー
@Resource
private LoadBalancer loadBalancer;
@Resource
private DiscoveryClient discoveryClient;
//测试自己写的负载均衡
@GetMapping("/consumer/payment/lb")
public String getPaymentLB(){
//获取CLOUD-PAYMENT-SERVICE服务的所有具体实例
List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
if(instances == null || instances.size() <= 0){
return null;
}
ServiceInstance serviceInstance = loadBalancer.instances(instances);
URI uri = serviceInstance.getUri();
System.out.println(uri);
return restTemplate.getForObject(uri + "/payment/lb", String.class);
}
- 测试:http://localhost/consumer/payment/lb
- まずサービスを開始してください
- 効果: 私が作成したポーリング負荷ルールは正常にテストされました。
- まずサービスを開始してください
- コンソール
9 OpenFeign サービス インターフェイスの呼び出し
9.1 概要
9.1.1 OpenFeignとは
公式 Web サイトのドキュメントには次のように説明されています。
-
https://cloud.spring.io/spring-cloud-static/Hoxton.SR1/reference/htmlsingle/#spring-cloud-openfeign
-
Feign は宣言型 WebService クライアントです。Feign を使用すると、Web サービス クライアントの作成が容易になります。
-
使い方は です
定义一个服务接口然后在上面添加注解
。Feign は、プラグ可能なエンコーダとデコーダもサポートしています。Spring Cloud は、Spring MVC 標準アノテーションと HttpMessageConverters をサポートするために Feign をカプセル化します。Feign は Eureka およびリボンと組み合わせて負荷分散をサポートできます。
要約:
- Feign は、Web サービス クライアントの作成を非常に簡単にする宣言型 Web サービス クライアントです。
只需创建一个接口并在接口上添加注解即可
- GitHub ソースコード:
https://github.com/spring-cloud/spring-cloud-openfeign
9.1.2 何ができるのですか?
-
フェイグには何ができるでしょうか?
- Feign は、Java Http クライアントの作成を容易にすることを目的としています。
- 以前にリボン+RestTemplate を使用したときは、RestTemplate を使用して http リクエストをカプセル化し、テンプレート化された呼び出しメソッドのセットを形成しました。ただし、実際の開発では、サービスの依存関係が複数の場所で呼び出される可能性があるため、
往往一个接口会被多处调用,所以通常都会针对每个微服务自行封装一些客户端类来包装这些依赖服务的调用
. したがって、Feign はこれに基づいてそれをさらにカプセル化し、依存するサービス インターフェイスの定義と実装を支援します。Feign の実装では我们只需创建一个接口并使用注解的方式来配置它(以前是Dao接口上面标注Mapper注解,现在是一个微服务接口上面标注一个Feign注解即可
、サービス プロバイダーへのインターフェイス バインディングを完了でき、Spring クラウド リボンを使用するときにサービス呼び出しクライアントを自動的にカプセル化する開発作業が簡素化されます。
-
フェーンはリボンを統合します
- リボンは、Payment のサービス リスト情報を維持するために使用され、クライアントの負荷分散はポーリングによって実装されます。リボンとの違いは、
通过feign只需要定义服务绑定接口且以声明式的方法
サービス呼び出しをエレガントかつシンプルに実装していることです。
- リボンは、Payment のサービス リスト情報を維持するために使用され、クライアントの負荷分散はポーリングによって実装されます。リボンとの違いは、
9.1.3 Feign と OpenFeign の違い
9.2 OpenFeign の使用手順
- マイクロサービス呼び出しインターフェイス+@FeignClient
- マイクロサービス呼び出しインターフェイス: プロバイダーと呼び出し元を一致させるインターフェイス
- 消費者側で偽装が使用される
- 建築
9.2.1 新しいクラウド消費者偽装注文80の作成
9.2.2 POM
- OpenFeign の古いバージョンにはリボンも統合されていますが、新しいバージョンには統合されていないことがわかります。
<?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-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>
<!--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>
9.2.3 YML
- OpenFeign はマイクロサービスとして eureka に登録するのではなく、単なるクライアントです。
server:
port: 80
eureka:
client:
register-with-eureka: false
service-url: # 配置服务中心,openFeign去里面找服务
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/
9.2.4 メイン起動
package com.angenin.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
@EnableFeignClients //使用feign,激活并开启
@SpringBootApplication
public class OrderFeignMain80 {
public static void main(String[] args) {
SpringApplication.run(OrderFeignMain80.class, args);
}
}
9.2.5 ビジネスクラス
1) 新しい PaymentFeignService インターフェースを作成し、注釈 @FeignClient を追加します
- ビジネス ロジック インターフェイス + @FeignClient 構成はプロバイダー サービスを呼び出します
package com.angenin.springcloud.service;
import com.angenin.springcloud.entities.CommonResult;
import com.angenin.springcloud.entities.Payment;
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-PAYMENT-SERVICE")
public interface PaymentFeignService {
//调用8001的控制层方法
@GetMapping(value = "/payment/get/{id}")
public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id);
}
2) 制御層Controller
package com.angenin.springcloud.controller;
import com.angenin.springcloud.entities.CommonResult;
import com.angenin.springcloud.entities.Payment;
import com.angenin.springcloud.service.PaymentFeignService;
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;
@Slf4j
@RestController
public class OrderFeignController {
@Resource
private PaymentFeignService paymentFeignService;
@GetMapping("/consumer/payment/get/{id}")
public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id){
return paymentFeignService.getPaymentById(id);
}
}
9.2.6 テスト
- 最初に 2 つの eureka クラスター 7001/7002 を開始します。
- さらに 2 つのマイクロサービス 8001/8002 を開始します
- クラウド消費者偽装注文80を開始する
- http://localhost/consumer/payment/get/4
- Feign には独自の負荷分散構成アイテムであるリボンが付属しています
- Feign には独自の負荷分散構成アイテムであるリボンが付属しています
9.2.7 概要
9.3 OpenFeign タイムアウト制御
- 注: コンシューマーは 2 つの異なるマイクロサービスであるプロデューサーを呼び出します。そのため、タイムアウト現象が発生するはずです。
- 例: プロバイダーはサービスの処理に 3 秒かかります。プロバイダーは 3 秒が正常であると考えていますが、コンシューマーは 1 秒しか待ちません。1 秒後、プロバイダーはデータを返さず、コンシューマーは問題を引き起こす可能性があります。タイムアウト呼び出しエラー。
- したがって、双方が時刻について合意する必要があり、デフォルトの時刻を使用しないでください。
9.3.1 タイムアウト設定、エラー状態を示すために意図的にタイムアウトを設定する
- サービスプロバイダー8001が意図的に一時停止プログラムを作成
//测试OpenFeign超时控制
@GetMapping("/payment/feign/timeout")
public String paymentFeignTimeout(){
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
return serverPort;
}
- サービスコンシューマ80はタイムアウトメソッドPaymentFeignServiceを追加します
@GetMapping(value = "/payment/feign/timeout")
public String paymentFeignTimeout();
- サービスコンシューマ80はタイムアウトメソッドOrderFeignControllerを追加します
@GetMapping("/consumer/payment/feign/timeout")
public String paymentFeignTimeout(){
//openFeign底层是---ribbon,客户端(消费者)一般默认等待1秒
return paymentFeignService.paymentFeignTimeout();
}
- テスト
-
開始 7001、7002、プロバイダー 8001、コンシューマー クラウド-コンシューマー-フェイン-オーダー80
-
http://localhost/consumer/payment/feign/timeout
-
エラーページ
-
9.3.2 とは
- OpenFeign はデフォルトで 1 秒待機し、制限時間を超えるとエラーを報告します。
- デフォルトでは、Feign クライアントは 1 秒しか待機しませんが、サーバー側の処理には 1 秒以上かかるため、Feign クライアントはそれ以上待機せず、直接エラーを返します。このような状況を避けるために、Feign クライアントのタイムアウト制御を設定する必要がある場合があります。
- OpenFeign はデフォルトでリボンをサポートし (バージョン 3 以降のバージョンでは廃止されました)、そのタイムアウト制御も最下位レベルのリボンによって制限されます。
9.3.3 OpenFeign クライアントのタイムアウト制御を YML ファイルで有効にする必要がある
#设置feign客户端超时时间(OpenFeign默认支持ribbon)(单位:毫秒)
ribbon:
#指的是建立连接所用的时间,适用于网络状况正常的情况下,两端连接所用的时间
ConnectTimeout: 5000
#指的是建立连接后从服务器读取到可用资源所用的时间
ReadTimeout: 5000
- テストのために 80 を再起動します: http://localhost/consumer/payment/feign/timeout
9.4 OpenFeignログ印刷機能
- Feign はログ出力機能を提供しており、Feign での HTTP リクエストの詳細を理解するために設定を通じてログ レベルを調整できます。
说白了就是对Feign接口的调用情况进行监控和输出
- ログレベル:
- NONE: デフォルト、ログは表示されません。
- BASIC: リクエストメソッド、URL、レスポンスステータスコード、実行時間のみを記録します。
- HEADERS: BASIC で定義された情報に加えて、リクエストおよびレスポンスのヘッダー情報もあります。
- FULL: HEADERS で定義された情報に加えて、リクエストとレスポンスの本文とメタデータもあります。
テスト手順:
- ロギング Bean を構成する
package com.angenin.springcloud.config;
import feign.Logger; //不要导错包
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FeignConfig {
@Bean
Logger.Level feignLoggerLevel(){
//打印最详细的日志
return Logger.Level.FULL;
}
}
- YML ファイルのログを有効にする必要がある偽クライアント
#开启日志的feign客户端
logging:
level:
#feign日志以什么级别监控哪个接口
com.angenin.springcloud.service.PaymentFeignService: debug #写你们自己的包名
- バックグラウンド ログ ビュー: 再起動 80