Chuyển đến nội dung chính

レッスン 22: マイクロサービス — サービス ディスカバリと API ゲートウェイ

Spring Boot を使用したマイクロサービス アーキテクチャ。 Consul/Eureka によるサービスディスカバリ。春のクラウドゲートウェイ。 Resilience4j を備えたサーキット ブレーカー。構成サーバー。

💻 プログラミング — レッスン 21 レッスン 22: マイクロサービス — サービス検出 & APIゲートウェイ

Spring Boot 4: 基本から上級まで

パート 6: マイクロサービスとプロダクション

xdev.asia

はじめに

マイクロサービス アーキテクチャは、アプリケーションを小さな独立したサービスに分割します。 Spring Cloud は、実稼働対応のマイクロサービス システムを構築するための完全なツール (Service Discovery、API Gateway、Circuit Breaker、Config Server) を提供します。


1. マイクロサービス アーキテクチャの概要

                    ┌──────────────┐
                    │   Client     │
                    └──────┬───────┘
                           │
                    ┌──────▼───────┐
                    │ API Gateway  │
                    │(Spring Cloud)│
                    └──────┬───────┘
                           │
          ┌────────────────┼────────────────┐
          │                │                │
   ┌──────▼──────┐ ┌──────▼──────┐ ┌──────▼──────┐
   │ Order       │ │ Product     │ │ User        │
   │ Service     │ │ Service     │ │ Service     │
   └──────┬──────┘ └──────┬──────┘ └──────┬──────┘
          │                │                │
          ▼                ▼                ▼
     ┌─────────┐    ┌─────────┐     ┌─────────┐
     │Order DB │    │Product  │     │User DB  │
     │(Postgres)│   │DB(Mongo)│     │(Postgres)│
     └─────────┘    └─────────┘     └─────────┘

2. Consul によるサービスの発見

2.1 Consul (Docker) のセットアップ

# docker-compose.yml
services:
  consul:
    image: hashicorp/consul:1.20
    ports:
      - "8500:8500"
    command: agent -server -bootstrap-expect=1 -ui -client=0.0.0.0

2.2 Spring Boot サービスの登録

// build.gradle.kts
implementation("org.springframework.cloud:spring-cloud-starter-consul-discovery")
# application.yml (Product Service)
spring:
  application:
    name: product-service
  cloud:
    consul:
      host: localhost
      port: 8500
      discovery:
        service-name: ${spring.application.name}
        health-check-interval: 10s
        instance-id: ${spring.application.name}:${random.value}

2.3 サービス間の通信

@Configuration
public class RestClientConfig {

    @Bean
    @LoadBalanced
    public RestClient.Builder restClientBuilder() {
        return RestClient.builder();
    }
}

@Service
public class OrderService {

    private final RestClient restClient;

    public OrderService(RestClient.Builder builder) {
        this.restClient = builder
            .baseUrl("http://product-service")  // Tên service, không phải IP
            .build();
    }

    public ProductResponse getProduct(Long productId) {
        return restClient.get()
            .uri("/api/v1/products/{id}", productId)
            .retrieve()
            .body(ProductResponse.class);
    }
}

3. Spring Cloud Gateway を使用した API ゲートウェイ

3.1 ゲートウェイのセットアップ

// build.gradle.kts (Gateway Service)
implementation("org.springframework.cloud:spring-cloud-starter-gateway")
implementation("org.springframework.cloud:spring-cloud-starter-consul-discovery")

3.2 ルート構成

# application.yml
spring:
  application:
    name: api-gateway
  cloud:
    gateway:
      routes:
        - id: product-service
          uri: lb://product-service
          predicates:
            - Path=/api/v1/products/**
          filters:
            - StripPrefix=0
            - name: CircuitBreaker
              args:
                name: productCircuitBreaker
                fallbackUri: forward:/fallback/products

        - id: order-service
          uri: lb://order-service
          predicates:
            - Path=/api/v1/orders/**
          filters:
            - StripPrefix=0

        - id: user-service
          uri: lb://user-service
          predicates:
            - Path=/api/v1/users/**

3.3 グローバルフィルター

@Component
public class LoggingFilter implements GlobalFilter, Ordered {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String requestId = UUID.randomUUID().toString();
        exchange.getRequest().mutate()
            .header("X-Request-Id", requestId);

        log.info("Request: {} {} [{}]",
            exchange.getRequest().getMethod(),
            exchange.getRequest().getPath(),
            requestId);

        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return -1;
    }
}

4. Resilience4j を備えたサーキットブレーカー

4.1 セットアップ

// build.gradle.kts
implementation("org.springframework.cloud:spring-cloud-starter-circuitbreaker-resilience4j")

4.2 構成

resilience4j:
  circuitbreaker:
    instances:
      productService:
        sliding-window-size: 10
        failure-rate-threshold: 50
        wait-duration-in-open-state: 10s
        permitted-number-of-calls-in-half-open-state: 3
        slow-call-duration-threshold: 2s
        slow-call-rate-threshold: 80

  retry:
    instances:
      productService:
        max-attempts: 3
        wait-duration: 1s
        exponential-backoff-multiplier: 2

  timelimiter:
    instances:
      productService:
        timeout-duration: 3s

4.3 コードでの使用

@Service
public class OrderService {

    private final RestClient restClient;
    private final CircuitBreakerFactory circuitBreakerFactory;

    @CircuitBreaker(name = "productService", fallbackMethod = "getProductFallback")
    @Retry(name = "productService")
    public ProductResponse getProduct(Long productId) {
        return restClient.get()
            .uri("/api/v1/products/{id}", productId)
            .retrieve()
            .body(ProductResponse.class);
    }

    // Fallback khi circuit open hoặc service down
    private ProductResponse getProductFallback(Long productId, Throwable t) {
        log.warn("Fallback for product {}: {}", productId, t.getMessage());
        return new ProductResponse(productId, "Unknown Product",
            BigDecimal.ZERO, "N/A");
    }
}

4.4 サーキットブレーカーの状態

      ┌─────────┐   Failure rate > threshold   ┌──────────┐
      │ CLOSED  │ ──────────────────────────►  │   OPEN   │
      │(normal) │                              │(blocking)│
      └────▲────┘                              └────┬─────┘
           │                                        │
           │  Success rate OK          Wait timeout │
           │                                        │
      ┌────┴──────────┐                            │
      │  HALF-OPEN    │ ◄──────────────────────────┘
      │(testing)      │
      └───────────────┘

5. 集中構成

5.1 Spring クラウド構成サーバー

# Config Server application.yml
spring:
  cloud:
    config:
      server:
        git:
          uri: https://github.com/myorg/config-repo
          default-label: main

5.2 クライアント構成

# bootstrap.yml (Client Service)
spring:
  application:
    name: product-service
  config:
    import: optional:configserver:http://localhost:8888

概要

  • マイクロサービス アーキテクチャ: 各サービスは独立しており、独自のデータベースを持ち、REST/gRPC 経由で通信します。
  • サービス検出 (Consul): サービスの自動登録/検出、@LoadBalanced による負荷分散
  • API ゲートウェイ: シングル エントリ ポイント、ルーティング、フィルタリング、サーキット ブレーカーの統合
  • Resilience4j サーキット ブレーカー: フォールバックによる連鎖的な障害からサービスを保護します

演習

  1. Consul サービス ディスカバリを使用して 3 つのマイクロサービス (Order、Product、User) を構築します。サービスをスケーリングするときに負荷分散をテストする
  2. Spring Cloud Gateway のセットアップ: 3 つのサービスへのルーティング、グローバル ロギング フィルター、レート制限
  3. 注文→製品通信用にサーキット ブレーカーを実装: 製品サービスがダウンしたときのテスト フォールバック