Springcloud-Alibaba 〖〗 Ribbon seven handwritten papers open source load balancing algorithm

A. What Ribbon that?

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

Ribbon is Netflix released open source project, the main function is to provide the client software load balancing algorithms and service calls . Ribbon client components, such as a series of perfect CI connection timeout, retry the like. Simply put, it is listed in the configuration file Load Balancer (referred to as LB) all machines behind, Ribbon will automatically help you to connect these machines based on certain rules (such as a simple polling, random connections, etc.). It is easy to use for load balancing algorithm Ribbon customizable.

Two. LB load balancing (Load Balance)

Simply means that the user's request equal shares allocated to the plurality of services, so as to achieve the system HA (High Availability). There are common load balancing software Nginx, LVS, F5 hardware and so on.

  • Centralized B
    that is separate between consumers and service providers LB facilities (can be hardware, such as F5, can be software, such as nginx), the facility is responsible for the access request is forwarded to the service through a strategy provider
  • LB-process
    will be integrated into the LB logical consumer, consumer service registry learn from what address is available, and then select a suitable own server from these addresses. Ribbon belong to LB in the process, it's just a class library, integrated with the consumer process, consumer to get the address of the service provider through it.

Ribbon is load balancing + RestTemplate calls, and ultimately the RPC remote call.

Three. Ribbon architecture

Here Insert Picture Description
Since eureka born with integrated ribbon, so you can not rely on it to add a ribbon
Here Insert Picture Description

Four. RestTemplate call

4.1 getForObject () method


    @GetMapping("/consumer/payment/getEntity/{id}")
    public CommonResult<Payment> getForEntity(@PathVariable("id") Long id){
        ResponseEntity<CommonResult> forEntity = restTemplate.getForEntity(PAYMENT_URL + "/payment/get/" + id, CommonResult.class);
        if ((forEntity.getStatusCode().is2xxSuccessful())){
            return forEntity.getBody();
        }else {
            return new CommonResult<>(444,"调用失败");
        }
    }

getForObject returning to get more information, including a request header, the request status code, and the like .
Here Insert Picture Description
Test
Here Insert Picture Description

4.2 getForObject () method

  • getForObject () is actually more than getForEntity () it contains more than the HTTP turn into a POJO functions, but does not address getForObject response capabilities. We get our hands because it is shaped pojo. It omitted a lot of information in response.

transfer

@GetMapping("/consumer/payment/create")
    public CommonResult<Payment> create(Payment payment){
        log.info("*******消费者启动创建订单*******");
        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);
    }

Test Results
Here Insert Picture Description

Five. Ribbon load balancing mechanism IRule

The default polling mechanism
Here Insert Picture Description

5.1 Directory Structure

Here Insert Picture Description

5.2 Create a rule class

The custom configuration class can not be placed under the current package @ComponentScan scanned and sub-package, or a custom configuration class will be shared by all of the Ribbon clients reach specialized custom purpose. So we create com.atguigu.myrule.MyselfRule class in java directory, where we create a random rule

package com.atguigu.myrule;

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

@Configuration
public class MyselfRule {

    @Bean
    public IRule myRule(){
        return new RandomRule(); //定义为随机
    }
}

5.3 Master Boot class annotate

Here Insert Picture Description

@RibbonClient(name = "CLOUD-PAYMENT-SERVICE",configuration = MyselfRule.class)

5.4 Test

Here Insert Picture Description
In the case of the prior polling port 8001 and 8002 alternate, while the load balancing rule becomes random, the random port

VI. Load Balancing Algorithm

6.1 load balancing algorithm: poll

  • Interface rest of the total number of requested number of times the server cluster% = actual call server location subscript

  • Rest after each server restart from the beginning the number of interfaces

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

  1. List[0] instances = 127.0.0.1:8002

  2. List[1] instances = 127.0.0.1:8001

For example, we now have two machines to load balancing

The number of requests The formula Get subscript
1 1%2=1 Correspondence 127.0.0.1:8001
2 2%2=0 Correspondence 127.0.0.1:8002
3 3%2=1 Correspondence 127.0.0.1:8001

6.2 interface class

Here Insert Picture Description

6.3 Ribbon source

IRule Interface

//IRule接口
public interface IRule{
    /*
     * choose one alive server from lb.allServers or
     * lb.upServers according to key
     * 
     * @return choosen Server object. NULL is returned if none
     *  server is available 
     */
	//选择哪个服务实例
    public Server choose(Object key);
    
    public void setLoadBalancer(ILoadBalancer lb);
    
    public ILoadBalancer getLoadBalancer();    
}

RoundRobinRule polling Source

public class RoundRobinRule extends AbstractLoadBalancerRule {

    private AtomicInteger nextServerCyclicCounter;
    private static final boolean AVAILABLE_ONLY_SERVERS = true;
    private static final boolean ALL_SERVERS = false;

    private static Logger log = LoggerFactory.getLogger(RoundRobinRule.class);

    public RoundRobinRule() {
        nextServerCyclicCounter = new AtomicInteger(0);
    }

    public RoundRobinRule(ILoadBalancer lb) {
        this();
        setLoadBalancer(lb);
    }

    public Server choose(ILoadBalancer lb, Object key) {
        if (lb == null) {
            log.warn("no load balancer");
            return null;
        }

        Server server = null;
        int count = 0;
        while (server == null && count++ < 10) {
            List<Server> reachableServers = lb.getReachableServers();
            List<Server> allServers = lb.getAllServers();
            int upCount = reachableServers.size();
            int serverCount = allServers.size();

            if ((upCount == 0) || (serverCount == 0)) {
                log.warn("No up servers available from load balancer: " + lb);
                return null;
            }

            int nextServerIndex = incrementAndGetModulo(serverCount);
            server = allServers.get(nextServerIndex);

            if (server == null) {
                /* Transient. */
                Thread.yield();
                continue;
            }

            if (server.isAlive() && (server.isReadyToServe())) {
                return (server);
            }

            // Next.
            server = null;
        }

        if (count >= 10) {
            log.warn("No available alive servers after 10 tries from load balancer: "
                    + lb);
        }
        return server;
    }

    /**
     * Inspired by the implementation of {@link AtomicInteger#incrementAndGet()}.
     *
     * @param modulo The modulo to bound the value of the counter.
     * @return The next value.
     */
    private int incrementAndGetModulo(int modulo) {
        for (;;) {
            int current = nextServerCyclicCounter.get();
            int next = (current + 1) % modulo;
            if (nextServerCyclicCounter.compareAndSet(current, next))
                return next;
        }
    }

    @Override
    public Server choose(Object key) {
        return choose(getLoadBalancer(), key);
    }

    @Override
    public void initWithNiwsConfig(IClientConfig clientConfig) {
    }
}

CAS point here with the knowledge points, not little friends can be the venue here: What is CAS

VII. Handwriting load balancing algorithm

7.1 change controller

One way to increase the project ends in 8001

Here Insert Picture Description

   @GetMapping("/payment/lb")
    public String getPaymentLB(){
        return serverPort;
    }

In a similar increase in 8002 project end method

  @GetMapping("/payment/lb")
    public String getPaymentLB(){
        return serverPort;
    }

7.2 out of 80 projects Note @LoadBalanced

Commented, after all, we have to use to write their own
Here Insert Picture Description

7.3 80 projects to increase an interface and an implementation class

Here Insert Picture Description
interface

package com.aiguigu.springcloud.lb;

import org.springframework.cloud.client.ServiceInstance;

import java.util.List;

public interface LoadBalancer {

    ServiceInstance instances(List<ServiceInstance> serviceInstances);
}

Implementation class

package com.aiguigu.springcloud.lb;

import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.stereotype.Component;

import java.lang.annotation.Annotation;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

@Component
public class MyLB implements LoadBalancer {

    private AtomicInteger atomicInteger=new AtomicInteger(0);

    public final int getAndIncrement(){
        int current;
        int next;
        do{
            current=atomicInteger.get();
            next=current>=2147483647?0:current+1;
        }while (!this.atomicInteger.compareAndSet(current,next));
        System.out.println("***第几次访问,次数: "+next);
        return next;
    }


    public ServiceInstance instances(List<ServiceInstance> serviceInstances){
        int index=getAndIncrement()%serviceInstances.size();
        return serviceInstances.get(index);
    }
}

  • Here there is a first class atomic int type, the initial value is 0, there is used a spin lock, so that he is not a time to determine the value of our previous, +1 if it is representative of the number of visits has increased again, not to continue loop until judgment is really out of the loop, there is no guarantee the increase in the number of synchronized method can achieve thread-safe under high concurrency
  • The second method of instances ()% to achieve a number of clusters with the current number of visits, so this value will never exceed the number of clusters, and then to obtain this value as the index acquiring a single instance, a current instance of the cluster returns should be returned

7.4 controller layer

New method getPaymentLB ()

 	@Resource
    private LoadBalancer loadBalancer;

    @Resource
    private DiscoveryClient discoveryClient;
    
    @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 instances1 = loadBalancer.instances(instances);
        URI uri = instances1.getUri();
        return restTemplate.getForObject(uri+"/payment/lb",String.class);
    }

First, obtain an instance of the cluster, and then determine whether the method is empty, the cluster passed to get to the list just write in to get the current instance load balancing acquired, and then get to the instance address, last restTemplate will use the service to call before writing to our load balancing to call

7.5 Test

Call polling method would have been called, embodies our load balancing mechanism just
Here Insert Picture Description

Here Insert Picture Description
The server console also print out the first few visits, the service will restart number becomes 0, so to ensure that the memory does not overflow, just set the maximum value is the maximum value of int
Here Insert Picture Description

Finally finished liver Ribbon, honest writing this really long time, because the foundation is really bad, it will go up some basic, reading may not be white prostitute oh ~

Reproduced, please mark!

Published 85 original articles · won praise 77 · views 10000 +

Guess you like

Origin blog.csdn.net/kingtok/article/details/105049480
Recommended