Diagram + source code to explain the principle of Ribbon service selection

Get into the habit of writing together! This is the 14th day of my participation in the "Nuggets Daily New Plan · April Update Challenge", click to view the details of the event

Diagram + source code to explain the principle of Ribbon service selection

Don't complain when you encounter difficulties, since you can't change the past, try to change the future

Related Articles
Illustration + Source Code Explaining Ribbon How to Get the Registration Center Example
Illustration + Source Code Explaining Ribbon Principles
Illustration + Source Code Explaining Ribbon Service List Update

Where to start your analysis

    Think about when to make service selection, specify that when requesting access, specific service selection will be made, then let's take a look at the executed code to see if there is any specific related code in it

public <T> T execute(String serviceId, LoadBalancerRequest<T> request, Object hint)
        throws IOException {
    ILoadBalancer loadBalancer = getLoadBalancer(serviceId);
    Server server = getServer(loadBalancer, hint);
    if (server == null) {
        throw new IllegalStateException("No instances available for " + serviceId);
    }
    RibbonServer ribbonServer = new RibbonServer(serviceId, server,
            isSecure(server, serviceId),
            serverIntrospector(serviceId).getMetadata(server));

    return execute(serviceId, ribbonServer, request);
}
复制代码

    At a glance, we can see the method getServer(loadBalancer, hint) for obtaining services. Then we will start the analysis from this line of code. Let's first look at a flow chart of the principle of one-choice service.

Select Service Schematic

image.png

Source code analysis

1. Get the service DynamicServerListLoadBalancer

    In fact, he obtained the service list getServer(loadBalancer, hint) from the load balancer. This load balancer is DynamicServerListLoadBalancer, which was previously defined in RibbonClientConfiguration. In fact, we have obtained two from the above flow chart. Service node [192.168.0.107:9100, 192.168.0.107:9200]

2. loadBalancer select service

    loadBalancer.chooseServer This method of selecting services actually takes the chooseServer method in the BaseLoadBalancer class

protected Server getServer(ILoadBalancer loadBalancer, Object hint) {
    if (loadBalancer == null) {
        return null;
    }
    return loadBalancer.chooseServer(hint != null ? hint : "default");
}
复制代码

    In fact, service selection is performed through certain service selection rules. The code rule.choose(key) is the core selection rule.

public Server chooseServer(Object key) {
    if (counter == null) {
        counter = createCounter();
    }
    counter.increment();
    if (rule == null) {
        return null;
    } else {
        try {
            // 实例选择算法
            return rule.choose(key);
        } catch (Exception e) {
            logger.warn("LoadBalancer [{}]:  Error choosing server for key {}", 
                        name, key, e);
            return null;
        }
    }
}
复制代码

3. Select services by polling rules

    The default service selection rule is the polling algorithm, which is accessed one by one. The chooseRoundRobinAfterFiltering method is the most important. It is to pass in the service list in the load balancer and then select one through the round-robin algorithm. We enter this You can see in the method

@Override
public Server choose(Object key) {
    ILoadBalancer lb = getLoadBalancer();
    Optional<Server> server = getPredicate()
        .chooseRoundRobinAfterFiltering(lb.getAllServers(), key);
    if (server.isPresent()) {
        return server.get();
    } else {
        return null;
    }       
}
复制代码

4. Polling algorithm selection filter chooseRoundRobinAfterFiltering

    First select the appropriate service list through the getEligibleServers method, return a List collection, and then enter the new service selection through the incrementAndGetModulo(eligible.size()) modulo algorithm

    public Optional<Server> chooseRoundRobinAfterFiltering(List<Server> servers, 
                                                           Object loadBalancerKey) {
        List<Server> eligible = getEligibleServers(servers, loadBalancerKey);
        if (eligible.size() == 0) {
            return Optional.absent();
        }
        return Optional.of(eligible.get(incrementAndGetModulo(eligible.size())));
    }
复制代码

5. Modulo algorithm incrementAndGetModulo

    An infinite loop of for, records the current value through an atomic class nextIndex, then takes the remainder of the current value + 1 and the service list, sets the remainder to current and returns it, in fact, calculates an index value, this index The value must be less than the size of the service list, because it needs to get a value from the List collection through the index

private int incrementAndGetModulo(int modulo) {
    for (;;) {
        int current = nextIndex.get();
        int next = (current + 1) % modulo;
        if (nextIndex.compareAndSet(current, next) && current < modulo)
            return current;
    }
}
复制代码

    Obtain a service node through eligible.get(current) and then return it to the request for subsequent access

summary

  1. Get service list from DynamicServerListLoadBalancer load balancer
  2. Service list selection via round-robin algorithm
  3. The polling algorithm is calculated by the modulo algorithm

Guess you like

Origin juejin.im/post/7086261802211737630