Spring cloud learning 3 (using Ribbon to realize load balancing and customize load balancing algorithm)

1, Ribbon: load balancing (client based)

1.1 load balancing and Ribbon

What is Ribbon?

  • Spring Cloud Ribbon is a set of client-side load balancing tools based on Netflix Ribbon.
  • In short, Ribbon is an open source project released by Netflix. Its main function is to provide software load balancing algorithms for clients and connect Netflix's middle tier services together. The Ribbon client component provides a series of complete configuration items, such as connection timeout, Retry, etc. To put it simply, list all the machines behind the LoadBalancer (LB: load balancer for short) in the configuration file. The Ribbon will automatically help you connect these machines based on certain rules (such as simple polling, random connection, etc.). We can also easily use Ribbon to implement a custom load balancing algorithm!

What can Ribbon do?

  • LB, load balancer, is an application often used in microservices or distributed clusters.
  • Load balancing simply means that users' requests are evenly distributed to multiple services, so as to achieve the HA (high use) of the system.
  • Common load balancing software include Nginx, Lvs, etc.
  • Both Dubbo and spring cloud provide us with load balancing. The load balancing algorithm of spring cloud can be customized.
  • Simple classification of load balancing:
    • Centralized LB
      • That is, an independent LB facility is used between the service provider and the consumer, such as nginx (reverse proxy server), which is responsible for forwarding the access request to the service provider through some policy!
    • Advance program LB
      • Integrate LB logic into the consumer. The consumer knows which addresses are available from the service registry, and then selects an appropriate server from these addresses.
      • Ribbon belongs to in-process LB. it is just a class library integrated into the consumer process. The consumer obtains the address of the service provider through it!

1.2. Integrated Ribbon

springcloud-consumer-dept-80 adds Ribbon and Eureka dependencies to pom.xml

<!--Ribbon-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-ribbon</artifactId>
    <version>1.4.6.RELEASE</version>
</dependency>
<!--Eureka: Ribbon Need from Eureka What can I get from the service center-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-eureka</artifactId>
    <version>1.4.6.RELEASE</version>
</dependency>

Configure Eureka in the application.yml file

# Eureka configuration
eureka:
  client:
    register-with-eureka: false # Do not register yourself with Eureka
    service-url: # Access one of the three registries at random
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/

The main startup class is annotated with @ EnableEurekaClient to open Eureka

//After the integration of Ribbon and Eureka, the client can call directly without caring about the IP address and port number
@SpringBootApplication
@EnableEurekaClient //Open Eureka client
public class DeptConsumer_80 {
    public static void main(String[] args) {
        SpringApplication.run(DeptConsumer_80.class, args);
    }
}

Custom Spring configuration class: ConfigBean.java configures load balancing and implements RestTemplate

@Configuration
public class ConfigBean {
    //@Configuration -- spring  applicationContext.xml
    @LoadBalanced //Configure load balancing to implement RestTemplate
    @Bean
    public RestTemplate getRestTemplate() {
        return new RestTemplate();
    }
}

Modify the controller: DeptConsumerController.java

//Ribbon: the address here should be a variable accessed by the service name
//private static final String REST_URL_PREFIX = "http://localhost:8001";
private static final String REST_URL_PREFIX = "http://SPRINGCLOUD-PROVIDER-DEPT";

1.3. Use Ribbon to realize load balancing

flow chart:

1. Create two new service providers: springcloud-provider-dept-8003 and springcloud-provider-dept-8002

2. Refer to springcloud-provider-dept-8001, add pom.xml dependency, mybatis and application.yml configuration under resourcece, and Java code for the other two clouds

3. Start all service tests (determine the number of services to start according to your computer configuration), and access http://eureka7001.com:7002/ View results

Test access http://localhost/consumer/dept/list At this time, the service provider 8003 is accessed randomly

Visit again http://localhost/consumer/dept/list At this time, the random service provider 8001


Each visit above http://localhost/consumer/dept/list Random access to a service provider in the cluster is called polling. The polling algorithm can be customized in spring cloud.

How to switch or customize rules?

Configure in the ConfigBean under the springcloud-provider-dept-80 module and switch to different rules

@Configuration
public class ConfigBean {
    //@Configuration -- spring  applicationContext.xml
    /**
     * IRule:
     * RoundRobinRule round-robin policy 
     * RandomRule Random strategy
     * AvailabilityFilteringRule :  It will filter out, trip, access the failed service ~, and poll the rest~
     * RetryRule :  The service ~ will be obtained according to the polling first. If the service acquisition fails, it will be performed within the specified time and try again
     */
    @Bean
    public IRule myRule() {
        return new RandomRule();//Use random strategy
        //return new RoundRobinRule();// Use polling policy
        //return new AvailabilityFilteringRule();// Use polling policy
        //return new RetryRule();// Use polling policy
    }
}

You can also customize rules and customize a configuration class MyRule.java under the myRule package. Note: the package should not be the same level as the package where the main startup class is located, but should be the same level as the package where the startup class is located:

MyRule.java

@Configuration
public class MyRule {
    @Bean
    public IRule myRule(){
        return new MyRandomRule();//The default is polling RandomRule, which is now customized as its own
    }
}

The main startup class enables load balancing and specifies a custom MyRule configuration class

//After the integration of Ribbon and Eureka, the client can call directly without caring about the IP address and port number
@SpringBootApplication
@EnableEurekaClient
//The custom Ribbon class can be loaded when the micro service is started (the custom rules will overwrite the original default rules)
@RibbonClient(name = "SPRINGCLOUD-PROVIDER-DEPT",configuration = MyRule.class)//Turn on load balancing and specify custom rules
public class DeptConsumer_80 {
    public static void main(String[] args) {
        SpringApplication.run(DeptConsumer_80.class, args);
    }
}

Custom rules (here we refer to the default rule code in the Ribbon and change it slightly): MyRandomRule.java

public class MyRandomRule extends AbstractLoadBalancerRule {
    /**
     * If each service is accessed 5 times, the next service will be replaced (3 services in total)
     * <p>
     * total=0,Default = 0. If = 5, it points to the next service node
     * index=0,Default = 0, if total=5,index+1
     */
    private int total = 0;//Number of calls
    private int currentIndex = 0;//Who is currently providing services
    //@edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "RCN_REDUNDANT_NULLCHECK_OF_NULL_VALUE")
    public Server choose(ILoadBalancer lb, Object key) {
        if (lb == null) {
            return null;
        }
        Server server = null;
        while (server == null) {
            if (Thread.interrupted()) {
                return null;
            }
            List<Server> upList = lb.getReachableServers();//Access to currently alive services
            List<Server> allList = lb.getAllServers();//Get all services
            int serverCount = allList.size();
            if (serverCount == 0) {
                /*
                 * No servers. End regardless of pass, because subsequent passes
                 * only get more restrictive.
                 */
                return null;
            }
            //int index = chooseRandomInt(serverCount);// Generating interval random number
            //server = upList.get(index);// Randomly get one from a or living service
            //=====================Custom code=========================
            if (total < 5) {
                server = upList.get(currentIndex);
                total++;
            } else {
                total = 0;
                currentIndex++;
                if (currentIndex > upList.size()) {
                    currentIndex = 0;
                }
                server = upList.get(currentIndex);//Obtain the specified service from the living service for operation
            }
            //======================================================
            if (server == null) {
                /*
                 * The only time this should happen is if the server list were
                 * somehow trimmed. This is a transient condition. Retry after
                 * yielding.
                 */
                Thread.yield();
                continue;
            }
            if (server.isAlive()) {
                return (server);
            }
            // Shouldn't actually happen.. but must be transient or a bug.
            server = null;
            Thread.yield();
        }
        return server;
    }
    protected int chooseRandomInt(int serverCount) {
        return ThreadLocalRandom.current().nextInt(serverCount);
    }
    @Override
    public Server choose(Object key) {
        return choose(getLoadBalancer(), key);
    }
    @Override
    public void initWithNiwsConfig(IClientConfig clientConfig) {
        // TODO Auto-generated method stub
    }
}

Keywords: Java Operation & Maintenance Algorithm Spring Cloud

Added by Shuriken1 on Sun, 05 Sep 2021 00:10:07 +0300