Ribbon of spring cloud: load balancing

Keywords: Java Spring Maven xml

Spring Cloud integrates Ribbon and Eureka to realize load balancing of clients.

An example is implemented below, as shown in the figure below.

I. server side

1. Create project

Development tool: IntelliJ idea February 3, 2019
Create a new spring boot project named "cloud server" in IDEA, select 2.1.10 for spring boot version, and check "spring cloud discovery - >
Eureka Server. After creation, the pom.xml configuration file automatically adds the latest stable version dependency of spring cloud. Currently, it is Greenwich.SR3.
The complete content of pom.xml is as follows:

<?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.1.10.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>cloud-server</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>cloud-server</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>Greenwich.SR3</spring-cloud.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </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>

2. Modify the configuration application.yml

server:
  port: 8761
eureka:
  client:
    register-with-eureka: false
    fetch-registry: false

3. Modify the startup code CloudServerApplication.java

Add annotation @ EnableEurekaServer

package com.example.cloudserver;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

@SpringBootApplication
@EnableEurekaServer
public class CloudServerApplication {

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

}

II. Service provider

1. Create project

Create a new spring boot project in IDEA, with the exception of the name "cloud provider", the other steps are the same as above.

2. Modify the configuration application.yml

spring:
  application:
    name: cloud-provider
eureka:
  instance:
    hostname: localhost
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

3. Modify the startup code CloudProviderApplication.java

Add the annotation @ EnableEurekaClient;
Let the class read the console input at startup and decide which port to use to start the server;
Add a controller method for testing.

package com.example.cloudprovider;

//import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.util.Scanner;

@SpringBootApplication
@EnableEurekaClient
@RestController
public class CloudProviderApplication {

    public static void main(String[] args) {
        //SpringApplication.run(CloudProviderApplication.class, args);
        Scanner scan = new Scanner(System.in);
        String port = scan.nextLine();
        new SpringApplicationBuilder(CloudProviderApplication.class).properties("server.port=" + port).run(args);
    }

    @RequestMapping("/")
    public String index(HttpServletRequest request) {
        return request.getRequestURL().toString();
    }
}

III. service caller

1. Create project
Create a new spring boot project in IDEA, with the exception of the name "cloud invoker", and the other steps are the same as above.

2. Modify the configuration application.yml

server:
  port: 9000
spring:
  application:
    name: cloud-invoker
eureka:
  instance:
    hostname: localhost
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

3. Modify the startup code CloudInvokerApplication.java

Add the annotation @ EnableDiscoveryClient.

package com.example.cloudinvoker;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@SpringBootApplication
@EnableDiscoveryClient
public class CloudInvokerApplication {

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

}

4. There are two ways to configure the Ribbon: code and profile

Mode 1: use code
(1) create a new custom load rule class MyRule.java
The load balancer interface of Ribbon defines the operation of the server, which is mainly used for server selection.
Call the getAllServers method of ILoadBalancer to return all servers, here only the first server is returned.

package com.example.cloudinvoker;

import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.Server;

import java.util.List;

public class MyRule implements IRule {

    private ILoadBalancer iLoadBalancer;

    @Override
    public Server choose(Object o) {
        List<Server> servers = iLoadBalancer.getAllServers();
        System.out.println("Custom server rule class, output server information:");
        for(Server s: servers){
            System.out.println(" " + s.getHostPort());
        }
        return servers.get(0);
    }

    @Override
    public void setLoadBalancer(ILoadBalancer iLoadBalancer) {
        this.iLoadBalancer = iLoadBalancer;
    }

    @Override
    public ILoadBalancer getLoadBalancer() {
        return this.iLoadBalancer;
    }
}

(2) create a new Ping class MyPing.java

The load balancer provides a ping mechanism to Ping the server at regular intervals to determine whether the server is alive or not.
The implementation class of the IPing interface is responsible for this work.

package com.example.cloudinvoker;

import com.netflix.loadbalancer.IPing;
import com.netflix.loadbalancer.Server;

public class MyPing implements IPing {

    @Override
    public boolean isAlive(Server server) {
        System.out.println("custom Ping Class, server information:" + server.getHostPort() + ",Status:" + server.isAlive());
        return true;
    }
}

(3) create a new configuration class MyConfig.java

package com.example.cloudinvoker.config;

import com.example.cloudinvoker.MyPing;
import com.example.cloudinvoker.MyRule;
import com.netflix.loadbalancer.IPing;
import com.netflix.loadbalancer.IRule;
import org.springframework.context.annotation.Bean;

public class MyConfig {
    @Bean
    public IRule getRule(){
        return new MyRule();
    }
    @Bean
    public IPing getPing(){
        return new MyPing();
    }
}

(4) create a new configuration class CloudProviderConfig.java

package com.example.cloudinvoker.config;

import org.springframework.cloud.netflix.ribbon.RibbonClient;

@RibbonClient(name = "cloud-provider", configuration = MyConfig.class)
public class CloudProviderConfig {
}

Mode 2: use profile

Comment out the two configuration classes of method 1, and add the following configuration at the end of application.yml

cloud-provider:
  ribbon:
    NFLoadBalancerRuleClassName: com.example.cloudinvoker.MyRule
    NFLoadBalancerPingClassName: com.example.cloudinvoker.MyPing
    listOfServers: http://localhost:8080/,http://localhost:8081/

5. Add controller InvokerController.java

package com.example.cloudinvoker;

import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
@Configuration
public class InvokerController {

    @LoadBalanced
    @Bean
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }

    @RequestMapping(value="/router", method = RequestMethod.GET,produces = MediaType.APPLICATION_JSON_VALUE)
    public String router(){
        RestTemplate restTemplate = getRestTemplate();
        //Call service by name
        String json = restTemplate.getForObject("http://cloud-provider/", String.class);
        return json;
    }
}

6, test

(1) start the server.
(2) start two service providers, and input 8080 and 8081 respectively in the console to start.
(3) start the service caller.
(4) the browser visits http://localhost:9000/router and refreshes the page several times. The results are as follows:

http://localhost:8081/

Service caller project IDEA console timing output:

Custom server rule class, output server information:
 localhost:8081
 localhost:8080
Custom Ping class, server information: localhost:8081, status: true
Custom Ping class, server information: localhost:8080, status: true

Posted by Sesquipedalian on Fri, 15 Nov 2019 01:03:19 -0800