• 欢迎访问 winrains 的个人网站!
  • 本网站主要从互联网整理和收集了与Java、网络安全、Linux等技术相关的文章,供学习和研究使用。如有侵权,请留言告知,谢谢!

SpringCloud:负载均衡器 Ribbon

Spring Cloud winrains 来源:GuoLei Song 8个月前 (03-21) 51次浏览
上一篇 SpringCloud-声明式服务调用 Feign 中介绍了如何使用 Feign 来完成服务调用。因为 Feign 本身已经集成了 Ribbon ,所以也具有负载均衡的能力。那么本篇将使用 RestTemplate + Ribbon 来实现服务调用和负载均衡策略。

Ribbon 简介

Ribbon 是管理HTTP和TCP服务客户端的负载均衡器。Ribbon 具有一些列带有名称的客户端,也就是带有名称的Ribbon 客户端。每个客户端由可配置的组件构成,负责一类服务的调用请求。Spring Cloud 通过RibbonClientConfiguration 为每个Ribbon 客户端创建一个ApplicationContext 上下文来进行组件装配。Ribbon 作为 Spring Cloud的负载均衡机制的实现,可以与OpenFeign 和 RestTemplate 进行无缝集成,让二者也具有负载均衡的能力。

负载均衡策略

策略类 命名 备注
RoundRobinRule 轮训策略 按顺序循环选择 Server
RandomRule 随机策略 随机选择 Server
RetryRule 重试策略 在一个配置时问段内当选择 Server 不成功,则一直尝试选择一个可用的 Server
BestAvailableRule 最低并发策略 逐个考察 Server,如果 Server 断路器打开,则忽略,再选择其中并发连接最低的 Server
AvailabilityFilteringRule 可用过滤策略 过滤掉一直连接失败并被标记为 circuit tripped 的 Server,过滤掉那些高并发连接的 Server(active connections 超过配置的网值)
ResponseTimeWeightedRule 响应时间加权策略 根据 Server 的响应时间分配权重。响应时间越长,权重越低,被选择到的概率就越低;响应时间越短,权重越高,被选择到的概率就越高。这个策略很贴切,综合了各种因素,如:网络、磁盘、IO等,这些因素直接影响着响应时间
ZoneAvoidanceRule 区域权衡策略 综合判断 Server 所在区域的性能和 Server 的可用性轮询选择 Server,并且判定一个 AWS Zone 的运行性能是否可用,剔除不可用的 Zone 中的所有 Server

环境准备

类别
JDK 1.8.0_162
SOFABoot/SpringBoot 3.0.0/2.0.x.RELEASE
SpringCloud Finchley.RC1
IDE IDEA

工程背景

本节将会创建一个 sofa-eureka-consumer-Ribbon 工程,通过 Spring Cloud 提供的负载均衡器 Ribbon 实现服务的负载均衡,并对 Ribbon 中的负载均衡策略进行验证。

新建 sofa-eureka-consumer-ribbon

本工程继续使用《SpringCloud-Eureka 服务注册》中的父工程来构建。

右击 sofa-eureka-parent 父工程 -> New -> Module,这里选择 Maven 工程;

  • artifactId:sofa-eureka-consumer-ribbon

前面我们已经对feign进行的实际操作,因此本节使用 Ribbon + RestTemplate 组合实现具体的负载均衡实验。

修改 pom 文件

<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>

配置文件

server:
  port: 8889
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
spring:
  application:
    name: eureka-consumer-ribbon

启动类

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

@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/helloHELLOSOFASERVICE 为 Provider 提供的服务的实例名称,也就是 Eureka 服务端界面上对应的 Application。

@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次:

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 包下面新建一个配置类,这里使用的策略是随机策略:

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

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

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 配置类,这里有个前提是需要删除 全局配置类 。

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

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

@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次:

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 资源地址:

@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 均使用随机策略。

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

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

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

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

重启启动当前服务。

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

作者:GuoLei Song

来源:http://www.glmapper.com/2018/12/31/springcoud-ribbon-project/


版权声明:文末如注明作者和来源,则表示本文系转载,版权为原作者所有 | 本文如有侵权,请及时联系,承诺在收到消息后第一时间删除 | 如转载本文,请注明原文链接。
喜欢 (2)