SpringCloud (IV) --Ribbon Load Balancing

Posted by snapbackz on Tue, 08 Feb 2022 23:57:32 +0100

Ribbon is a client-based load balancing tool based on Netflix Ribbon. The main function is to provide a client-side software load balancing algorithm to connect Netflix's intermediate services together. Ribbon's client components provide a complete set of configuration items, such as connection timeouts, retries, and so on. Simply put, if you list all the machines behind load balancing in the configuration file, Ribbon will automatically help you connect them based on certain rules, such as simple polling, random connections, and so on. It's also easy to use Ribbon to implement custom load balancing algorithms!

The role of Ribbon

Load Balancing:
Load balancing is often used in micro-services or distributed clusters by distributing users'requests equally across multiple servers to achieve high system utilization.
Common load balancing software is Nginx, Lvs.
Load balancing is provided in Dubbo and SpringCloud, and SpringCloud's load balancing algorithm can be customized.
Classification of load balancing:

  • Centralized LB:
    This means using an independent LB facility, such as Nginx (reverse proxy server), between the provider and consumer of the service, which is responsible for forwarding access requests to the provider of the service through a policy.

  • Process-time LB
    (1) Integrate LB logic with the consumer, who knows from the service registry which addresses are available, and then chooses an appropriate server from these addresses.
    (2) Ribbon is a process LB. It is just a class library that integrates with the consumer process, through which the consumer gets the address of the service provider.

Integrated Ribbon

  1. springcloud-consumer-dept-80 to pom. Add Ribbon and Eureka dependencies to XML
<!--Ribbon-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-ribbon</artifactId>
    <version>1.4.6.RELEASE</version>
</dependency>
<!--Eureka: Ribbon Need to be from Eureka Service center get what to take-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-eureka</artifactId>
    <version>1.4.6.RELEASE</version>
</dependency>

  1. In application. Configure Eureka in 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/

  1. The main startup class opens Eureka with the @EnableEurekaClient annotation
//When Ribbon and Eureka are integrated, clients can call them directly, regardless of 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);
    }
}

  1. Custom spring configuration class: ConfigBean.java configures load balancing to implement RestTemplate
@Configuration
public class ConfigBean {//@Configuration -- spring  applicationContext.xml

    @LoadBalanced //Configure Load Balancing for RestTemplate
    @Bean
    public RestTemplate getRestTemplate() {
        return new RestTemplate();
    }
}

  1. Modify conroller:DeptConsumerController.java
//Ribbon: Our 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";

Load balancing using Ribbon

  1. Create two new service providers, Moudle: springcloud-provider-dept-8003, springcloud-provider-dept-8002
  2. Add POMS for the other two Moudle s in turn, referring to springcloud-provider-dept-8001. XML dependency, mybatis and application under resourece. YML configuration, Java code
  3. Start all service tests (depending on your computer configuration, the number of services to start), access http://eureka7001.com:7002/ View results

    Test Access http://localhost/consumer/dept/list Random access at this time is to service provider 8003.

    Visit again http://localhost/consumer/dept/list Random at this point is service provider 8001

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

Method of switching or customizing rules

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

@Configuration
public class ConfigBean {//@Configuration -- spring  applicationContext.xml

    /**
     * IRule:
     * RoundRobinRule round-robin policy
     * RandomRule Random strategy
     * AvailabilityFilteringRule :  It filters out, trips, accesses the failed service ~, polls the rest of the process ~
     * RetryRule :  Will first get the service according to the poll~, if the service get failed, will be in the specified time, retry
     */
    @Bean
    public IRule myRule() {
        return new RandomRule();//Using random strategies
        //return new RoundRobinRule();// Use polling policy
        //return new AvailabilityFilteringRule();// Use polling policy
        //return new RetryRule();// Use polling policy
    }
}

You can also customize rules to customize a configuration class, MyRule, under the myRule package. Java, note: this package does not have the same level as the package in which the main boot class resides, but rather the same level as the package in which the boot class resides:

  1. MyRule.java:
/**
 * @Auther: csp1999
 * @Date: 2020/05/19/11:58
 * @Description: Custom Rules
 */
@Configuration
public class MyRule {

    @Bean
    public IRule myRule(){
        return new MyRandomRule();//The default is to poll RandomRule and now customize it to your own
    }
}

  1. The main startup class turns on load balancing and specifies a custom MyRule configuration class
//When Ribbon and Eureka are integrated, clients can call them directly, regardless of IP address and port number
@SpringBootApplication
@EnableEurekaClient
//Custom Ribbon classes can be loaded when the microservice starts (custom rules override the 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);
    }
}

  1. Custom rule (here we refer to the default rule code in Ribbon that changes a little by itself): MyRandomRule.java
public class MyRandomRule extends AbstractLoadBalancerRule {

    /**
     * Change to the next service (a total of 3 services) after 5 visits to each service
     * <p>
     * total=0,Default = 0, if = 5, pointing 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 the service

    //@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();//Get services that are currently alive
            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 Numbers
            //server = upList.get(index);// Randomly get one from or live services

            //=========================Custom code========================

            if (total < 5) {
                server = upList.get(currentIndex);
                total++;
            } else {
                total = 0;
                currentIndex++;
                if (currentIndex > upList.size()) {
                    currentIndex = 0;
                }
                server = upList.get(currentIndex);//Get the specified service from the living service to operate on
            }
            
            //======================================================
            
            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
    }
}

Thank you and refer to:
https://csp1999.blog.csdn.net/article/details/106255122

Topics: Java Spring Cloud