序論
こんにちは、しばらくぶりです。数ヶ月間お休みしていたのですが、小年(旧正月)に再び戻ってきました!
最近のプロジェクトではアーキテクチャの最適化が必要となり、あるビジネスモジュールが急速に成長しているため、それを独立したサービスとして切り出すことを検討しています。
以前にもサービス分割に関する記事を書いたことがあります:「毎日Architectureを学ぶ:サービス分割と移行」
設計段階において、共通APIの移行という難しい課題に直面しました。共通APIとは複数のビジネスモジュールで共有されるインターフェースであり、通常はパラメータによって業務種別を区別します。
当初考えた解決策としては、ゲートウェイ層がカスタムなパラメータルーティングルールをサポートすることを検討しました(前提として、マイクロサービスにゲートウェイ層がある必要があります)。
しかし、ゲートウェイ担当者はこの機能は実装されていないと答えました。さらに、共通APIはゲートウェイ層からの呼び出しだけでなく、サービス間の相互呼び出しも含まれており、その場合はゲートウェイを経由しません!
そのため、このアプローチでは後者の問題に対処できません。
また、各サービスで個別にAPIを切り替えて転送する方法も考えられますが、それは実際には不可能です。なぜなら、API数が多く、それぞれのルールも異なるため、手作業での開発量が膨大になってしまうからです。
もしAPIの転送を行うのであれば、ビジネス層で直接ゲートウェイ機能を実装できないでしょうか?
現在のシステムはSpring Cloudフレームワークを使用しており、Spring Cloud Gatewayを使ってゲートウェイ層の機能を簡単に導入できます。加えて、カスタムインターセプターのサポートにより、パラメータに基づくルーティングやグレーゾーンリリースも実現可能です。
本記事では、Spring Cloud Gatewayの基本概念と基本的な設定方法について紹介し、ソースコードを読解してその仕組みを理解します。
本文
概要説明
Spring Cloud Gatewayは、Spring CloudにおけるAPIゲートウェイコンポーネントであり、Spring Framework 5およびSpring Boot 2.0ベースで構築されています。Project Reactor(リアクティブプログラミングモデル)を活用しており、非同期かつブロッキングしないAPIゲートウェイとして、高スループットな環境に適しています。
また、一般的なゲートウェイが持つ機能、例えばルーティング、フィルタリング、レート制限、フェールセーフなども備えています。
Spring Boot 2.0以前はAPIゲートウェイとしてNetflix Zuulが使われていましたが、Spring Cloud Finchley以降ではSpring Cloud Gatewayが推奨されるようになりました。なぜこのような変更が起こったのでしょうか?
両者の違いを比較してみましょう。GPTによる回答を以下に示します:
Spring Cloud Gateway と Zuul はどちらもマイクロサービスアーキテクチャでよく使われるAPIゲートウェイですが、デザイン理念、パフォーマンス、機能面でいくつかの違いがあります。主な比較ポイントは以下の通りです:
- アーキテクチャとパフォーマンス:
- Zuul 1.x はServlet 2.5に基づいており、同期・ブロッキング方式です。WebSocketなどの長時間接続をサポートしていません。
- Spring Cloud Gateway はSpring WebFluxを基盤としており、非同期・非ブロッキングなリクエスト処理をサポートし、WebSocketにも対応しており、高并发環境に適しています。
- プログラミングモデル:
- Zuul 1.x は従来のServletモデルを利用します。
- Spring Cloud Gateway はリアクティブプログラミングに対応しており、WebFluxフレームワークを活かして非同期かつイベント駆動型のサービス構築が可能です。
- 統合とエコシステム:
- Zuul はNetflixのオープンソースプロジェクトで、Spring Cloudとの統合はありますが、Zuul 2.xはSpring Cloudに統合されていません。Zuul 2.xはNettyベースで非同期非ブロッキングをサポートします。
- Spring Cloud Gateway はSpring Cloudのサブプロジェクトであり、Springエコシステムと密接に連携しており、より良い開発体験を提供します。
- パフォーマンス最適化:
- Zuul 1.x はパラメータ調整によって改善可能ですが、Spring Cloud Gateway は非同期非ブロッキングの特徴により、最適化なしでも高い性能を維持できます。
- 機能と拡張性:
- Zuul は基本的なルーティングとフィルタリング機能しか提供していませんが、コミュニティの活発さや拡張性は低いです。
- Spring Cloud Gateway は豊富なルーティングやフィルタの拡張ポイントを提供し、カスタマイズが容易です。
- コミュニティと保守:
- Zuul 1.x はコミュニティ活動が少なく、NetflixはZuul 2.xをリリースしていますが、Spring Cloudでは統合計画はありません。
- Spring Cloud Gateway はSpringコミュニティの積極的なメンテナンスとアップデートが行われています。
- サービス間通信:
- Zuul 1.x はブロッキングI/OベースのAPIゲートウェイであるため、パフォーマンスが低くなります。
- Spring Cloud Gateway は非同期通信をサポートし、システム全体のスループットと応答性を向上させます。
コアコンセプト
ルート(Route)
ルートはゲートウェイの基本構成要素であり、クライアントからのリクエストがバックエンドサービスへどのように転送されるかを定義します。ルートには1つ以上の述部(Predicate)とフィルタ(Filter)リストが含まれ、リクエストをマッチさせて目的のサービスに転送します。
述部(Predicate)
リクエストがルートに一致するかどうかを判定します。Spring Cloud Gatewayはリクエストヘッダ、HTTPメソッド、パスなどをチェックするための組み込み述部を提供します。
フィルタ(Filter)
ルーティング中にリクエストとレスポンスを処理するために使用されます。例えば、ヘッダの修正、ログ記録、認証などが可能です。開発者はカスタムフィルタを追加したり、既存のフィルタを利用したりできます。
サンプルコード
サンプルリポジトリ:https://github.com/Zhang-BigSmart/spring-clould-gateway-demo
spring-cloud-gateway-demo-eureka:サービス登録センター。マイクロサービスの管理を行います。spring-cloud-gateway-demo-api:ゲートウェイサービス。リクエストのルーティングを担当します。spring-cloud-gateway-demo-server:APIを提供するサービス。ゲートウェイの転送先となります。
主な注目点はspring-cloud-gateway-demo-apiモジュールです。必要な依存関係を追加します。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
application.yamlでルーティングルールを設定します。例えば、routeIDがpayment_routeの場合、パスが/test/**かつGETリクエストであれば、localhost:8080にリクエストを転送します。
つまり、GET: localhost:8111/test/paymentのリクエストはlocalhost:8080/test/paymentに転送されます。
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
server:
port: 8111
spring:
main:
web-application-type: reactive