Spring Cloud (6): Ribbon load balancing service call

1 Overview

Spring Cloud Ribbon is a set of client load balancing tools based on Netflix Ribbon.

Simply put, Ribbon is an open source project released by Netflix. Its main function is to provide client-side load balancing algorithms and service calls. The Ribbon client component provides a series of complete configuration items such as connection timeout, retry, etc. Simply put, it is to list all the machines behind Load Balance (LB for short) in the configuration file. Ribbon will automatically help you connect these machines based on certain rules (such as simple polling, random connection, etc.). It is easy for us Use Ribbon to implement custom load balancing algorithms.

Official website information: https://github.com/Netflix/ribbon/wiki/Getting-Started

2. LB (Load Balancing)

2.1 What is LB load balancing

Simply put, the user's requests are equally distributed to multiple servers, so as to achieve the system's HA (high availability). Common load balancing includes software nginx, LVS, hardware F5, etc.

2.2 The difference between Ribbon local guest load balancing client and nginx server load balancing

Nginx is server load balancing. All client requests are handed over to nginx, and then nginx implements forwarding requests, that is, load balancing is implemented by the server.

Ribbon local load balancing: When calling the microservice interface, the registration information service list will be obtained from the registry list and cached locally in the JVM, thereby implementing RPC remote service invocation technology locally

Centralized LB
refers to the use of independent LB facilities (hardware such as F5 or software such as nginx) between the consumer and provider of the service. The facility is responsible for forwarding the request for access to the service through a certain strategy. provider.

In-process LB
integrates the LB logic into the consumer. The consumer selects a suitable server from the service registry or which addresses are available. Ribbon belongs to the in-process LB, which is just a class library. Integrated in the consumer process, the consumer obtains the address of the service provider through him.

3. Ribbon load balancing

3.1 Architecture description

Insert picture description here
Ribbon is divided into two steps when working:

  • The first step is to choose Eureka Server, he prefers to choose the server with less load in the same area
  • The second part selects an address from the list of services obtained by the server according to the strategy specified by the user.
    Among them, Ribbon provides a variety of strategies: such as polling, random, and weighting based on response time.

Summary: Ribbon is actually a client component of soft load balancing. It can be used in conjunction with other clients that require requests. The combination with eureka is just one example.

3.2 Use of RestTemplate

https://docs.spring.io/spring-framework/docs/5.2.2.RELEASE/javadoc-api/org/springframework/web/client/RestTemplate.html

getForObject method/getForEntity method
Insert picture description here

postForObject/postForEntity
Insert picture description here

3.3 Ribbon core component IRule

IRule: Select a service to be accessed from the list of services according to a specific algorithm

  • com.netflix.loadbalancer.RoundRobinRule: polling
  • com.netflix.loadbalancer.RandomRule: Random
  • com.netflix.loadbalancer.RetryRule: First obtain the service according to the RoundRobinRule strategy, if the service fails, it will retry within the specified time
  • WeightedResponseTimeRule: an extension of RoundRobinRule, the faster the response speed, the greater the weight of the instance selection, the easier it is to be selected
  • BestAvailableRule: It will first filter out services that are in the circuit breaker trip state due to multiple access failures, and then select a service with the least amount of concurrency
  • AvailabilityFilteringRule: First filter out the failed instances, and then select the instance with less concurrency
  • ZoneAvoidanceRule: The default rule, the composite judges the performance of the area where the server is located and the availability of the server to select the server

How to replace
modify cloud-consumer-order80
Note the configuration details:
Insert picture description here
Insert picture description here

  • New package
    Insert picture description here
  • Create a new MyselfRule class
package com.lele.myrule;

import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @author: lele
 * @date: 2021/3/15 7:12
 * @description:
 */
@Configuration
public class MySelfRule {
    
    

    @Bean
    public IRule myRule() {
    
    
        return new RandomRule(); // 定义为随机
    }
}
  • Add @RibbonClient
    Insert picture description here
    browser access to the main startup class of consumer 80 : http://localhost/consumer/payment/get/1

4. Ribbon load balancing algorithm

4.1 Principle

Load balancing algorithm: the number of requests to the rest interface% The total number of server clusters = the actual call server location index (the rest interface count starts from 1 after each restart)

List instances = discoveryClient.getInstances(“CLOUD-PAYMENT-SERVICE”);

List[0] instances = 127.0.0.1:8001
List[1] instances = 127.0.0.1:8002

8001 and 8002 are combined into a cluster. They have two machines in total, and the total number of clusters is 2. According to the principle of the polling algorithm:

When the total number of requests is 1, 1%2 =1 ​​corresponds to the subscript position 1, and the obtained server address is 127.0.0.1:8002
When the total number of requests is 2, 2%2 =0 corresponds to the subscript position 0, and the obtained The server address is 127.0.0.1:8001
when the total number of requests is 3, and 3%2 =1 ​​corresponds to the subscript position 1, and the obtained server address is 127.0.0.1:8002
when the total number of requests is 4, 4%2 =0 corresponds to the next If the label position is 0, the obtained server address is 127.0.0.1:8001
…and
so on

4.2 Handwriting polling algorithm

  • 7001/7002 cluster startup

  • 8001/8002 microservice transformation
    Insert picture description here
    Insert picture description here

  • 80 order microservice transformation:

    • ApplicationContextBean remove @LoadBalanced
      Insert picture description here

    • LoadBalancer interface
      Insert picture description here

    • MyLB

      package com.lele.springcloud.lb;
      
      import org.springframework.cloud.client.ServiceInstance;
      import org.springframework.stereotype.Component;
      
      import java.util.List;
      import java.util.concurrent.atomic.AtomicInteger;
      
      /**
       * @author: lele
       * @date: 2021/3/16 7:27
       * @description:
       */
      @Component
      public class MyLB implements LoadBalancer {
              
              
      
          private AtomicInteger atomicInteger = new AtomicInteger(0);
      
          public final int getAndIncrement() {
              
              
              int current;
              int next;
              do {
              
              
                  current = this.atomicInteger.get();
                  next = current >= 2147483647 ? 0 : current + 1;
              } while (!this.atomicInteger.compareAndSet(current,  next));
              System.out.println("*****第几次访问,次数next:"+next);
              return next;
          }
      
          @Override
          public ServiceInstance instances(List<ServiceInstance> serviceInstances) {
              
              
              int index = getAndIncrement() % serviceInstances.size();
              return serviceInstances.get(index);
          }
      }
      
      
  • 80 OrderController

package com.lele.springcloud.controller;

import com.lele.springcloud.entities.CommonResult;
import com.lele.springcloud.entities.Payment;
import com.lele.springcloud.lb.LoadBalancer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.net.URI;
import java.util.List;

/**
 * @author: lele
 * @date: 2021/3/1 21:33
 * @description:
 */
@RestController
@Slf4j
public class OrderController {
    
    

//    public static final String PAYMENT_URL = "http://localhost:8001";
    public static final String PAYMENT_URL = "http://CLOUD-PAYMENT-SERVICE";

    @Resource
    private RestTemplate restTemplate;

    @Resource
    private LoadBalancer loadBalancer;

    @Resource
    private DiscoveryClient discoveryClient;

    @GetMapping("/consumer/payment/create")
    public CommonResult<Payment> create(Payment payment) {
    
    
        return restTemplate.postForObject(PAYMENT_URL + "/payment/create", payment, CommonResult.class);
    }

    @GetMapping("/consumer/payment/get/{id}")
    public CommonResult<Payment> getPayment(@PathVariable("id") Long id) {
    
    
        return restTemplate.getForObject(PAYMENT_URL + "/payment/get/" + id, CommonResult.class);
    }

    @GetMapping("/consumer/payment/getForEntity/{id}")
    public CommonResult<Payment> getPayment2(@PathVariable("id") Long id) {
    
    
        ResponseEntity<CommonResult> entity = restTemplate.getForEntity(PAYMENT_URL + "/payment/get/" + id, CommonResult.class);

        if (entity.getStatusCode().is2xxSuccessful()) {
    
    
            return entity.getBody();
        } else {
    
    
            return new CommonResult<>(444, "操作失败");
        }
    }

    @GetMapping(value = "/consumer/payment/lb")
    public String getPaymentLB() {
    
    
        List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
        if (instances == null || instances.size() <= 0) {
    
    
            return null;
        }

        ServiceInstance serviceInstance = loadBalancer.instances(instances);

        URI uri = serviceInstance.getUri();

        return restTemplate.getForObject(uri+"/payment/lb", String.class);
    }

}

  • 测试
    http://localhost/consumer/payment/lb

Guess you like

Origin blog.csdn.net/houwanle/article/details/114789056
Recommended