プロジェクトのインポート
- Cloud_demo のデータベースの構成、データベースのアカウントとパスワードを変更すると、プロジェクトが正常に実行できるようになります。プロジェクトの JDK バージョンは 1.8 です。
RestTemplate を使用してサービスを呼び出す
必要
- 注文情報は ordr-service サービスにあり、ユーザー情報は user-service サービスにあります
order-service の ID に基づいて注文クエリ ビジネスを変更します。注文のクエリ中に、注文に含まれる userId に基づいてユーザー情報が取得され、一緒に返されることが必要です。
- したがって、order-service で user-service への http リクエストを開始し、インターフェイス http://localhost:8081/user/{userId} を呼び出す必要があります。
一般的な手順は次のとおりです。
- RestTemplateのインスタンスをSpringコンテナに登録する
- order-service サービスの OrderService クラスの queryOrderById メソッドを変更し、Order オブジェクトの userId に従ってユーザーをクエリします。
- クエリされたユーザーを Order オブジェクトに入力し、一緒に返します
RestTemplate のインスタンスを Spring コンテナーに作成する
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
RestTemplate を使用してリクエストを送信する
@RestController
@RequestMapping("order")
public class OrderController {
@Resource
private RestTemplate restTemplate;
@GetMapping("{orderId}")
public Order queryOrderByUserId(@PathVariable("orderId") Long orderId) {
// 根据id查询订单并返回
Order order = orderService.queryOrderById(orderId);
//查询用户的信息
String url="http://localhost:8081/user/"+order.getUserId();
User user = restTemplate.getForObject(url, User.class);
order.setUser(user);
return order;
}
}
消費者とプロバイダー
サービス呼び出し関係には、次の 2 つの異なる役割があります。
- サービス プロバイダー: ビジネス内の他のマイクロサービスによって呼び出されるサービス。(他のマイクロサービスへのインターフェースを提供します)
- サービスコンシューマ: ビジネス内の他のマイクロサービスを呼び出すサービス。(他のマイクロサービスによって提供される呼び出しインターフェイス)
ただし、サービス プロバイダーとサービス利用者の役割は絶対的なものではなく、ビジネスに対して相対的なものです。
サービス A がサービス B を呼び出し、サービス B がサービス C を呼び出す場合、サービス B の役割は何ですか?
- A が B に電話をかけるビジネスの場合: A はサービス コンシューマ、B はサービス プロバイダーです。
- B が C に電話をかけるビジネスの場合: B はサービス コンシューマ、C はサービス プロバイダーです。
- したがって、サービス B はサービス プロバイダーとサービス コンシューマの両方になることができます。
エウレカレジストリ
サービスをリモートで呼び出すときに発生する可能性のある問題
-
order-service がリモート呼び出しを開始するとき、ユーザー サービス インスタンスの IP アドレスとポートをどのようにして知るのでしょうか?
-
ユーザーサービスインスタンスのアドレスが複数ありますが、order-service を呼び出すときにどのように選択すればよいですか?
-
order-service は、ユーザー サービス インスタンスがまだ正常であるかダウンしているかをどのようにして知るのでしょうか?
エウレカの構造と機能
質問 1: order-service はどのようにして user-service インスタンスのアドレスを知るのでしょうか?
住所情報を取得する手順は次のとおりです。
-
user-serviceサービスインスタンス起動後、eureka-server(エウレカサーバー)に情報を登録します。これをサービス登録といいます
-
eureka-server は、サービス名とサービス インスタンスのアドレス リスト間のマッピング関係を保存します。
-
order-service は、サービス名に基づいてインスタンスのアドレスリストを取得します。これはサービス ディスカバリまたはサービス プルと呼ばれます
質問 2: order-service は、複数の user-service インスタンスから特定のインスタンスをどのように選択しますか?
- order-service は、負荷分散アルゴリズムを使用してインスタンス リストからインスタンス アドレスを選択し、インスタンス アドレスへのリモート呼び出しを開始します。
質問 3: order-service は、特定のユーザー サービス インスタンスがまだ正常であるかダウンしているかをどのようにして知るのでしょうか?
-
ユーザー サービスは、一定の間隔 (デフォルトは 30 秒) で eureka サーバーへのリクエストを開始し、ハートビートと呼ばれる独自のステータスを報告します。
-
一定期間ハートビートが送信されない場合、eureka-server はマイクロサービス インスタンスに障害があるとみなし、そのインスタンスをサービス リストから削除します。order-service がサービスをプルすると、障害のあるインスタンスを削除できます。
注: マイクロサービスはサービス プロバイダーとサービス コンシューマーの両方になることができるため、eureka はサービス登録、サービス検出、その他の機能を eureka-client に均一にカプセル化します。
エウレカの設定プロセス
登録センターを構築する
- Cloud-demo 親プロジェクトの下にサブモジュールを作成します
- Maven プロジェクトを作成し、eureka の依存関係をインポートする
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
</dependencies>
- スタートアップクラスを書く
@SpringBootApplication
@EnableEurekaServer
public class EurekaApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaApplication.class, args);
}
}
- 設定ファイルの書き込み
server:
port: 10086
spring:
application:
name: eureka-server
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:10086/eureka
instance:
prefer-ip-address: true
instance-id: 127.0.0.1:${
server.port}
- サービスを開始する
- マイクロサービスを開始し、ブラウザーでアクセスします: http://127.0.0.1:10086
サービス登録
1) 依存関係を導入する
user-service の pom ファイルに、次の eureka-client 依存関係を導入します。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
2) 構成ファイル
user-service で、application.yml ファイルを変更し、サービス名と eureka アドレスを追加します。
spring:
application:
name: userservice
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:10086/eureka
instance:
prefer-ip-address: true #以IP地址注册到服务中心,相互注册使用IP地址,如果不配置就是机器的主机名
instance-id: 127.0.0.1:${
server.port} # instanceID默认值为主机名+服务名+端口
3) 複数のユーザーサービスインスタンスを開始する
サービスに複数のインスタンスがあるシナリオを示すために、SpringBoot スタートアップ構成を追加し、ユーザー サービスを開始します。
まず、元のユーザー サービスの起動設定をコピーします。
サービスディスカバリ
次に、order-service のロジックを変更します。eureka-server からユーザー サービス情報をプルして、サービス ディスカバリを実現します。
1) 依存関係の導入
前述したように、サービス検出とサービス登録はすべて eureka-client 依存関係にカプセル化されているため、このステップはサービス登録と一致しています。
order-service の pom ファイルに、次の eureka-client 依存関係を導入します。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
2) 構成ファイル
サービス検出では、エウレカ アドレスも知る必要があるため、2 番目のステップはサービス登録と一致しており、エウレカ情報を構成します。
order-service で、application.yml ファイルを変更し、サービス名と eureka アドレスを追加します。
spring:
application:
name: orderservice
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:10086/eureka
instance:
prefer-ip-address: true
instance-id: 127.0.0.1:${
server.port}
3) サービスのプルとロード バランシング
最後に、eureka-server からユーザー サービス サービスのインスタンス リストをプルし、ロード バランシングを実装する必要があります。
ただし、これらのアクションを実行する必要はなく、いくつかの注釈を追加するだけで済みます。
@Configuration
public class RestTemplateConfig {
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
order-service サービスの cn.itcast.order.service パッケージの下にある OrderService クラスの queryOrderById メソッドを変更します。アクセスした URL パスを変更し、IP とポートをサービス名に置き換えます。
@RestController
@RequestMapping("order")
public class OrderController {
@Autowired
private OrderService orderService;
@Resource
private RestTemplate restTemplate;
@GetMapping("{orderId}")
public Order queryOrderByUserId(@PathVariable("orderId") Long orderId) {
// 根据id查询订单并返回
Order order = orderService.queryOrderById(orderId);
//查询用户的信息
// String url="http://localhost:8081/user/"+order.getUserId();
//使用服务名代替
String url = "http://user-service/user/"+order.getUserId();
User user = restTemplate.getForObject(url, User.class);
order.setUser(user);
return order;
}
}
- Spring は、userservice サービス名に基づいて eureka-server 側からインスタンス リストを取得し、負荷分散を完了するのに自動的に役立ちます。
リボンの負荷分散
前節では負荷分散機能を実装するために @LoadBalanced アノテーションを追加しましたが、これはどのような原理でしょうか?
負荷分散の原理
Spring Cloud の最下層では、実際にはリボンと呼ばれるコンポーネントを使用して負荷分散機能を実装しています。
- では、送信したリクエストは明らかに http://userservice/user/1 でしたが、なぜ http://localhost:8081 になったのでしょうか?
ソースコードの追跡
なぜサービス名を入力するだけでアクセスできるのでしょうか?また、事前に IP とポートを取得する必要があります。
- どうやら誰かがサービス名に基づいてサービス インスタンスの IP とポートを取得するのを手伝ってくれたようです。LoadBalancerInterceptor です。このクラスは RestTemplate リクエストをインターセプトし、サービス ID に基づいて Eureka からサービス リストを取得し、負荷分散アルゴリズムを使用して実際のサービス アドレス情報を取得し、サービス ID を置き換えます。
私たちはソースコードの追跡を実施します。
1)ロードバランサーインターセポート
ここでの intercept メソッドがユーザーの HttpRequest リクエストをインターセプトし、いくつかのことを実行することがわかります。
- request.getURI(): リクエスト URI を取得します。この場合は http://user-service/user/8
- originalUri.getHost(): Uri パスのホスト名を取得します。これは実際にはサービス ID、user-service です。
- this.loadBalancer.execute(): サービス ID とユーザー リクエストを処理します。
2) ロードバランサークライアント
コードは次のようなものです:
-
getLoadBalancer(serviceId): サービス ID に基づいて LoadBalancer を取得します。LoadBalancer はサービス ID を取得して eureka からサービス リストを取得し、保存します。
-
getServer(loadBalancer,hint): 組み込みの負荷分散アルゴリズムを使用して、サービス リストから 1 つを選択します。この例では、ポート 8082 のサービスが取得されていることがわかります。
解放された後、再度アクセスして追跡したところ、8081 を取得していることがわかりました。
3) 負荷分散戦略 IRule
要約する
基本的なプロセスは次のとおりです。
-
RestTemplate リクエストをインターセプト http://user-service/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 を取得して、実際のリクエストを開始します。
負荷分散戦略
負荷分散ルールは IRule インターフェイスで定義され、IRule にはさまざまな実装クラスがあります。
さまざまなルールの意味は次のとおりです。
組み込みの負荷分散ルールクラス | ルールの説明 |
---|---|
ラウンドロビンルール | サービス リストをポーリングしてサーバーを選択するだけです。これは、リボンのデフォルトの負荷分散ルールです。 |
可用性フィルタリングルール | 次の 2 種類のサーバーは無視してください。 (1) デフォルトでは、このサーバーが 3 回接続に失敗すると、このサーバーは「短絡」状態に設定されます。短絡状態は 30 秒間続き、再び接続に失敗すると、短絡の継続時間は幾何級数的に増加します。(2) 同時実行性が高すぎるサーバー。サーバーの同時接続数が多すぎる場合、AvailabilityFilteringRule ルールで構成されたクライアントもそれを無視します。同時接続数の上限は、クライアントの ActiveConnectionsLimit プロパティによって<clientName>.<clientConfigNameSpace>. 構成できます。 |
WeightedResponseTimeRule | 各サーバーに重み値を与えます。サーバーの応答時間が長いほど、サーバーの重みは小さくなります。このルールはサーバーをランダムに選択し、この重み値はサーバーの選択に影響します。 |
ゾーン回避ルール | サーバーの選択は、その地域で利用可能なサーバーに基づいて行われます。ゾーンを使用してサーバーを分類します。このゾーンは、コンピューター室、ラックなどとして理解できます。次に、ゾーン内の複数のサービスをポーリングします。 |
BestAvailableルール | ショートサーキットしているサーバーを無視し、同時実行数が低いサーバーを選択します。 |
ランダムルール | 利用可能なサーバーをランダムに選択します。 |
再試行ルール | リトライ機構の選択ロジック |
カスタム負荷分散戦略
負荷分散ルールは、次の 2 つの方法で IRule 実装を定義することで変更できます。
コード メソッド: order-service の OrderApplication クラスで、新しい IRule を定義します。
@Bean
public IRule randomRule(){
return new RandomRule();
}
構成ファイルによる方法: order-service の application.yml ファイルで、新しい構成を追加すると、ルールを変更することもできます。
userservice: # 给某个微服务配置负载均衡规则,这里是userservice服务
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule # 负载均衡规则
通常、デフォルトの負荷分散ルールは変更せずに使用されることに注意してください。
飢えがいっぱい
リボンはデフォルトで遅延読み込みを使用します。つまり、LoadBalanceClient は最初のアクセスまで作成されず、要求時間は非常に長くなります。
プロジェクトの開始時にハングリー ローディングが作成され、最初の訪問の時間が短縮されます。次の構成を通じてハングリー ローディングを有効にします。
ribbon:
eager-load:
enabled: true # 开启饥饿加载
clients:
- userservice # 指定饥饿加载的服务名称
- xxxxservice # 如果需要指定多个,需要这么写
ナコス登録センター
国内企業は一般的に登録センターなどアリババの技術を尊重しており、Spring Cloud アリババも Nacos と呼ばれる登録センターを立ち上げた。
Nacos の理解とインストール
Nacosは Alibaba の製品であり、現在Spring Cloudのコンポーネントです。Eurekaに比べて機能が豊富で、中国での人気が高いです。
- 開発段階では、単一のマシンにインストールできます。
インストールパッケージをダウンロードする
Nacos の GitHub ページには、コンパイルされた Nacos サーバーまたはソース コードをダウンロードするためのダウンロード リンクが提供されています。
GitHub ホームページ: https://github.com/alibaba/nacos
GitHub のリリース ダウンロード ページ: https://github.com/alibaba/nacos/releases
図に示すように:
解凍する
図に示すように、このパッケージを中国語以外のディレクトリに解凍します。
カタログの説明:
- bin: 起動スクリプト
- conf: 設定ファイル
ポート構成
Nacos のデフォルトのポートは 8848 です。コンピュータ上の他のプロセスがポート 8848 を占有している場合は、最初にプロセスを閉じてみてください。
ポート 8848 を占有しているプロセスを閉じることができない場合は、 nacos の conf ディレクトリに入り、構成ファイル内のポートを変更することもできます。
内容を変更します。
起動する
起動は非常に簡単で、bin ディレクトリに入ります。構造は次のとおりです。
次に、次のコマンドを実行します。
-
Windowsコマンド:
startup.cmd -m standalone
実行後の効果は以下の通りです。
アクセス
ブラウザにアドレスを入力します: http://127.0.0.1:8848/nacos:
nacosへのサービス登録
Nacos は SpringCloudAlibaba のコンポーネントであり、SpringCloudAlibaba も SpringCloud で定義されたサービス登録およびサービス検出の仕様に従います。したがって、マイクロサービスに Nacos を使用する場合と Eureka を使用する場合に大きな違いはありません。
主な違いは次のとおりです。
- 依存関係が違う
- サービスアドレスが異なります
依存関係をインポートする
<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>
- 親プロジェクトの
<dependencyManagement>
Alibaba コンポーネントのバージョンを制御する
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
- サービスコンポーネントを必要とするモジュールに、対応する nacos 依存関係を導入します。
- 注: eureka の依存関係をコメントアウトすることを忘れないでください。
nacosアドレスを設定する
user-service と order-service の application.yml に nacos アドレスを追加します。
spring:
cloud:
nacos:
server-addr: localhost:8848
注: eureka のアドレスをコメントアウトすることを忘れないでください。
サービス階層型ストレージ モデル
サービスには複数のインスタンスを含めることができます。たとえば、ユーザー サービスには次のインスタンスを含めることができます。
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 は、同じコンピュータ ルーム内のインスタンスをクラスタに分割します。
つまり、ユーザー サービスはサービスです。サービスには、杭州や上海などの複数のクラスターを含めることができます。各クラスターには複数のインスタンスを含めることができ、図に示すように階層モデルを形成できます。
マイクロサービスが相互にアクセスする場合は、ローカル アクセスの方が高速であるため、できる限り同じクラスター インスタンスにアクセスする必要があります。他のクラスターにアクセスできるのは、クラスターが使用できない場合のみです。例えば:
ユーザーサービス用にクラスターを構成する
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=WH
同一クラスタ優先ロードバランシング
デフォルトの ZoneAvoidanceRule は、同じクラスターの優先順位に基づいて負荷分散を実現できません。
したがって、Nacos は、同じクラスターからインスタンスを優先的に選択できる NacosRule の実装を提供します。
order-service のクラスター情報を構成する
1) 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 は同じクラスター内でランダムに選択され、マシンのパフォーマンスの問題は考慮されません。
そこでNacosではアクセス頻度を制御するための重み設定を用意しており、重みが大きいほどアクセス頻度が高くなります。
nacos コンソールで、user-service のインスタンス リストを見つけ、[編集] をクリックして重みを変更します。
環境隔離
Nacos は、環境分離機能を実装するための名前空間を提供します。
- nacos には複数の名前空間が存在する可能性があります
- 名前空間の下にはグループ、サービスなどが存在する場合があります。
- 異なる名前空間は互いに分離されており、たとえば、異なる名前空間にあるサービスは相互に認識されません。
名前空間の作成
デフォルトでは、すべてのサービス、データ、およびグループは、public という名前の同じ名前空間内にあります。
マイクロサービスの名前空間を構成する
マイクロサービスの名前空間の構成は、構成を変更することによってのみ実現できます。
たとえば、order-service の application.yml ファイルを変更します。
spring:
cloud:
nacos:
server-addr: localhost:8848
discovery:
cluster-name: HZ
namespace: 35d92630-d382-4dab-b659-a7a6c019805f # 命名空间,填ID
この時点で order-service にアクセスすると、名前空間が異なるため userservice が見つからず、コンソールにエラーが報告されます。
ナコスとエウレカの違い
Nacos サービス インスタンスは 2 つのタイプに分類されます。
-
一時インスタンス: インスタンスが一定期間以上ダウンしている場合、サービス リストから削除されます。これがデフォルトのタイプです。
-
非一時インスタンス: インスタンスがダウンしてもサービス リストから削除されず、永続インスタンスと呼ぶこともできます。
サービス インスタンスを永続インスタンスとして構成します。
spring:
cloud:
nacos:
discovery:
ephemeral: false # 设置为非临时实例
Nacos と Eureka の全体的な構造は、サービスの登録、サービスのプル、ハートビートの待機など似ていますが、いくつかの違いもあります。
ナコスとエウレカの共通点
-
どちらもサービスの登録とサービスのプルをサポートします。
-
すべてのサービス プロバイダーの健全性検査のハートビート方式をサポートします。
ナコスとエウレカの違い
- Nacos は、サーバーがプロバイダーのステータスをアクティブに検出することをサポートします。一時インスタンスはハートビート モードを採用し、非一時インスタンスはアクティブ検出モードを採用します。
- 異常なハートビートのある一時的なインスタンスは削除されますが、一時的ではないインスタンスは削除されません。
- Nacos はサービス リスト変更のメッセージ プッシュ モードをサポートしており、サービス リストはよりタイムリーに更新されます。
- Nacos クラスターはデフォルトで AP モードを使用します。クラスター内に非一時インスタンスがある場合は CP モードが使用され、Eureka は AP モードを使用します。
リモート通話を装う
まず、RestTemplate を使用してリモート呼び出しを開始するために使用したコードを見てみましょう。
//String url="http://localhost:8081/user/"+order.getUserId();
User user = restTemplate.getForObject(url, User.class);
次の問題が存在します。
- コードの可読性が低く、プログラミング エクスペリエンスに一貫性がない
- 複雑なパラメータを持つ URL は保守が困難です
Feign は宣言型 http クライアントで、公式アドレスは https://github.com/OpenFeign/feign です。その機能は、http リクエストの送信をエレガントに実装し、上記の問題を解決するのに役立ちます。
Feign が RestTemplate を置き換える
Fegin を使用する手順は次のとおりです。
依存関係を導入する
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
注釈を追加する
order-service のスタートアップ クラスにアノテーションを追加して、Feign の機能を有効にします。
Feign のクライアントを作成する
次の内容を含む新しいインターフェイスを order-service に作成します。
@FeignClient("userservice")
public interface UserClient {
@GetMapping("/{id}")
public User queryById(@PathVariable("id") Long id);
}
このクライアントは主に SpringMVC アノテーションに基づいて、次のようなリモート呼び出し情報を宣言します。
- サービス名: ユーザーサービス
- リクエストメソッド:GET
- リクエストパス:/user/{id}
- リクエストパラメータ: 長い ID
- 戻り値の型: ユーザー
リモート通話インターフェイスのテスト
@RestController
@RequestMapping("order")
public class OrderController {
@Autowired
private OrderService orderService;
@Resource
private UserClient userClient;
@GetMapping("{orderId}")
public Order queryOrderByUserId(@PathVariable("orderId") Long orderId) {
// 根据id查询订单并返回
Order order = orderService.queryOrderById(orderId);
User user = userClient.queryById(orderId);
order.setUser(user);
return order;
}
}
要約する
Feign を使用する手順:
①依存関係を導入する
② @EnableFeignClients アノテーションを追加
③ FeignClientインターフェースを書く
④ RestTemplate の代わりに FeignClient で定義されたメソッドを使用する
カスタム構成
Feign は、次の表に示すように、多くのカスタム構成をサポートできます。
通常の状況では、デフォルト値で十分ですが、これをカスタマイズする場合は、カスタム @Bean を作成してデフォルト Bean をオーバーライドするだけです。
設定ファイルモード
構成ファイルに基づいて偽装のログ レベルを変更すると、単一のサービスを対象にすることができます。
feign:
client:
config:
userservice: # 针对某个微服务的配置
loggerLevel: FULL # 日志级别
または、すべてのサービスの場合:
feign:
client:
config:
default: # 这里用default就是全局配置,如果是写服务名称,则是针对某个微服务的配置
loggerLevel: FULL # 日志级别
ログには 4 つのレベルがあります。
-
NONE: ログ情報を記録しません。これがデフォルト値です。
-
BASIC: 要求されたメソッド、URL、応答ステータス コードと実行時間のみを記録します。
-
HEADERS: BASICをベースに、リクエストとレスポンスのヘッダ情報を追加記録します。
-
FULL: ヘッダー情報、リクエスト本文、メタデータを含む、すべてのリクエストとレスポンスの詳細を記録します。
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 の最下層は http リクエストを開始し、他のフレームワークに依存します。その基礎となるクライアント実装には次のものが含まれます。
-
URLConnection: デフォルトの実装、接続プーリングをサポートしません
-
Apache HttpClient: 接続プーリングをサポート
-
OKHttp: 接続プーリングをサポートします
したがって、Feign のパフォーマンスを向上させる主な手段は、デフォルトの URLConnection の代わりに接続プールを使用することです。
ここでは、Apache の HttpClient を使用してデモンストレーションします。
1) 依存関係を導入する
Apache の HttpClient 依存関係を order-service の pom ファイルに導入します。
<!--httpClient的依赖 -->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
</dependency>
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 # 每个路径的最大连接数
要約、Feign の最適化:
- 1. 基本的なログレベルを使用してみる
- 2. URLConnection の代わりに HttpClient または OKHttp を使用します。
- ① feign-httpClient 依存関係を導入する
- ② 設定ファイルで httpClient 機能を有効にし、接続プールのパラメータを設定します。
ベストプラクティス
いわゆる最近の実践とは、使用中に要約された経験を指し、それを使用するのが最善の方法です。
自己研究による観察から、Feign のクライアントとサービス プロバイダーのコントローラー コードが非常に似ていることがわかります。
偽のクライアント:
ユーザーコントローラー:
この繰り返しのコード記述を簡素化する方法はあるでしょうか?
継承方法
同一のコードは継承を通じて共有できます。
- 1) API インターフェースを定義し、定義メソッドを使用し、SpringMVC アノテーションに基づいて宣言を行います。
- 2) 偽クライアントとコントローラーの両方が変更されたインターフェイスを統合します
アドバンテージ:
-
単純
-
コード共有を有効にしました
欠点:
-
サービスプロバイダーとサービス利用者は密接に結びついています
-
パラメータ リスト内のアノテーション マッピングは継承されないため、メソッド、パラメータ リスト、およびアノテーションをコントローラで再度宣言する必要があります。
抽出方法
Feign のクライアントを独立したモジュールに抽出し、インターフェイスに関連する POJO とデフォルトの Feign 設定をすべてのコンシューマが使用できるようにこのモジュールに配置します。
たとえば、UserClient、User、および Feign のデフォルト構成を 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 プロジェクトにコピーされ、
テストが再開されました
。再起動後、サービスがエラーを報告したことがわかりました。
これは、UserClient が cn.itcast.feign.clients パッケージの下にあるためです。
order-service の @EnableFeignClients アノテーションは、同じパッケージ内ではなく cn.itcast.order パッケージの下にあるため、UserClient をスキャンできません。
パッケージのスキャンの問題を解決する
方法 1:
Feign がスキャンするパッケージを指定します。
@EnableFeignClients(basePackages = "cn.itcast.feign.clients")
方法 2:
ロードする必要があるクライアント インターフェイスを指定します。
@EnableFeignClients(clients = {UserClient.class})