Spring Cloud Gateway – API Gateway

TL;DR: Spring Cloud Gateway to nowe rozwiązanie API Gateway w ekosystemie Spring Cloud, które zastępuje Netflix Zuul. Oferuje reactive programming model, lepszą wydajność oraz elastyczne mechanizmy routingu i filtrowania dla architektury mikrousług.

Dlaczego potrzebujesz API Gateway?

W architekturze mikrousług klienci muszą komunikować się z wieloma niezależnymi serwisami. Bez API Gateway każdy klient musiałby znać adresy wszystkich mikrousług, obsługiwać autoryzację osobno dla każdego serwisu i radzić sobie z różnymi protokołami. API Gateway rozwiązuje te problemy, działając jako pojedynczy punkt wejścia do całego systemu.

Co się nauczysz:

  • Czym jest Spring Cloud Gateway i jak się różni od Zuul
  • Jak skonfigurować podstawowy routing
  • Jak używać predykatów i filtrów
  • Jak implementować load balancing
  • Jak dodać monitoring i logowanie
  • Jak zabezpieczyć API Gateway
Wymagania wstępne: Znajomość Spring Boot, podstawy mikrousług, pojęcie reactive programming (WebFlux), doświadczenie z Spring Cloud.

Spring Cloud Gateway vs Netflix Zuul

Spring Cloud Gateway to następca Netflix Zuul w ekosystemie Spring Cloud. Podczas gdy Zuul 1.x jest oparty na blocking I/O, Gateway wykorzystuje reactive programming model z Spring WebFlux.

AspektNetflix Zuul 1.xSpring Cloud Gateway
Model programowaniaBlocking (Servlet API)Reactive (WebFlux)
WydajnośćOgraniczona przez thread poolWyższa – non-blocking I/O
KonfiguracjaJava Config + PropertiesFluent API + YAML
EkosystemNetflix OSSSpring Cloud native
PrzyszłośćMaintenance modeAktywny rozwój
Netflix Zuul 2.x również oferuje reactive model, ale Spring Cloud Gateway zapewnia lepszą integrację z ekosystemem Spring i jest oficjalnie wspieranym rozwiązaniem.

Konfiguracja projektu

Aby rozpocząć pracę ze Spring Cloud Gateway, dodaj odpowiednie zależności do pom.xml:

<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-eureka-client</artifactId>
    </dependency>
</dependencies>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Finchley.RC1</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
Uwaga: Spring Cloud Gateway wymaga Spring Boot 2.0+ i nie jest kompatybilny z tradycyjnymi aplikacjami webowymi opartymi na Spring MVC. Używa wyłącznie reactive stack.

Podstawowa konfiguracja routingu

Routing w Spring Cloud Gateway konfiguruje się przez application.yml. Każda reguła routingu składa się z trzech elementów: predicate, filter i URI docelowego.

spring:
  cloud:
    gateway:
      routes:
      - id: user-service
        uri: http://localhost:8081
        predicates:
        - Path=/api/users/**
        filters:
        - StripPrefix=2
        
      - id: order-service
        uri: http://localhost:8082
        predicates:
        - Path=/api/orders/**
        - Method=GET,POST
        filters:
        - AddRequestHeader=X-Request-Source, gateway
        
      - id: payment-service
        uri: lb://payment-service
        predicates:
        - Path=/api/payments/**
        filters:
        - CircuitBreaker=paymentCircuitBreaker
Predicate – warunek który musi być spełniony aby żądanie zostało przekierowane do danego serwisu. Filter – modyfikacja żądania lub odpowiedzi przed/po przekierowaniu.

Predykaty (Predicates)

Spring Cloud Gateway oferuje bogaty zestaw wbudowanych predykatów do dopasowywania żądań:

spring:
  cloud:
    gateway:
      routes:
      - id: advanced-routing
        uri: http://localhost:8083
        predicates:
        # Ścieżka URL
        - Path=/api/v1/**
        # Metoda HTTP
        - Method=GET,POST
        # Nagłówek HTTP
        - Header=X-Request-Id, \d+
        # Query parameter
        - Query=version, v1
        # Czas - żądania między 9:00 a 17:00
        - Between=9:00,17:00
        # Host header
        - Host=api.example.com
        # Remote address
        - RemoteAddr=192.168.1.0/24
Pro tip: Możesz łączyć wiele predykatów – wszystkie muszą być spełnione (logiczne AND). Dla logiki OR stwórz osobne routes.

Filtry (Filters)

Filtry pozwalają na modyfikację żądań i odpowiedzi. Spring Cloud Gateway dostarcza wiele wbudowanych filtrów:

spring:
  cloud:
    gateway:
      routes:
      - id: filter-example
        uri: http://localhost:8084
        predicates:
        - Path=/api/**
        filters:
        # Usuń prefiksy ze ścieżki
        - StripPrefix=1
        # Dodaj nagłówek do żądania
        - AddRequestHeader=X-Gateway-Name, spring-cloud-gateway
        # Dodaj nagłówek do odpowiedzi  
        - AddResponseHeader=X-Response-Time, ${T(java.time.Instant).now()}
        # Przepisz ścieżkę
        - RewritePath=/api/(?.*), /${segment}
        # Rate limiting
        - RequestRateLimiter=10,1,#{@userKeyResolver}
        # Retry mechanizm
        - Retry=3

Load Balancing z Service Discovery

Spring Cloud Gateway integruje się z Eureka Service Discovery, umożliwiając automatyczne load balancing:

spring:
  application:
    name: api-gateway
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true
          lower-case-service-id: true
      routes:
      - id: user-service-lb
        uri: lb://user-service
        predicates:
        - Path=/users/**
        
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
    fetch-registry: true
    register-with-eureka: true
Prefiks lb:// informuje Gateway o użyciu load balance. Nazwa serwisu musi odpowiadać nazwie zarejestrowanej w Eureka.

Własne filtry

Możesz tworzyć własne filtry implementując GatewayFilter lub GlobalFilter:

@Component
public class LoggingGlobalFilter implements GlobalFilter, Ordered {
    
    private static final Logger logger = LoggerFactory.getLogger(LoggingGlobalFilter.class);
    
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        
        logger.info("Request: {} {} from {}", 
            request.getMethod(), 
            request.getURI().getPath(),
            request.getRemoteAddress());
        
        return chain.filter(exchange).then(Mono.fromRunnable(() -> {
            ServerHttpResponse response = exchange.getResponse();
            logger.info("Response: {} for {}", 
                response.getStatusCode(), 
                request.getURI().getPath());
        }));
    }
    
    @Override
    public int getOrder() {
        return -1; // Wykonuj jako pierwszy
    }
}

Monitoring i Health Checks

Spring Cloud Gateway dostarcza actuator endpoints do monitorowania:

management:
  endpoints:
    web:
      exposure:
        include: health,info,metrics,gateway
  endpoint:
    gateway:
      enabled: true
    health:
      show-details: always
      
spring:
  cloud:
    gateway:
      actuator:
        verbose:
          enabled: true

Dostępne endpoints:

  • /actuator/gateway/routes – lista wszystkich routes
  • /actuator/gateway/filters – dostępne filtry
  • /actuator/gateway/refresh – odświeżenie konfiguracji routes
  • /actuator/metrics – metryki wydajności

Circuit Breaker Pattern

Spring Cloud Gateway integruje się z Hystrix dla implementacji Circuit Breaker pattern:

spring:
  cloud:
    gateway:
      routes:
      - id: circuit-breaker-route
        uri: lb://unreliable-service
        predicates:
        - Path=/api/unreliable/**
        filters:
        - name: CircuitBreaker
          args:
            name: unreliableServiceCB
            fallbackUri: forward:/fallback/unreliable
            
hystrix:
  command:
    unreliableServiceCB:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 3000
      circuitBreaker:
        requestVolumeThreshold: 10
        errorThresholdPercentage: 50
@RestController
public class FallbackController {
    
    @RequestMapping("/fallback/unreliable")
    public Mono<ResponseEntity<String>> fallback() {
        return Mono.just(ResponseEntity.ok()
            .body("{\"message\": \"Service temporarily unavailable\"}"));
    }
}
Pułapka: Circuit Breaker wymaga dodatkowej zależności spring-cloud-starter-netflix-hystrix w pom.xml.

Zabezpieczenia

Spring Cloud Gateway można zabezpieczyć używając Spring Security:

@EnableWebFluxSecurity
@Configuration
public class SecurityConfig {
    
    @Bean
    public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
        return http
            .authorizeExchange(exchanges -> exchanges
                .pathMatchers("/actuator/**").hasRole("ADMIN")
                .pathMatchers("/api/public/**").permitAll()
                .anyExchange().authenticated()
            )
            .oauth2ResourceServer(oauth2 -> oauth2
                .jwt(jwt -> jwt.jwtDecoder(jwtDecoder()))
            )
            .csrf().disable()
            .build();
    }
    
    @Bean
    public ReactiveJwtDecoder jwtDecoder() {
        return ReactiveJwtDecoders.fromIssuerLocation("https://your-auth-server.com");
    }
}

Performance i Best Practices

Pro tip: Spring Cloud Gateway używa Netty jako reactive server. Dostraj parametry JVM: -Dio.netty.allocator.numDirectArenas=0 -Dio.netty.noUnsafe=true dla lepszej wydajności.

Kluczowe parametry konfiguracyjne dla wydajności:

spring:
  cloud:
    gateway:
      httpclient:
        connect-timeout: 1000
        response-timeout: 5s
        pool:
          type: elastic
          max-connections: 1000
          max-idle-time: 15s
      default-filters:
      - name: Retry
        args:
          retries: 3
          statuses: BAD_GATEWAY,SERVICE_UNAVAILABLE
          backoff:
            firstBackoff: 10ms
            maxBackoff: 50ms
Czy Spring Cloud Gateway zastępuje Netflix Zuul?

Tak, Spring Cloud Gateway to oficjalny następca Netflix Zuul w ekosystemie Spring Cloud. Oferuje lepszą wydajność dzięki reactive programming model i jest aktywnie rozwijany.

Czy mogę używać Spring MVC z Gateway?

Nie, Spring Cloud Gateway jest oparty wyłącznie na reactive stack (WebFlux) i nie jest kompatybilny z tradycyjnym Spring MVC. Musisz używać reactive programming.

Jak debugować problemy z routingiem?

Włącz debug logi: logging.level.org.springframework.cloud.gateway=DEBUG i użyj actuator endpoint /actuator/gateway/routes do sprawdzenia aktywnych reguł.

Jaka jest wydajność Gateway vs Zuul?

Spring Cloud Gateway oferuje znacznie lepszą wydajność dzięki non-blocking I/O. W testach benchmarkowych obsługuje 2-3x więcej żądań na sekundę niż Zuul 1.x.

Czy Gateway obsługuje WebSockets?

Tak, Spring Cloud Gateway natywnie obsługuje WebSocket proxying. Skonfiguruj route z predykatem – Path=/websocket/** i Gateway automatycznie obsłuży upgrade connection.

Jak obsłużyć CORS w Gateway?

Użyj wbudowanego filtru: – DedupeResponseHeader=Access-Control-Allow-Origin lub skonfiguruj globalnie w spring.cloud.gateway.globalcors.

Czy można dynamicznie zmieniać routes?

Tak, możesz programowo dodawać/usuwać routes używając RouteDefinitionRepository lub odświeżyć konfigurację przez actuator endpoint /refresh.

Przydatne zasoby:

🚀 Zadanie dla Ciebie

Stwórz API Gateway który routuje żądania do trzech mikrousług: user-service, order-service i notification-service. Dodaj rate limiting, basic authentication, circuit breaker dla notification-service oraz custom filter logujący wszystkie żądania. Przetestuj load balancing z wieloma instancjami jednego serwisu.

Czy planujesz migrację z Netflix Zuul na Spring Cloud Gateway? Jakie są twoje główne obawy dotyczące reactive programming w kontekście API Gateway? Podziel się swoimi doświadczeniami w komentarzach!

Zostaw komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *

Przewijanie do góry