1. Built-in load balancing rules

1.1 RoundRobinRule

Direct round robin: Select a server from a list of servers in round robin. The requests evenly distributed by each server are roughly equal

1.2 AvailabiltyFileringRule

This checks the availability of the server, and if three attempts fail, it waits 30 seconds to try again; If you continue to fail, the wait time gets longer and longer, and if a server has too many concurrent requests, it gets bypassing and never visits again

1.3 WeightedResponseTimeRule

This represents the weight, each server can have a weight, the weight of the high priority access, if a server response time is long, then the weight will be reduced, reducing access

1.4 ZoneAvoidanceRule

Will be responsible for the balance according to the region and server, which is the meaning of the computer room

1.5 BestAvailableRule

Ignore the servers that fail to connect, and try to find a server with low concurrency

1.6 RandomRule

Pick a random server

1.7 RetryRule

The request can be retried, that is, the round Robin server fails to find a new server

2. Basic integration principles

3. General process of source code level

4.@LoadBalanced Minimalist process

  • First by @ loadBalanced annotations, find the corresponding related configuration class LoadBalancerAutoConfiguration, he still has a class that is responsible for an asynchronous invocation, AsyncLoadBalancerAutoConfiguration
  • Within this class, a collection of empty RestTemplates is built to hold the restTemplate instance of the annotation tag
  • The RestTemplate will be customized by the restTemplateCustomizer when it is initialized, we mark it as a normal RestTemplate, So all restTemplates are loaded with a simple LoadBalancerInterceptor interceptor
  • In the execution LoadBalancerAutoConfigutaion for automatic assembly, will be the annotations, To execute the first @ AutoConfigureBefore ({LoadBalancerAutoConfiguration. Class, AsyncLoadBalancerAutoConfiguration. Class}), to execute the first RibbonAutoConfigutaion this class, the initialization information, The main thing is to de-initialize the LoadBalancedClient object to RibbonLoadBalancerClient

* * * *

5.LoadBalancedInterceptor

  • The general process is the same as above. Each time we use the restTemplate to send a request, we first encapsulate the information as an HttpRequest object
  • The interceptor added by customizer calls the interceptor method
  • Parse the URI from the request object, parse the service name from the URI, and determine whether the service name is null or not
  • Subsequent calls requestFactory. CreateRequest (request, body, execution), create LoadBalancerRequest
  • The parsed service name and constructed LoadBalancerRequest are handed to LoadBalancerClient to execute the request
  • LoadBalancerClient is in the spring – the cloud – netflix – the core project, the org.springframework.cloud.net flix. Ribbon package, this project is mainly a glue code, Responsible for the integration of the various components, the RibbonAutoConfiguration class was found in it
@Configuration
@ConditionalOnClass({ IClient.class, RestTemplate.class, AsyncRestTemplate.class, Ribbon.class})
@RibbonClients
@AutoConfigureAfter(name = "org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration")
@AutoConfigureBefore({LoadBalancerAutoConfiguration.class, AsyncLoadBalancerAutoConfiguration.class})
@EnableConfigurationProperties({RibbonEagerLoadProperties.class, ServerIntrospectorProperties.class})
public class RibbonAutoConfiguration {
    
    // This will be implemented after the Eureka client
    / / in LoadBalancerAutoConfiguration initialization before the execution
    
    / / so in LoadBalancerAutoConfiguration LoadBalancerClient from this in class
    RibbonLoadBalancerClient instance object is constructed
    
    @Bean
    @ConditionalOnMissingBean(LoadBalancerClient.class)
    public LoadBalancerClient loadBalancerClient(a) {
        return newRibbonLoadBalancerClient(springClientFactory()); }}Copy the code
  • So basically, the request from the restTemplate, decorated with the @loadbalanced annotation, is added to the interceptor, which is ultimately carried out by the RibbonLoadBalancerClient

6. RibbonLoadBalancerClient. Execute execution

6.1 ILoadBalancer loadBalancer = getLoadBalancer(serviceId)

  • The instance object is first obtained from SpringClientFactory using the getLoadBalancer method
  • NamedContextFactory will be called from the Context of the Contexts service for this context,
  • Each service name corresponds to a service context object, encapsulated in a Map data structure.
  • The LoadBalancer instance is obtained from the service context object based on Type. The Type we passed was ILoadBalancer, so the ILoadBalancer interface is returned
  • So what is the interface type, we can be found in the RibbonClientConfiguration this class, ILoadBalancer initialization is ZoneAwareLoadBalancer this object, DynamicServerListLoadBalancer is his parent, it is the parent of the BaseLoadBalancer proceeds is AbstractLoadBalancer at up will find implements ILoadBalancer, So this could be an ILoadBalancer interface, but of type ZoneAwareLoadBalancer

* * * *

6.2 ZoneAwareLoadBalancer Obtaining the registry

A call request is first intercepted by the interceptor. Interrupt is used to obtain the URL and parse the ServiceName from the URL. The ServiceName is executed by the RibbonLoadBalancerClient. The execute method is called.

First through the context of the service name access to the service object, through IloadBalancer. Class access to the corresponding IloadBalancer interface, but this interface, in RibbonClientConfiguration class, This is initialized via the @bean, so the corresponding implementation class for ILoadBalancer is the ZoneAwareLoadBalancer instance.

When building the ZoneAwareLoadBalancer, the restOfInit method is called, and the updateListOfServers method is called to get the registry. This method is executed primarily by ServerImpl, which is passed in from the constructor when the ZoneAwareLoadBalancer instance is created, We can be found from EurekaRibbonClientConfiguration class will to construct ServerList will create DiscoveryEnabledNIWSServerList instance, And by the DomainExtractingServerList, that is to say, the last ServerList interface implementation class is the class DomainExtractingServerList.

So to make calls through ServerImpl, which is equivalent to calling DomainExtractingServerList getInitialListOfServers method, because at the time of creation, Is actually the DiscoveryEnabledNIWSServerList to it management, so the final implementation method is * * DiscoveryEnabledNIWSServerList obtainServersViaDiscovery * *.

The main logic here is to obtain the EurekaClient instance, obtain the corresponding service instance by the service name, and put the address of the service instance into a service instance collection. Of course, some trivial things will be done in the process, but the general process is like this: By building the ZoneAwareLoadBalance through the realization of the initialization has good ServerLIist DiscoveryEnabledNIWSServerList responsible and eureka cient interact, Obtain the corresponding service information through the service name, and add the service instance address to the collection for later use.

So, in our actual use of eureka information is will change, so will be at the time of call restOfInit method, called enableAndInitLearnNewServersFeature inside it, the main or call the method that the above the access to the registry, It also initializes a scheduling task that invokes every 30 seconds with a delay of one second and updates the registry information every 30 seconds.

6.3 Obtaining the Service Address using an Algorithm

Will first through getServer () method to call BaseLoadBalancer. ChooseServer method, through an example of IRule rules were selected, and the default instance is PredicateBasedRule, The core implementation is the incermentAndGetModulo method called in the AbstractServerPredicate class. The internal algorithm is also relatively simple. It takes the current value +1 and the number of services and modifies the current value to the calculated value

for (;;) {
            int current = nextIndex.get();
            int next = (current + 1) % modulo;
            if (nextIndex.compareAndSet(current, next) && current < modulo)
                return current;
        }
Copy the code

7. The mechanism of Ping

The native Ribbon has a ping mechanism. There is an IPing component that ping the server to see if the server is alive. In this way, we can only access those that are alive.

By default, when creating ZoneAwareLoadBalancer, an IPing component is passed in, It is on the org.springframework.cloud.net flix. Ribbon. Eureka package under EurekaRibbonClientConfiguration initialize the class, Basically, you create a NIWSDiscoveryPing object.

NIWSDiscoveryPing The method of Ping verification is very simple. It is to obtain the InstanceInfo instance object corresponding to each service and determine whether the InstanceInfo instance object is in up state.

ZoneAwareLoadBalancer () : BaseLoadBalancer () : PingTask (); It will be called every 30 seconds, mainly to obtain the collection of service instances, traverse this collection, call the isAlive method of NIWSDiscoveryPing to determine whether the service instance isAlive (that is, to determine whether the corresponding state of the current service instance is up).