Home > Enterprise >  Strange behaviour server side load balancing in Spring Cloud Gateway with Netflix Eureka
Strange behaviour server side load balancing in Spring Cloud Gateway with Netflix Eureka

Time:12-29

I'm trying to implement server side LB with SpringCloudGateway and Eureka. I have microservices ABC (abc.test.com) and gateway (gateway.test.com) register in eureka (eureka.test.com) by hostname.

If I send request from postman on local machine to gateway.test.com/test/owned then I see in postman console 2 requests instead of 1. Even though I don't have a dependency: spring-cloud-starter-loadbalancer It is look like spring doing client side load balancing instead of server side. Also, not all headers are probably passed through this redirect (like Authorization, which caused final 401).

Gateway routing:

- id: ABC
  uri: lb://ABC
  predicates:
    - Path=/test/**

First:

GET / HTTP/1.1
Authorization: Bearer ****
User-Agent: PostmanRuntime/7.28.2
Accept: */*
Host: gateway.test.com
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
 
HTTP/1.1 301
location: https://abc.test.com/test/owned
date: Mon, 26 Dec 2022 13:00:54 GMT
server: ******
content-length: 0
cache-control: no-cache, no-store, max-age=0, must-revalidate
pragma: no-cache
expires: 0
x-content-type-options: nosniff
x-frame-options: DENY
x-xss-protection: 1 ; mode=block
referrer-policy: no-referrer
x-envoy-upstream-service-time: 12

Second:

GET /test/owned HTTP/1.1
User-Agent: PostmanRuntime/7.28.2
Accept: */*
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Referer: https://gateway.test.com/test/owned
Host: abc.test.com
Cookie: JSESSIONID=720********
 
HTTP/1.1 401 Unauthorized
vary: Origin,Access-Control-Request-Method,Access-Control-Request-Headers
www-authenticate: Bearer
x-content-type-options: nosniff
x-xss-protection: 1; mode=block
cache-control: no-cache, no-store, max-age=0, must-revalidate
pragma: no-cache
expires: 0
x-frame-options: DENY
content-length: 0
date: Mon, 26 Dec 2022 13:00:59 GMT
x-envoy-upstream-service-time: 5
server: *******

POM:

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>
   <parent>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-parent</artifactId>
      <version>2.7.4</version>
      <relativePath/> <!-- lookup parent from repository -->
   </parent>
   <groupId>com.test</groupId>
   <artifactId>testGateway</artifactId>
   <version>0.0.1-SNAPSHOT</version>
   <properties>
      <java.version>18</java.version>
      <spring-cloud.version>2021.0.1</spring-cloud.version>
   </properties>
   <dependencies>
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-oauth2-client</artifactId>
      </dependency>
      <dependency>
         <groupId>org.springframework.cloud</groupId>
         <artifactId>spring-cloud-starter-gateway</artifactId>
      </dependency>
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
         <scope>compile</scope>
      </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>${spring-cloud.version}</version>
            <type>pom</type>
            <scope>import</scope>
         </dependency>
      </dependencies>
   </dependencyManagement>


   <build>
      <plugins>
         <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
         </plugin>
      </plugins>
   </build>

</project>

When I run services in localhost - let's say gateway 8080, abc 8081, eureka 8082 and then send request via gateway it's seems working (only 1 request is in postman console, without client visible redirect).

When I change gateway routing from lb://ABC direct to https://abc.test.com than it seems to working to - but this workaround cannot be accepted, because of killing microservices responsibility.

What I want to achieve is full server-side load balancing -> every client making request via gateway should not know what/where gateway service call.

CodePudding user response:

For future seekers: This behavior was due to http -> https redirect. My services were registered in eureka as http -> spring cloud gateway load balancer get from eureka http address and execute request -> then redirect was executed by PAAS (I am using railway.app) to https domain (which cause losing headers and force doing it on client side).

Fix: Properly register microservice in eureka for https (first four are the most matter):

eureka.instance.nonSecurePort=80
eureka.instance.nonSecurePortEnabled=false
eureka.instance.securePortEnabled=true
eureka.instance.securePort=443
eureka.instance.preferIpAddress=false
eureka.instance.hostname=abc.test.com
eureka.instance.statusPageUrl='https://abc.test.com/info'
eureka.instance.healthCheckUrl='https://abc.test.com/health'
eureka.instance.homePageUrl='https://abc.test.com/'
  • Related