Spring Cloud Gateway の核心机制と路由設定実践

マイクロサービスゲートウェイの選定:Zuul から Spring Cloud Gateway へ

マイクロサービスアーキテクチャにおいて、API ゲートウェイは重要なコンポーネントです。かつて Netflix Zuul が標準として広く採用されていましたが、現在は Spring Cloud Gateway への移行が進んでいます。この両者にはどのような違いがあり、なぜ移行が推奨されるのでしょうか。

1. Zuul と Spring Cloud Gateway の比較

1.1 背景とアーキテクチャ

Zuul は Netflix によって開発されたゲートウェイで、Spring Cloud 早期バージョンにおいて統合されていました。一方、Spring Cloud Gateway は Spring チームによってゼロから開発されたプロジェクトであり、Spring Cloud エコシステムの一部です。

Zuul 1.x はブロッキング I/O モデルを採用しており、パフォーマンスに課題がありました。Zuul 2.x では非阻塞 I/O へ移行しましたが、リリースの遅れや安定性の問題もあり、Spring Cloud Gateway が公式の推奨ゲートウェイとして位置づけられました。

1.2 パフォーマンス特性

一般的に Zuul 1.x は阻塞型、Spring Cloud Gateway は非阻塞型(Reactor パターン)と言われます。公式のベンチマークプロジェクト「spring-cloud-gateway-bench」による比較テストでは、以下のような結果が報告されています。

コンポーネント RPS (Requests Per Second)
Spring Cloud Gateway 32213.38
Zuul 1.x 20800.13
Linkerd 28050.76

この結果から、Spring Cloud Gateway は Zuul 1.x と比較して約 1.6 倍のスループットを発揮することが確認できます。

2. Spring Cloud Gateway の概要

Spring Cloud Gateway は、Spring 5.0、Spring Boot 2.0、および Project Reactor を基盤として構築されています。マイクロサービスにおける API 路由管理を統一し、フィルタチェーンを通じてセキュリティ、モニタリング、レート制限などの機能を提供します。

2.1 主要な特徴

  • Spring Framework 5 および Spring Boot 2.0 基于
  • 動的な路由設定
  • Predicate と Filter による細かな制御
  • Hystrix による回路遮断器の統合
  • Spring Cloud DiscoveryClient との連携
  • カスタム Predicate および Filter の作成が容易
  • レート制限およびパス書き換え機能

2.2 主要用語

  • Route(路由): ゲートウェイの基本構成要素。ID、URI、Predicate の集合、Filter の集合で定義されます。
  • Predicate(断言): Java 8 の Predicate 関数。ServerWebExchange を入力とし、HTTP リクエストの属性(ヘッダー、パラメータなど)に基づいて真偽を判定します。
  • Filter(过滤器): GatewayFilter のインスタンス。リクエストまたはレスポンスを加工するために使用されます。

2.3 処理フロー

クライアントからのリクエストは、Gateway Handler Mapping によって一致する Route を検索されます。一致した場合、Gateway Web Handler に送られ、設定された Filter チェーンを経由してバックエンドサービスへ転送されます。Filter は「pre」(プロキシ前)と「post」(プロキシ後)のフェーズで実行可能です。

3. 実装ガイド

Spring Cloud Gateway の設定には、YAML ファイルによる宣言的な方法と、Java コードによる Bean 定義の方法の 2 通りがあります。維持性の観点から、YAML 設定が推奨されます。

3.1 依存関係の定義

プロジェクトの POM ファイルには、WebFlux を含むゲートウェイstarter を追加します。従来の Web モジュールは不要です。

<?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>cloud-native-platform</artifactId>
        <groupId>com.example.microservices</groupId>
        <version>1.0.0</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>edge-service</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>
    </dependencies>
</project>

3.2 YAML による路由設定

application.yml にて路由ルールを定義します。

server:
  port: 8080

spring:
  application:
    name: edge-gateway
  cloud:
    gateway:
      routes:
        - id: external_site_route
          uri: https://httpbin.org
          predicates:
            - Path=/proxy/**
          filters:
            - StripPrefix=1

この設定により、http://localhost:8080/proxy/get へのアクセスは https://httpbin.org/get へ転送されます。

3.3 Java コードによる設定

RouteLocator Bean を定義することで、プログラム的に路由を制御できます。

@SpringBootApplication
public class ApiGatewayApp {
    @Bean
    public RouteLocator defineRoutes(RouteLocatorBuilder builder) {
        return builder.routes()
                .route(r -> r.path("/data/**")
                        .filters(f -> f.stripPrefix(1))
                        .uri("https://mockapi.io"))
                .build();
    }

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

4. Route Predicate の活用

Spring Cloud Gateway は、多様な条件に基づいた路由マッチングをサポートしています。内置された Predicate Factory を組み合わせることで、柔軟な制御が可能です。

4.1 時間に基づくマッチング

特定の日時以降、以前、または期間内のリクエストのみを許可できます。

spring:
  cloud:
    gateway:
      routes:
       - id: time_limited_route
         uri: http://backend-service.local
         predicates:
          - After=2023-01-01T00:00:00+09:00[Asia/Tokyo]

After は指定時刻以降、Before は以前、Between は期間内を意味します。タイムゾーンは Asia/Tokyo 等形式で指定可能です。

4.2 Cookie によるマッチング

特定の Cookie 名とその値(正規表現)が一致する場合に路由されます。

spring:
  cloud:
    gateway:
      routes:
         - id: auth_cookie_route
           uri: http://backend-service.local
           predicates:
           - Cookie=session_id, valid_.*

テスト例:curl http://localhost:8080 --cookie "session_id=valid_123"

4.3 ヘッダー属性によるマッチング

HTTP ヘッダーの値を条件にできます。

spring:
  cloud:
    gateway:
      routes:
      - id: trace_header_route
        uri: http://backend-service.local
        predicates:
        - Header=X-User-Type, admin

テスト例:curl http://localhost:8080 -H "X-User-Type: admin"

4.4 ホスト名によるマッチング

Host ヘッダーのドメイン名をパターンマッチングします。

spring:
  cloud:
    gateway:
      routes:
      - id: subdomain_route
        uri: http://backend-service.local
        predicates:
        - Host=*.service.local

4.5 HTTP メソッドによるマッチング

GET、POST などの HTTP メソッドでフィルタリングします。

spring:
  cloud:
    gateway:
      routes:
      - id: write_operation_route
        uri: http://backend-service.local
        predicates:
        - Method=POST,PUT

4.6 パスによるマッチング

URI パスをパターンで匹配します。

spring:
  cloud:
    gateway:
      routes:
      - id: versioned_api_route
        uri: http://backend-service.local
        predicates:
        - Path=/api/{version}/**

例:/api/v1/users は匹配しますが、/api/users は匹配しません。

4.7 クエリパラメータによるマッチング

クエリパラメータの存在または値を条件にします。

spring:
  cloud:
    gateway:
      routes:
      - id: feature_flag_route
        uri: http://backend-service.local
        predicates:
        - Query=enable_feature, true

テスト例:curl localhost:8080?enable_feature=true

4.8 IP アドレスによるマッチング

リモートアドレスの CIDR ブロックを指定します。

spring:
  cloud:
    gateway:
      routes:
      - id: internal_network_route
        uri: http://backend-service.local
        predicates:
        - RemoteAddr=10.0.0.1/8

4.9 複数条件の組み合わせ

複数の Predicate を同時に設定できます。この場合、すべての条件を満たす必要があります。

spring:
  cloud:
    gateway:
      routes:
       - id: complex_rule_route
         uri: http://backend-service.local
         predicates:
         - Host=api.service.local
         - Path=/secure/**
         - Method=GET
         - Header=X-Auth-Token, \w+
         - Query=region, jp
         - After=2023-06-01T00:00:00+09:00[Asia/Tokyo]

複数の Route に匹配する可能性がある場合、最初に定義された Route が優先されて処理されます。

タグ: Spring Cloud Gateway Spring WebFlux Microservices Netty API Gateway

7月30日 19:19 投稿