Idea build SpringCloud (3)------Ribbon implements load balancing and its custom algorithm strategy

Spring Cloud provides a component Ribbon. Spring Cloud Ribbon is a client-side load balancing tool based on Http and TCP. It is implemented based on Netflix Ribbon .

Why do you need to implement load balancing for SpringCloud? Load balancing is a common means for clusters or distributed to reduce server pressure, not only for microservices, but in another set of distributed architecture Zookeeper, Dubbo, commonly used soft load balancing is nginx. In Spring Cloud, there may be multiple service providers, and users visit the providers with consumers. Naturally, load balancing is needed to realize the equal sharing of pressure among servers. Before we build load-balanced microservices, let's build the integration of Eureka and Ribbon to achieve the real access to the microservice name through rest to call the microservice.

For consumers, it is the entry point for access, so it needs to add Ribbon's dependency, and Ribbon needs to depend on Eureka, so Eureka's dependency should also be added:

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

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

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-config</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-ribbon</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

Add in application.yml:

server:
  port: 80

eureka:
  client:
    register-with-eureka: false
    service-url:
      defaultZone: http://localhost:7001/eureka/,http://localhost:7002/eureka/,http://localhost:7003/eureka/

 The port number is port 80, which is configured to connect to the Eureka service registration center. The connection here is mainly because the consumer will first obtain the provider's information from Eureka, including the service application name, IP address, port number, and so on.

Start class:

@SpringBootApplication
@EnableEurekaClient
public class EurekaServerConsumerApplication {

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

}

Then the key point comes! In the project we built before, consumers use the specific URL of RestTempete to access the provider, but for real microservices, this is not standard, and load balancing cannot be written in this way. It should be through microservice applications Name to visit the provider.

First, add the @LoadBanlanced annotation on the RestTemplate. After adding this annotation, the RestTemplate can recognize the microservice application name to access the provider, otherwise it cannot be accessed.

@Configuration
public class ConfigBean {

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

Access through the microservice application name, http://microservice application name/url, here I set the microservice name as EUREKA-SERVER-PROVIDER

@RequestMapping("/consumer/test3")
    public String test3(){
        return restTemplate.getForObject("http://EUREKA-SERVER-PROVIDER/provider/test",String.class);
    }

 In this way, the integration of Eureka and Ribbon to access the provider through the microservice application name is successful.

The above only implements access to the provider through the microservice application name, but does not implement load balancing, because load balancing is based on accessing the provider through the microservice application name, so our last step is to achieve load balancing Play well. Let's implement load balancing below.

We create and start three service providers, 8001, 8002, and 8003, and set their microservice application names to be consistent .

8001 configuration files, 8002 and 8003 configuration files are similar to 8001, but the port number is different:

server:
  port: 8001

eureka:
  client:
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/  #Eureka Server url
      instance-id: eureka-server-provider-test #修改主机名称
      prefer-ip-address: true  #设置主机ip映射


spring:
  application:
    name: eureka-server-provider #该微服务应用名称

 Then we look back at the consumer configuration file, we set it in the consumer's application.yml above

eureka:
  client:
    register-with-eureka: false
    service-url:
      defaultZone: http://localhost:7001/eureka/,http://localhost:7002/eureka/,http://localhost:7003/eureka/

This setting is very important, we can try once it is not set, the following error will occur when the user accesses through the consumer:

 

We can see that there is such a sentence No instances available for EUREKA-SERVER-PROVIDER, which means that the microservice named EUREKA-SERVER-PROVIDER cannot be found, then we go to the registry to see if this microservice exists

It can be found that this microservice exists, so it can be proved that the consumer needs to query the provider's information in the registry before accessing, such as the microservice application name, ip address, port number, etc., and then obtain it through The name of the microservice application can access the provider, and how to get this information in the registry is to configure the connection to the registry above.

Closer to home, add the following RequestMapping to the 8001, 8002 and 8003 service providers for testing.

8001:

@RequestMapping("/provider/test")
    public String test(){
        return "这是provider01";
    }

8002:

@RequestMapping("/provider/test")
    public String test(){
        return "这是provider02";
    }

8003:

@RequestMapping("/provider/test")
    public String test(){
        return "这是provider03";
    }

 Then we start Eureka clusters 701, 7002 and 7003, service providers 8001, 8002 and 8003, and service consumer 80, and visit http://localhost/consumer/test through consumers

First visit:

Second visit:

Third visit:

Then every visit below is 02, 01, 03 (polling algorithm, Ribbon default), so our load balancing has been implemented successfully.

Summary: We have started 7 microservice processes above, of which 3 Eureka registries form a cluster, 3 service providers (the microservice application names all want the same group of service providers), a service consumer, and a service After the consumer starts, it will connect to the Eureka registry to obtain the microservice application name (and other information) of the successfully registered service provider, and then save it locally. The next time the user visits the provider through the consumer, it will be saved according to the previous The information (name of the microservice application) of multiple providers to access the provider, according to the @LoadBanlanced annotation to achieve load balancing purposes, and if the provider goes down, the registry will notify the consumer to update the previously saved provider in time In this way, service consumers, registration centers, and service providers can work together.

The previous picture below illustrates the above summary:

 

 Replace Ribbon's default load balancing strategy

The default load balancing strategy in Ribbon is carried out through polling, and the polling algorithm strategy is through the implemented IRule interface

In Ribbon, there are other algorithm strategies that Ribbon has helped us implement. They are:

  • RoundRobinRule polling
  • RandomRule random
  • AvailabilityFilteringRule will first filter out services that are in a circuit breaker trip state due to multiple access failures, and services that have concurrent connections exceeding the threshold, and then poll the list of remaining services
  • The WeightedResponseTimeRule weight calculates the weight of all services based on the average response time. The faster the response time, the higher the service weight, the higher the probability of being selected. At the
    beginning , if the statistical information is insufficient, the polling strategy is used, and when the information is sufficient, switch to WeightedResponseTimeRule RetryRule Retry First obtain the service according to the polling strategy, if the acquisition fails, retry within the specified time to obtain the available services
  • BestAvailableRule selects and filters out services that are in the circuit breaker trip state due to multiple access failures, and then selects a service with the least concurrency
  • ZoneAvoidanceRule is in line with the selection service for judging the performance of the area where the server is located and the availability of the server

So if we want to change the algorithm strategy, we must tell Ribbon the strategy we need.

@Configuration
public class ConfigBean {

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

    @Bean
    public IRule iRule(){
        return new RandomRule();
    }
}

In this way, if we do not tell Ribbon, then Ribbon will use the default polling algorithm strategy. If we declare it in the configuration class, then we will use the algorithm strategy we declared.

Custom algorithm strategy 

In addition to the above Ribbon's own algorithm strategy, we can also implement the algorithm strategy ourselves

First create a new configuration class. Note that this configuration class cannot be in the @ComponentScans package or sub-packages, and our @SpringbootApplication annotation inherits the @ComponentScans annotation, so our matching class cannot be in the same package or in the same package as the startup class. Under the package.

Customized polling algorithm, each server visits 5 times and then to the next server visits 5 times. And so on

	private int total = 0; 			// 总共被调用的次数,目前要求每台被调用5次
	private int currentIndex = 0;	// 当前提供服务的机器号
            if(total < 5)
            {
	            server = upList.get(currentIndex);
	            total++;
            }else {
	            total = 0;
	            currentIndex++;
	            if(currentIndex >= upList.size())
	            {
	              currentIndex = 0;
	            }
            }			

Finally, add the @RibbonClient annotation to the startup class, the attribute name is to declare which group of service providers it is used for, and configuration is the configuration class we just defined

@SpringBootApplication
@EnableEurekaClient
@RibbonClient(name = "MICROSERVICECLOUD-DEPT",configuration = MyRule.class)
public class EurekaServerConsumerApplication {

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

}

This completes the implementation of our custom algorithm strategy. 

 

 

 

 

 

 

 

 

 

Guess you like

Origin blog.csdn.net/weixin_37689658/article/details/88585839