マイクロメータートレーシングとSpring Cloud Gatewayの実装

分散トレーシングの基礎と実装

マイクロサービス環境では、単一リクエストが複数サービスを経由するため、エンドツーエンドの可視化が不可欠です。Spring Cloud Sleuthはメンテナンスモードとなり、現在はMicrometer Tracingが標準ソリューションとして採用されています。

トレーシングの仕組み

トレースIDとスパンIDでリクエスト経路を特定します。例として、order-servicepayment-serviceinventory-service の呼び出しチェーンを想定:

  • トレースID: 全経路を一意に識別(例: 7b3e9a1c4f2d
  • スパンID: 個々のサービス呼び出し単位(例: payment-service が生成する 4a8f2b
  • 親スパンID: 呼び出し元を参照(payment-service のスパンは order-service のスパンIDを親として保持)

Zipkinとの連携構成

ZipkinサーバーをDockerで起動する例:

docker run -d --name zipkin -p 9412:9411 openzipkin/zipkin

実装コードの再構築

親モジュールの依存関係定義(バージョン管理):

<properties>
  <micrometer.version>1.12.0</micrometer.version>
  <brave.version>5.17.0</brave.version>
</properties>

<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>io.micrometer</groupId>
      <artifactId>micrometer-tracing-bom</artifactId>
      <version>${micrometer.version}</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
  </dependencies>
</dependencyManagement>

サービスモジュールの実装例:

@RestController
public class OrderTraceController {
    @GetMapping("/api/v1/order/{id}")
    public TraceResponse traceOrder(@PathVariable String id) {
        return new TraceResponse(
            "Order processed: " + id,
            IdUtil.fastSimpleUUID()
        );
    }
    
    record TraceResponse(String message, String traceId) {}
}

構成設定の最適化

application.ymlのトレース設定:

management:
  tracing:
    sampling:
      probability: 0.8 # デフォルト0.1より高頻度で収集
  zipkin:
    tracing:
      endpoint: http://localhost:9412/api/v2/spans

Spring Cloud Gatewayの高度な活用

Zuulに代わる次世代APIゲートウェイで、ルーティング・フィルタリングの中心的役割を担います。

基本構成要素

  • Route: ID/URI/述語/フィルタで構成される基本単位
  • Predicate: リクエスト条件(例: パス・ヘッダ・時刻)
  • Filter: リクエスト/レスポンス処理(前処理/後処理)

動的サービスディスカバリの実装

固定URIではなくサービス名によるルーティング:

spring:
  cloud:
    gateway:
      routes:
        - id: order_route
          uri: lb://order-service
          predicates:
            - Path=/api/v1/order/**
          filters:
            - AddRequestHeader=X-Correlation-ID, {traceId}

カスタム述語の実装

会員ランクによるアクセス制御の例:

@Component
public class MemberLevelPredicateFactory extends AbstractRoutePredicateFactory<MemberLevelPredicateFactory.Config> {
    
    public MemberLevelPredicateFactory() {
        super(Config.class);
    }

    @Override
    public Predicate<ServerWebExchange> apply(Config config) {
        return exchange -> {
            String level = exchange.getRequest()
                .getQueryParams()
                .getFirst("membership");
            return level != null && level.equals(config.requiredLevel);
        };
    }

    @Validated
    public static class Config {
        @NotEmpty
        private String requiredLevel;
        // getter/setter
    }
}

グローバルフィルタの実装

リクエスト処理時間計測の例:

@Component
public class TimingFilter implements GlobalFilter, Ordered {
    
    private static final String START_TIME = "start_time";
    
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        exchange.getAttributes().put(START_TIME, System.currentTimeMillis());
        return chain.filter(exchange).then(Mono.fromRunnable(() -> {
            long duration = System.currentTimeMillis() - exchange.getAttribute(START_TIME);
            log.info("Request {} completed in {}ms", 
                exchange.getRequest().getURI(), duration);
        }));
    }

    @Override
    public int getOrder() {
        return Ordered.HIGHEST_PRECEDENCE;
    }
}

ヘッダ操作フィルタの応用

セキュリティヘッダの動的設定:

filters:
  - SetRequestHeader=X-Security-Context, {#request.remoteAddress}
  - RemoveResponseHeader=Server
  - AddResponseHeader=X-Content-Type-Options, nosniff

タグ: micrometer-tracing brave zipkin spring-cloud-gateway

6月5日 18:10 投稿