SpringCloud - Load Balancer Ribbon

Introduction to Ribbon

Ribbon is a load balancer that manages HTTP and TCP service clients. Ribbon has a list of clients with names, aka Ribbon clients with names. Each client is composed of configurable components and is responsible for invoking requests for a class of services. Spring Cloud creates an ApplicationContext context for each Ribbon client through RibbonClientConfiguration for component assembly. As an implementation of Spring Cloud's load balancing mechanism, Ribbon can be seamlessly integrated with OpenFeign and RestTemplate, so that both also have load balancing capabilities.

load balancing strategy

Strategy name Remark
RoundRobinRule rotation strategy Cycle through servers in order
RandomRule random strategy Randomly select Server
RetryRule retry strategy In a configuration period, when the server selection is unsuccessful, it always tries to select an available server
BestAvailableRule Minimum Concurrency Policy Check the servers one by one, if the server circuit breaker is open, ignore it, and then select the server with the lowest concurrent connection
AvailabilityFilteringRule Available filter policies Filter out the servers that have been failing to connect and are marked as servers, and filter out those servers with high concurrent connections (active connections exceed the configured network value) circuit tripped 
ResponseTimeWeightedRule Response Time Weighting Policy Weights are assigned based on the server's response time. 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. This strategy is very appropriate, combining various factors, such as: network, disk, IO, etc., these factors directly affect the response time
ZoneAvoidanceRule Regional trade-off strategy Comprehensively judge the performance of the region where the server is located and the availability of the server, select the server by polling, and determine whether the operating performance of an AWS zone is available, and eliminate all servers in the unavailable zone.

Environmental preparation

category value
JDK 1.8.0_162
SOFABoot / SpringBoot 3.0.0/2.0.x.RELEASE
SpringCloud Finchley.RC1
HERE IDEA

Engineering background

This section will create a sofa-eureka-consumer-Ribbon project to achieve load balancing of services through the load balancer Ribbon provided by Spring Cloud, and verify the load balancing strategy in Ribbon.

Newly built sofa-eureka-consumer-ribbon

This project continues to use the parent project in "SpringCloud-Eureka Service Registration" to build.

Right-click on the parent project of sofa-eureka-parent -> New -> Module, select the Maven project here;

  • artifactId:sofa-eureka-consumer-ribbon

We have already performed the actual operation of feign earlier, so this section uses the Ribbon + RestTemplate combination to implement specific load balancing experiments.

Modify pom file

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<parent>
<artifactId>sofa-eureka-parent</artifactId><groupId>com.alipay.sofa</groupId><version>0.0.1-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion>  
  
  



<artifactId>sofa-eureka-consumer-ribbon</artifactId>

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

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

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

</dependencies>

配置文件

1
2
3
4
5
6
7
8
9
server:
  port: 8889
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
spring:
  application:
    name: eureka-consumer-ribbon

启动类

这里需要引入 @EnableEurekaClient 注解,表示当前是一个客户端。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@SpringBootApplication
@EnableEurekaClient
public class SofaEurekaConsumerRibbonApplication {

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

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

@LoadBalanced : Spring Cloud 为客户端负载均衡创建了特定的注解,被该注解修饰的 RestTemplate Bean实例,Spring Cloud 就会让 RestTemplate 使用相关的负载均衡策略,默认情况下使用的就是 Ribbon。

资源类

这里我们通过 restTemplate 去访问 Provider 提供的服务,需要注意,这里为了演示作用,直接将资源 Url 固定写成:http://HELLOSOFASERVICE/hello HELLOSOFASERVICE 为 Provider 提供的服务的实例名称,也就是 Eureka 服务端界面上对应的 Application。

1
2
3
4
5
6
7
8
9
10
11
@RestController
public class RibbonController {

    @Autowired
    private RestTemplate restTemplate;

    @RequestMapping("/hello")
    public String hello(){
        return restTemplate.getForObject("http://HELLOSOFASERVICE/hello",String.class);
    }
}

启动服务

这里正常先后启动 服务注册中心 sofa-eureka-server-center ;服务提供方 sofa-eureka-provider ,服务提供方为了方便演示,这里启动4个实例,对应的端口分别为:8081,8082,8083,8084,如下:

image.png

然后启动当前 sofa-eurek-consumer-ribbon 工程。默认情况下,不指定任何负载均衡策略,使用的是轮询策略。

浏览器输入 http://localhost:8889/hello ,调用10次:

1
2
3
4
5
6
7
8
9
10
11
12
Hello SOFA! Now Port is 8081 And hostname is HelloSOFAService
Hello SOFA! Now Port is 8082 And hostname is HelloSOFAService
Hello SOFA! Now Port is 8083 And hostname is HelloSOFAService
Hello SOFA! Now Port is 8084 And hostname is HelloSOFAService
  
Hello SOFA! Now Port is 8081 And hostname is HelloSOFAService
Hello SOFA! Now Port is 8082 And hostname is HelloSOFAService
Hello SOFA! Now Port is 8083 And hostname is HelloSOFAService
Hello SOFA! Now Port is 8084 And hostname is HelloSOFAService
  
Hello SOFA! Now Port is 8081 And hostname is HelloSOFAService
Hello SOFA! Now Port is 8082 And hostname is HelloSOFAService

 

从结果来看,默认策略应该是轮询(不用情况下,调用顺序不一定是1-2-3-4,但是以每4组为一组来看,存在周期性)。

负载均衡策略设置

全局设置

全局设置就是自己定义一个配置类,然后在配置类中指定具体的负载均衡策略。在com.alipay.sofa.cloud.configuration 包下面新建一个配置类,这里使用的策略是随机策略:

1
2
3
4
5
6
7
@Configuration
public class RibbonGlobalLoadBalancingConfiguration {
    @Bean
    public IRule ribbonRule() {
        return new RandomRule();
    }
}

浏览器输入 http://localhost:8889/hello ,调用10次:

1
2
3
4
5
6
7
8
9
10
11
12
Hello SOFA! Now Port is 8083 And hostname is HelloSOFAService
Hello SOFA! Now Port is 8084 And hostname is HelloSOFAService
Hello SOFA! Now Port is 8084 And hostname is HelloSOFAService
Hello SOFA! Now Port is 8083 And hostname is HelloSOFAService
  
Hello SOFA! Now Port is 8082 And hostname is HelloSOFAService
Hello SOFA! Now Port is 8083 And hostname is HelloSOFAService
Hello SOFA! Now Port is 8082 And hostname is HelloSOFAService
Hello SOFA! Now Port is 8084 And hostname is HelloSOFAService
  
Hello SOFA! Now Port is 8081 And hostname is HelloSOFAService
Hello SOFA! Now Port is 8081 And hostname is HelloSOFAService

从结果来看,具有随机属性。

针对单个服务的 Ribbon 负载均衡策略

新建一个 RibbonRandomLBConfiguration 配置类,这里有个前提是需要删除 全局配置类 。

1
2
3
4
5
6
@Configuration
public class RibbonRandomLBConfiguration {
    @Bean
    public IRule ribbonRule() {
        return new RandomRule();
    }

修改启动类,增加 @RibbonClient 注解,并且通过 configuration 指定负载均衡策略。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@SpringBootApplication
@EnableEurekaClient
@RibbonClient(name="HELLOSOFASERVICE",configuration = RibbonRandomLBConfiguration.class)
public class SofaEurekaConsumerRibbonApplication {

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

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

浏览器输入 http://localhost:8889/hello ,调用10次:

1
2
3
4
5
6
7
8
9
10
11
12
Hello SOFA! Now Port is 8083 And hostname is HelloSOFAService
Hello SOFA! Now Port is 8081 And hostname is HelloSOFAService
Hello SOFA! Now Port is 8083 And hostname is HelloSOFAService
Hello SOFA! Now Port is 8083 And hostname is HelloSOFAService
  
Hello SOFA! Now Port is 8084 And hostname is HelloSOFAService
Hello SOFA! Now Port is 8082 And hostname is HelloSOFAService
Hello SOFA! Now Port is 8082 And hostname is HelloSOFAService
Hello SOFA! Now Port is 8081 And hostname is HelloSOFAService
  
Hello SOFA! Now Port is 8081 And hostname is HelloSOFAService
Hello SOFA! Now Port is 8083 And hostname is HelloSOFAService

从结果来看,具有随机属性。

@RibbonClient 注解属性中,name 并非是一个数组,也就是说只能指定一个服务实例。那么基于上述情况,如果还存在另外一个服务,比如 SOFABOOTHELLOSERVICE ,那么对于此服务的调用会是什么情况呢?

先向注册中心注册两个服务:HELLOSOFABOOTSERVICE 和 HELLOSOFASERVICE**

image.png

修改 RibbonController ,增加一个 /helloBoot 资源地址:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@RestController
public class RibbonController {

    @Autowired
    private RestTemplate restTemplate;

    @RequestMapping("/hello")
    public String hello(){
        return restTemplate.getForObject("http://HELLOSOFASERVICE/hello",String.class);
    }

    @RequestMapping("/helloBoot")
    public String helloBoot(){
        return restTemplate.getForObject("http://HELLOSOFABOOTSERVICE/hello",String.class);
    }
}

重启启动当前服务。

浏览器中输入:http://localhost:8889/hello ,验证结果满足随机调用。

浏览器中输入:http://localhost:8889/helloBoot ,验证结果满足轮询调用。

基于配置文件的负载均衡策略设置

个人感觉基于配置文件配置方式更加直观,而且对于多个服务对应不同的负载策略设置也更加清晰,下面对HELLOSOFASERVICE 和 HELLOSOFABOOTSERVICE 均使用随机策略。

1
2
3
4
5
6
7
HELLOSOFASERVICE:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

HELLOSOFABOOTSERVICE:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

启动类中删除以下注解配置:

1
@RibbonClient(name = "HELLOSOFASERVICE", configuration = RibbonRandomLBConfiguration.class)

重启启动当前服务。

浏览器中输入:http://localhost:8889/hello ,验证结果满足随机调用。
浏览器中输入:http://localhost:8889/helloBoot ,验证结果满足随机调用。

{{o.name}}
{{m.name}}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324152030&siteId=291194637