Introduction and practice of spring cloud ribbon

Time:2021-12-30

First article:Introduction and practice of spring cloud ribbon

What is ribbon

Ribbon is a client load balancer, which gives applications the ability to dominate HTTP and TCP behavior. Here, load balancing is client load balancing, also known as back-end load balancing, which is a kind of in-process load balancing. Ribbon is an indispensable component in the spring cloud ecosystem. With it, it is more convenient for horizontal expansion of services. In addition, feign and zuul integrate ribbon by default.

Ribbon is an open source component of neflix. At present, ribbon has already entered the maintenance state, but according to the current situation, some components of spring cloud Netflix can still be used.

Spring cloud loadbalancer is an open source component of the spring cloud community. It aims to replace the ribbon in maintenance status, but the loadbalancer still has a long way to go.

Introduction to ribbon

Since the client load balancing needs to obtain the service list from the registry, it needs to integrate the registry.

Create a parent project cloud ribbon practice

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.3.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <spring.cloud-version>Hoxton.SR3</spring.cloud-version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring.cloud-version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

Create registry cloud Eureka server

<dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
    </dependencies>

Configuration file application xml

server:
  port: 8761
eureka:
  instance:
    hostname: localhost
  client:
    registerWithEureka: false
    fetchRegistry: false
    serviceUrl:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

Startup class

@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(EurekaServerApplication.class, args);
    }
}

Create source service projects cloud-ribbon-hello-b1, cloud-ribbon-hello-b2 and cloud-ribbon-hello-b3

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
    </dependencies>

Configuration file application yml

b1

spring:
  application:
    name: ribbon-service-b
server:
  port: 7777
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/
  instance:
    prefer-ip-address: true

b2

spring:
  application:
    name: ribbon-service-b
server:
  port: 7778
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/
  instance:
    prefer-ip-address: true

b3

spring:
  application:
    name: ribbon-service-b
server:
  port: 7779
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/
  instance:
    prefer-ip-address: true

Controller of B1, B2 and B3

@RestController
public class OrderController {

    @Value("${server.port}")
    private Integer port;

    @Value("${spring.application.name}")
    private String name;

    @GetMapping("/test")
    public String add() {
        return "this service name is " + name + " and port is " + port;
    }

}

Startup classes of B1, B2 and B3

@SpringBootApplication
@EnableDiscoveryClient
public class ServiceB1Application {
    public static void main(String[] args) {
        SpringApplication.run(ServiceB1Application.class, args);
    }
}

@SpringBootApplication
@EnableDiscoveryClient
public class ServiceB2Application {
    public static void main(String[] args) {
        SpringApplication.run(ServiceB2Application.class, args);
    }
}

@SpringBootApplication
@EnableDiscoveryClient
public class ServiceB3Application {
    public static void main(String[] args) {
        SpringApplication.run(ServiceB3Application.class, args);
    }
}

Create service caller cloud-ribbon-hello-a

spring-cloud-starter-netflix-eureka-clientRibbon has been integrated. It can be used directly without additional introduction.

Introduction and practice of spring cloud ribbon

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
    </dependencies>

Configuration file application yml

spring:
  application:
    name: ribbon-hello-a
server:
  port: 7776
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/
  instance:
    prefer-ip-address: true

Start class, resttemplate uses@LoadBalancedIn this way, resttemplate enables load balancing of ribbon.

@SpringBootApplication
@EnableDiscoveryClient
public class ServiceAApplication {
    public static void main(String[] args) {
        SpringApplication.run(ServiceAApplication.class, args);
    }

    @LoadBalanced
    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

controller

@RestController
@RequestMapping("ribbon")
public class TestController {

    @Autowired
    private RestTemplate restTemplate;

    @GetMapping("/test")
    public String test(){
        String body = restTemplate.getForEntity("http://RIBBON-SERVICE-B/test", String.class).getBody();
        return body;
    }

}

Test, access several times using postman:http://localhost:7776/ribbon/…

Introduction and practice of spring cloud ribbon

Introduction and practice of spring cloud ribbon

Introduction and practice of spring cloud ribbon

Ribbon actual combat

As you can see from the previous section, you only need to start load balancing through@LoadBalancedJust annotate. There are many load balancing strategies in load balancing, such as round robin, weight, ip_hash, etc. These rich strategies give us a lot of choices when building applications, and we can choose the most appropriate strategy according to the actual business scenario.

Seven load balancing strategies are provided in the ribbon:

Policy class name describe
RandomRule Random strategy Randomly select server
RoundRobinRule round-robin policy Select server in order
RetryRule Retry policy During a configuration period, if the selection of server is unsuccessful, you will always try to select an available server
BestAvailableRule Minimum concurrency policy Zhuo Ge inspects the server. If the server circuit breaker is open, ignore it, and then select the server with the lowest concurrent connection
AvailabilityFilteringRule Available filtering policies Filter the servers that fail to connect all the time and are marked as circuit tripped, and filter out those servers with high concurrent connections (active connections exceed the configured threshold)
ResponseTimeWeightedRule Response time weighting strategy Has been deprecated for the same function as weightedresponsetimerule
WeightedResponseTimeRule Response time weighting strategy The weight is allocated according to the response time of the server. The longer the response time, the lower the weight, and the lower the probability of being selected. The shorter the response time, the higher the weight, and the higher the probability of being selected
ZoneAvoidanceRule Regional trade-off strategy Comprehensively judge the performance of the area where the server is located and the availability of the server, poll and select the server, judge whether the operation performance of an AWS zone is available, and eliminate all servers in the unavailable zone

In the above introductory case, the ribbon’s default load balancing strategy is polling strategy,

Ribbon custom configuration load balancing policy

Global configuration

To configure the global load balancing policy when using the ribbon, you need to add a configuration class. The configuration class needs to be changed@ComponentScanScan to take effect globally.

@Configuration
public class GlobalRuleConfig {
    @Bean
    public IRule ribbonRule() {
        return new RandomRule();
    }
}

The random policy is configured above, which can be accessed multiple timeshttp://localhost:7776/ribbon/…

be based on@RibbonClientor@RibbonClientsConfiguration of annotations

Configuration class, note:When writing a custom configuration class, it should be noted that the official document clearly gives a warning: this custom configuration class cannot be placed under the package scanned by @ componentscan and its sub packages (that is, it cannot be placed under the package and its sub packages where the main startup class is located, so we need to create a new package to place the configuration class), Otherwise, our customized configuration class will be shared by all ribbon clients, and the purpose of special customization will not be achieved

@Configuration
public class AnnoRuleConfig {
    @Bean
    public IRule ribbonRule() {
        return new RandomRule();
    }
}

Configuration of startup class

@SpringBootApplication
@EnableDiscoveryClient
@RibbonClient(name = "ribbon-service-b", configuration = AnnoRuleConfig.class)
public class ServiceAApplication {
    public static void main(String[] args) {
        SpringApplication.run(ServiceAApplication.class, args);
    }

    @LoadBalanced
    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

adopt@RibbonClientSpecify the load balancing policy for a service. For others that are not specified, the default load balancing policy is used. This annotation can import other configuration classes into the application as another IOC container, which is equivalent to loading two completely unrelated spring beans configuration files. At this time, there will be two IOC containers in the application.

@RibbonClient(name = "RIBBON-SERVICE-B", configuration = AnnoRuleConfig.class)

You can also use the following method to specify the load balancing policy for multiple services

@RibbonClients(value = {
        @RibbonClient(name = "RIBBON-SERVICE-B", configuration = AnnoRuleConfig.class),
        @RibbonClient(name = "RIBBON-SERVICE-C", configuration = AnnoRuleConfig.class)
})

Profile based

The following is about servicesribbon-service-bLoad balancing policy usage

RIBBON-SERVICE-B:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

Ribbon timeout and retry

Using HTTP to initiate a request will inevitably lead to problems. Starting from version F, the ribbon retry mechanism is turned on by default. You need to add the configuration of timeout and retry policy. Listed belowribbon-service-bConfiguration of services

RIBBON-SERVICE-B:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
    ConnectTimeout: 3000
    ReadTimeout: 60000
    Maxautoretries: 3 # the number of retries for the first requested service
    Maxautoretriesnextserver: 1 # maximum number of next services to retry (excluding the first service)
    OkToRetryOnAllOperations: true

It can also be configured globally

ribbon:
  ConnectTimeout: 3000
  ReadTimeout: 60000
  Maxautoretries: 3 # the number of retries for the first requested service
  Maxautoretriesnextserver: 1 # maximum number of next services to retry (excluding the first service)
  OkToRetryOnAllOperations: true

The ribbon is generally used with HTTP clients such as openfeign or other RPCs. Because it will be more elegant and convenient to call remote services. Openfeign inherits the ribbon by default, and the timeout configuration of the ribbon is also very simple.

For network jitter, these can be usedspring-retry, spring retry is a spring based retry framework provided by spring, which is very easy to use.

Ribbon hungry loading

When the ribbon performs client load balancing, it does not load the context at startup, but creates the context when the actual request is made. Because of the context to be loaded, the first call may be slow or even cause a timeout. Therefore, we can specify the ribbon client to enable immediate loading (hungry loading), and immediately load the application context of all configuration items when the application starts.

ribbon:
  eager-load:
    clients: ribbon-service-b, ribbon-service-order
    enabled: true

Custom ribbon client

In ribbon’s 1.2 After version 0, you can use the configuration file to customize the ribbon client. In fact, the essence is to use the configuration file to specify some default loading classes, so as to change the behavior of the ribbon client. In this way, the priority is the highest, and the priority is higher than the use of annotations@RibbonClientThe specified configuration and related beans loaded in the source code. See the table below:

Configuration item explain
<clientName>.ribbon.NFLoadBalancerClassName Specifies the implementation class of iloadbalancer
<clientName>.ribbon.NFLoadBalancerRuleClassName Specifies the implementation class of iRule
<clientName>.ribbon.NFLoadBalancerPingClassName Specifies the implementation class of iping
<clientName>.ribbon.NiWSServerListClassName Specifies the implementation class of serverlist
<clientName>.ribbon.NIWSServerListFilterClassName Specifies the implementation class of serverlistfilter

For example, the implementation used here is the implementation provided by ribbon

RIBBON-SERVICE-B:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
    NiWSServerListClassName: com.netflix.loadbalancer.ConfigurationBasedServerList

Ribbon out of Eureka

By default, the ribbon client needs to read the service registration information list from the Eureka registry to achieve a dynamic load balancing function. When the registration center used is a public registration center, such as Eureka for community welfare(http://eureka.springcloud.cn)…

ribbon: 
  eureka:
    enabled: false
#Get address of ribbon-service-b service
RIBBON-SERVICE-B:
  ribbon:
    listOfServers: http://localhost:8088/

Ribbon advanced

Core working principle

Ribbon’s core interface:

Interface describe Default implementation
IClientConfig Defines the interface for managing configuration in the ribbon DefaultClientConfigImpl
IRule Defines the interface for load balancing policies in the ribbon ZoneAdvoidanceRule
IPing Define an interface for periodic Ping Service check availability DummyPing
ServerList\<Server> Defines the interface of the method to get the service list ConfigurationBasedServerList
ServerListFilter\<Server> Defines an interface for a specific method that expects to get a service list ZonePreferenceServerListFilter
ILoadBalancer Define the interface of the core method of load balancing selection service ZoneAwareLoadBalancer
ServerListUpdater Define the interface for dynamically updating the service list for the dynamicserverlistloadbalancer PollingServerListUpdater

Ribbon is built entirely on these interfaces and is the core of ribbon. Understanding the functions of these core classes is helpful to understand the principle and extension of ribbon.

In the previous examples, ribbon load balancing is used by adding annotations on the bean of resttemplate@LoadBalancedSo resttemplate has the ability of load balancing.

Loadbalanced source code:


/**
 * Annotation to mark a RestTemplate or WebClient bean to be configured to use a
 * LoadBalancerClient.
 * @author Spencer Gibb
 */
@Target({ ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Qualifier
public @interface LoadBalanced {
}

You can see in the comments:This annotation is marked on resttemplate or other webclient beans to use loadbalancerclient

LoadBalancerClient:This interface extends from serviceinstancechooser

public interface LoadBalancerClient extends ServiceInstanceChooser {

    /**
     * Executes request using a ServiceInstance from the LoadBalancer for the specified
     * service.
     * @param serviceId The service ID to look up the LoadBalancer.
     * @param request Allows implementations to execute pre and post actions, such as
     * incrementing metrics.
     * @param <T> type of the response
     * @throws IOException in case of IO issues.
     * @return The result of the LoadBalancerRequest callback on the selected
     * ServiceInstance.
     */
    <T> T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException;

    /**
     * Executes request using a ServiceInstance from the LoadBalancer for the specified
     * service.
     * @param serviceId The service ID to look up the LoadBalancer.
     * @param serviceInstance The service to execute the request to.
     * @param request Allows implementations to execute pre and post actions, such as
     * incrementing metrics.
     * @param <T> type of the response
     * @throws IOException in case of IO issues.
     * @return The result of the LoadBalancerRequest callback on the selected
     * ServiceInstance.
     */
    <T> T execute(String serviceId, ServiceInstance serviceInstance,
            LoadBalancerRequest<T> request) throws IOException;

    /**
     * Creates a proper URI with a real host and port for systems to utilize. Some systems
     * use a URI with the logical service name as the host, such as
     * http://myservice/path/to/service. This will replace the service name with the
     * host:port from the ServiceInstance.
     * @param instance service instance to reconstruct the URI
     * @param original A URI with the host as a logical service name.
     * @return A reconstructed URI.
     */
    URI reconstructURI(ServiceInstance instance, URI original);
}

ServiceInstanceChooser:

public interface ServiceInstanceChooser {

    /**
     * Chooses a ServiceInstance from the LoadBalancer for the specified service.
     * @param serviceId The service ID to look up the LoadBalancer.
     * @return A ServiceInstance that matches the serviceId.
     */
    ServiceInstance choose(String serviceId);
}
  • Serviceinstance choose (string serviceid): select a service instance based on serviceid and load balancer
  • <T> T execute (string serviceid, loadbalancerrequest < T > request): use the serviceinstance from loadbalancer to execute the request for the specified service
  • <T> T execute(String serviceId, ServiceInstance serviceInstance,

    Loadbalancerrequest < T > request): the serviceinstance from loadbalancer is used to execute the request for the specified service. It is an overload of the previous method. Their relationship can be seen in the implementation class, which is the detailed implementation of the previous method
  • URI reconstructuri (service instance, URI original): use the annotation IP and port to build a specific URL for internal use in ribbon. The ribbon uses a URL with a logical service name as the host, for example:http://service-b/order/add。

From the functions of these methods, we can know the importance of these two interfaces. There is a class under the same package of the two interfacesLoadBalancerAutoConfigurationLoadBalancerAutoConfigurationstayorg.springframework.cloud.client.loadbalancerUnder the bag, inspring-cloud-commonsInside. This automatic configuration class is officially the core configuration class of ribbon.

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(RestTemplate.class)
@ConditionalOnBean(LoadBalancerClient.class)
@EnableConfigurationProperties(LoadBalancerRetryProperties.class)
public class LoadBalancerAutoConfiguration {

    @LoadBalanced
    @Autowired(required = false)
    private List<RestTemplate> restTemplates = Collections.emptyList();

    @Autowired(required = false)
    private List<LoadBalancerRequestTransformer> transformers = Collections.emptyList();

    @Bean
    public SmartInitializingSingleton loadBalancedRestTemplateInitializerDeprecated(
            final ObjectProvider<List<RestTemplateCustomizer>> restTemplateCustomizers) {
        return () -> restTemplateCustomizers.ifAvailable(customizers -> {
            for (RestTemplate restTemplate : LoadBalancerAutoConfiguration.this.restTemplates) {
                for (RestTemplateCustomizer customizer : customizers) {
                    customizer.customize(restTemplate);
                }
            }
        });
    }

    @Bean
    @ConditionalOnMissingBean
    public LoadBalancerRequestFactory loadBalancerRequestFactory(
            LoadBalancerClient loadBalancerClient) {
        return new LoadBalancerRequestFactory(loadBalancerClient, this.transformers);
    }

    @Configuration(proxyBeanMethods = false)
    @ConditionalOnMissingClass("org.springframework.retry.support.RetryTemplate")
    static class LoadBalancerInterceptorConfig {

        @Bean
        public LoadBalancerInterceptor ribbonInterceptor(
                LoadBalancerClient loadBalancerClient,
                LoadBalancerRequestFactory requestFactory) {
            return new LoadBalancerInterceptor(loadBalancerClient, requestFactory);
        }

        @Bean
        @ConditionalOnMissingBean
        public RestTemplateCustomizer restTemplateCustomizer(
                final LoadBalancerInterceptor loadBalancerInterceptor) {
            return restTemplate -> {
                List<ClientHttpRequestInterceptor> list = new ArrayList<>(
                        restTemplate.getInterceptors());
                list.add(loadBalancerInterceptor);
                restTemplate.setInterceptors(list);
            };
        }

    }

    /**
     * Auto configuration for retry mechanism.
     */
    @Configuration(proxyBeanMethods = false)
    @ConditionalOnClass(RetryTemplate.class)
    public static class RetryAutoConfiguration {

        @Bean
        @ConditionalOnMissingBean
        public LoadBalancedRetryFactory loadBalancedRetryFactory() {
            return new LoadBalancedRetryFactory() {
            };
        }

    }

    /**
     * Auto configuration for retry intercepting mechanism.
     */
    @Configuration(proxyBeanMethods = false)
    @ConditionalOnClass(RetryTemplate.class)
    public static class RetryInterceptorAutoConfiguration {

        @Bean
        @ConditionalOnMissingBean
        public RetryLoadBalancerInterceptor ribbonInterceptor(
                LoadBalancerClient loadBalancerClient,
                LoadBalancerRetryProperties properties,
                LoadBalancerRequestFactory requestFactory,
                LoadBalancedRetryFactory loadBalancedRetryFactory) {
            return new RetryLoadBalancerInterceptor(loadBalancerClient, properties,
                    requestFactory, loadBalancedRetryFactory);
        }

        @Bean
        @ConditionalOnMissingBean
        public RestTemplateCustomizer restTemplateCustomizer(
                final RetryLoadBalancerInterceptor loadBalancerInterceptor) {
            return restTemplate -> {
                List<ClientHttpRequestInterceptor> list = new ArrayList<>(
                        restTemplate.getInterceptors());
                list.add(loadBalancerInterceptor);
                restTemplate.setInterceptors(list);
            };
        }

    }

}

This makes it clear that the configuration loading time is that the current project environment must have an instance of resttemplate and the implementation class of loadbalancerclient must be initialized.

@ConditionalOnClass(RestTemplate.class)
@ConditionalOnBean(LoadBalancerClient.class)

Loadbalancerrequestfactory: used to create loadbalancerrequest for loadbalancerinterceptor.

Loadbalancerinterceptorconfig: maintains instances of loadbalancerinceptor and resttemplatecustomizer.

  • Loadbalancerinterceptor: intercepts every HTTP request and binds the request to the load balancing life cycle of golden ribbon.
  • Resttemplatecustomizer: bind loadbalancerinceptor interceptor interceptor for each restemplate.

The role of the loadbalancerinceptor is already close to the answer.

public class LoadBalancerInterceptor implements ClientHttpRequestInterceptor {

    private LoadBalancerClient loadBalancer;

    private LoadBalancerRequestFactory requestFactory;

    public LoadBalancerInterceptor(LoadBalancerClient loadBalancer,
            LoadBalancerRequestFactory requestFactory) {
        this.loadBalancer = loadBalancer;
        this.requestFactory = requestFactory;
    }

    public LoadBalancerInterceptor(LoadBalancerClient loadBalancer) {
        // for backwards compatibility
        this(loadBalancer, new LoadBalancerRequestFactory(loadBalancer));
    }

    @Override
    public ClientHttpResponse intercept(final HttpRequest request, final byte[] body,
            final ClientHttpRequestExecution execution) throws IOException {
        final URI originalUri = request.getURI();
        String serviceName = originalUri.getHost();
        Assert.state(serviceName != null,
                "Request URI does not contain a valid hostname: " + originalUri);
        return this.loadBalancer.execute(serviceName,
                this.requestFactory.createRequest(request, body, execution));
    }
}

It can be seen from the source code that it intercepts HTTP requests every time through clienthttprequeinterceptor. Clienthttprequeinterceptor class is a request interceptor maintained in spring. Implementing its intercept method can make requests enter the method, so that ribbon can do some of its own processing.

Uri used when requesting a service using resttemplate:http://serviceName/path/to/se…

The intercept method in loadbalancerinceptor finally calls the execute method of ribbonloadbalancerclient:

public <T> T execute(String serviceId, LoadBalancerRequest<T> request, Object hint) throws IOException {
        //Implementation of load balancer
        ILoadBalancer loadBalancer = this.getLoadBalancer(serviceId);
        //Get the specific server
        Server server = this.getServer(loadBalancer, hint);
        if (server == null) {
            throw new IllegalStateException("No instances available for " + serviceId);
        } else {
            RibbonLoadBalancerClient.RibbonServer ribbonServer = new RibbonLoadBalancerClient.RibbonServer(serviceId, server, this.isSecure(server, serviceId), this.serverIntrospector(serviceId).getMetadata(server));
            return this.execute(serviceId, (ServiceInstance)ribbonServer, (LoadBalancerRequest)request);
        }
    }
    protected Server getServer(ILoadBalancer loadBalancer, Object hint) {
        return loadBalancer == null ? null : loadBalancer.chooseServer(hint != null ? hint : "default");
    }

For the chooseserver is the method of the interface iloadbalancer, let’s take a look at one of them to implement baseloadbalancer

    public Server chooseServer(Object key) {
        if (this.counter == null) {
            this.counter = this.createCounter();
        }

        this.counter.increment();
        if (this.rule == null) {
            return null;
        } else {
            try {
                return this.rule.choose(key);
            } catch (Exception var3) {
                logger.warn("LoadBalancer [{}]:  Error choosing server for key {}", new Object[]{this.name, key, var3});
                return null;
            }
        }
    }

Finally, through:rule.choose(key)Get the server, and the rule is iRule.

stayRibbonClientConfigurationSeveral core classes mentioned in the table above are initialized in

  1. Initialize ribbonrule:ZoneAvoidanceRule
  2. Initialize ribbonping:DummyPing
  3. Initialize ribbonserverlist:ConfigurationBasedServerList
  4. Initialize serverlistupdater:new PollingServerListUpdater(config)
  5. Initialize iloadbalancer:ZoneAwareLoadBalancer
  6. Initialize ribbonserverlistfilter:ZonePreferenceServerListFilter
  7. Initialize ribbonloadbalancercontext:RibbonLoadBalancerContext
  8. Initialize serverintrospector:DefaultServerIntrospector

About blockingloadbalancerclient:

Spring Cloud Hoxton. After release, a new load balancer implementation was addedBlockingLoadBalancerClient。 It is the first to containBlocking typeandNon blockingThe version of the load balancer client implementation as an alternative to Netflix ribbon that has entered maintenance mode.

If you want toRestTemplateUse newBlockingLoadBalancerClient, need to increasespring-cloud-loadbalancerOtherwise, it is used by defaultRibbonLoadBalancerClient