天天看点

SpringCloud入门(三):服务消费者RestTemplate+Ribbon(Greenwich.SR2)

以上一篇【SpringCloud入门(二):Restful API-RestTemplate(Greenwich.SR2)】为基础来继续。

我们知道RestTemplate是负责服务与服务之间的通讯的,但在微服务中,一般上服务都不会进行单点部署的,都会至少部署2台及以上的。现在我们有了注册中心进行服务列表的维护,就需要一个客户端负载均衡来进行动态服务的调用。

何为负载均衡

负载均衡(Load Balance)是分布式系统架构设计中必须考虑的因素之一,它通常是指,将请求/数据【均匀】分摊到多个操作单元上执行,负载均衡的关键在于【均匀】。

Ribbon

Spring Cloud Ribbon是一个基于Http和TCP的客服端负载均衡工具,它是基于Netflix Ribbon实现的。与Eureka配合使用时,Ribbon 可自动从Eureka Server (注册中心) 获取服务提供者地址列表,并基于负载均衡算法,通过在客户端中配置ribbonServerList来设置服务端列表去轮询访问以达到均衡负载的作用。

服务提供者

在microservice-provider模块中,新增getRibbonBalancer接口。启动8764和8765两个端口。

idea多端口方式之一,-Dserver.port=8765

SpringCloud入门(三):服务消费者RestTemplate+Ribbon(Greenwich.SR2)
/**
     * @describe Ribbon负载均衡测试
     * @author: hero良
     * @param
     * @return:
     */
    @GetMapping("/getRibbonBalancer")
    public String getRibbonBalancer(String name){
        log.debug("************接受到请求*************");
        return "hello !" + name+" , this is 8764";
    }

           

两个实例都已经注册到注册中心

SpringCloud入门(三):服务消费者RestTemplate+Ribbon(Greenwich.SR2)

服务消费者,分两种情况

  • 项目使用了eureka
  • 项目未使用eureka
1.使用eureka

pom依赖

<!--使用了eureka-->
<dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
 </dependency>
           

yml

spring:
  application:
    name: ribbon

server:
  port: 8766

eureka:
  client:
    service-url:
      #单机版
      defaultZone: http://eureka1:8761/eureka/
      #集群模式
    #      defaultZone: http://eureka1:8761/eureka/,http://eureka2:8762/eureka/,http://eureka3:8763/eureka/
           
2.未使用eureka

需要引入ribbon依赖

<!--项目未使用eureka-->
<!--<dependency>-->
     <!--<groupId>org.springframework.cloud</groupId>-->
     <!--<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>-->
 <!--</dependency>-->
           

yml

provider-service:
  ribbon:
#    未使用eureka或者禁用从注册中心获取服务提供者信息时,需要自己维护地址  请求的服务地址,ip:port,多个时使用 逗号 隔开
    listOfServers: 127.0.0.1:8764,127.0.0.1:8765
           

在RestTemplate配置Bean新增 @LoadBalanced

@Bean
@LoadBalanced //开启负载均衡注解
 public RestTemplate restTemplate(){
     return new RestTemplate();
 }
           

这里直接使用服务名调用

public String getRibbonBalancer(String name){
        return restTemplate.getForObject("http://provider-service/appController/getRibbonBalancer?name="+name, String.class);
    }
           
/**
     * @description ribbon的负载均衡
     * @author hero良
     * @param name
     * @return java.lang.String
     * @exception
     * @version  1.0
     */
    @GetMapping("/getRibbonBalancer")
    public String getRibbonBalancer(String name){
        return ribbonService.getRibbonBalancer(name);
    }
           

使用postman来测试接口8764和8765交替出现,因为Ribbon的负载策略默认是轮询

SpringCloud入门(三):服务消费者RestTemplate+Ribbon(Greenwich.SR2)
SpringCloud入门(三):服务消费者RestTemplate+Ribbon(Greenwich.SR2)

在yml中类修改负载策略,也可以使用Bean的方式来配置。

provider-service:
  ribbon:
    #负载均衡策略
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule #配置规则 随机
    #  NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RoundRobinRule #配置规则 轮询
    #  NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RetryRule #配置规则 重试
    #  NFLoadBalancerRuleClassName: com.netflix.loadbalancer.WeightedResponseTimeRule #配置规则 响应时间权重
    #  NFLoadBalancerRuleClassName: com.netflix.loadbalancer.BestAvailableRule #配置规则 最空闲连接策略
           

provider-service 表示局部配置,只针对这个服务有效,也可以使用全局配置,如下

ribbon:
    #负载均衡策略
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule #配置规则 随机
           

Ribbon的超时、重试

RestTemplate结合Ribbon时,超时需要配置RestTemplate的超时,配置Ribbon时无效。

@Bean
@LoadBalanced //开启负载均衡注解
public RestTemplate restTemplate(){
   HttpComponentsClientHttpRequestFactory httpRequestFactory = new HttpComponentsClientHttpRequestFactory();
   httpRequestFactory.setConnectTimeout(500);
   httpRequestFactory.setReadTimeout(2000);
   return new RestTemplate(httpRequestFactory);
}

//无效
serviceId:
	ribbon:
		ReadTimeout: 1000
		ConnectTimeout: 1000
           

Ribbon通过增加Spring-retry还有相关配置开启了重试,这个重试机制对于OpenFeign是不起作用的,但是对于 @LoadBalanced注解修饰的RestTemplate是有作用的。

<!-- https://mvnrepository.com/artifact/org.springframework.retry/spring-retry -->
        <!--重试需要此依赖-->
        <dependency>
            <groupId>org.springframework.retry</groupId>
            <artifactId>spring-retry</artifactId>
            <version>1.2.4.RELEASE</version>
        </dependency>
           

yml配置

provider-service:
  ribbon:
    #负载均衡策略
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule #配置规则 随机
    #  NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RoundRobinRule #配置规则 轮询
    #  NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RetryRule #配置规则 重试
    #  NFLoadBalancerRuleClassName: com.netflix.loadbalancer.WeightedResponseTimeRule #配置规则 响应时间权重
    #  NFLoadBalancerRuleClassName: com.netflix.loadbalancer.BestAvailableRule #配置规则 最空闲连接策略
    # 同一实例最大重试次数,不包括首次调用
    MaxAutoRetries: 1
    # 重试其他实例的最大重试次数,不包括首次所选的server
    MaxAutoRetriesNextServer: 2
    # 是否所有操作都进行重试
    #当OkToRetryOnAllOperations设置为false时,只会对get请求进行重试。
    #如果设置为true,便会对所有的请求进行重试,如果是put或post等写操作,
    #如果服务器接口没做幂等性,会产生不好的结果,所以OkToRetryOnAllOperations慎用。
    OkToRetryOnAllOperations: false
           

新增getRibbonTimeout接口

/**
     * @description ribbon的超时与重试
     * 超时需要在创建RestTemplate的时候指定时间,配置在配置文件中不生效,重试需要引入Spring-retry依赖
     * @author hero良
     * @return java.lang.String
     * @exception
     * @version  1.0
     */
    @GetMapping("/getRibbonTimeout")
    public String getRibbonTimeout(){
        return restTemplate.getForObject("http://provider-service/appController/getRibbonTimeout", String.class);
    }
           

服务提供者

这里使用了sleep,让线程阻塞,达到超时重试的效果,sleep的时间要比设置的超时时间大,不然等于没设置。

/**
     * @describe Ribbon超时测试
     * @author: hero良
     * @param
     * @return: 
     */
    @GetMapping("/getRibbonTimeout")
    public String getRibbonTimeout(){
        log.debug("************接受到请求*************");
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "hello";
    }
           

调用后我们可以看到服务端的日志输出

SpringCloud入门(三):服务消费者RestTemplate+Ribbon(Greenwich.SR2)
SpringCloud入门(三):服务消费者RestTemplate+Ribbon(Greenwich.SR2)

两个服务加起来一共是6次请求,既实现了负载均衡也实现了 超时重试

重试计算公式

MaxAutoRetries+MaxAutoRetriesNextServer+(MaxAutoRetries * MaxAutoRetriesNextServer) ,即重试5次 (不包括首次调用)一共产生6次调用。

继续阅读