SpringCloud版本Hoxton SR5 --- 第三讲:Ribbon 、Ribbon与Feign配合使用

传送门:SpringCloud版本Hoxton SR5 --- 第一讲:认识 先看Ribbon、Fegin可以完成的功能,或者说他在项目中的定位和作用。

上篇文章主要讲:功能和作用都是用大白话,主要是通俗易懂的,推荐先看看。

 

专业术语:

ribbon是什么?

 Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端负载均衡的工具。

简单的说,Ribbon是Netflix发布的开源项目,主要功能是提供客户端的软件负载均衡算法,将Netflix的中间层服务连接在一起。Ribbon客户端组件提供一系列完善的配置项如连接超时,重试等。简单的说,就是在配置文件中列出Load Balancer(简称LB)后面所有的机器,Ribbon会自动的帮助你基于某种规则(如简单轮询,随机连接等)去连接这些机器。我们也很容易使用Ribbon实现自定义的负载均衡算法。

客户端负载均衡、 服务端负载均衡区别:

初学者,下面这幅图,看看就好,看不懂也没关系,我也是从别的地方弄过来的,画的还是很好。后面我会举例说明:

其实在我看来,不需要知道什么是客户端负载均衡 和 服务端负载均衡的概念,我们就看nginx和ribbon就好了,但是概念的东西,还是写出来:

客户端负载均衡的特点:他就是一个代理服务器,他不知道接下来,访问哪个服务可以正常调用,只是按照一定的规则做调用转发。

服务端负载均衡的特点:在调用之前,就已经知道哪些微服务可以正常调用,然后从正常的服务中,按照一定的规则,进行访问。

 

上面说的其实比较抽象,接下来具体说明:

nginx:(总体来说,有2个大功能)

1. 地址映射 (就是将多个相同功能的微服务ip地址,交给nginx管理,nginx提供一个统一的ip地址)

2. 客户端负载均衡  (就是当访问nginx提供的统一ip地址之后,nginx按照一定规则分配接下来运行哪一个微服务)

nginx其实不知道接下来会调用哪个微服务,反正就是按照一定的规则,得到一个映射到的ip,然后进行访问,也不管访问的服务是否宕机,nginx完成的就是客户端负载均衡。所以反推,客户端负载均衡就只是一个代理服务器,他也不知道接下来会访问哪一个微服务。

Ribbon:(总体来说就一个功能,负载均衡)

1. 服务端负载均衡   (Ribbon只是提供负载均衡算法,与Eureka结合后实现真正的负载均衡)

Ribbon在提供负载均衡功能之前,通过Eureka的服务注册与发现,已经知道了接下来会调用哪些微服务,再根据一定的规则在这些正常的服务中间选出一个微服务节点,进行访问。

其实专门拿出来说一下,也是为了可以更好的理解:nignx与eureka的区别。

 

feign是什么 :

 Feign是一个声明式WebService客户端。使用Feign能让编写Web Service客户端更加简单, 它的使用方法是定义一个接口,然后在上面添加注解,同时也支持JAX-RS标准的注解。Feign也支持可拔插式的编码器和解码器。Spring Cloud对Feign进行了封装,使其支持了Spring MVC标准注解和HttpMessageConverters。Feign可以与Eureka和Ribbon组合使用以支持负载均衡。

feign 能干什么:

Feign旨在使编写Java Http客户端变得更容易。 当然可以不使用Fegin,而使用Ribbon+RestTemplate,利用RestTemplate对http请求的封装处理,形成了一套模版化的调用方法。但是在实际开发中,由于对服务依赖的调用可能不止一处,往往一个接口会被多处调用,所以通常都会针对每个微服务自行封装一些客户端类来包装这些依赖服务的调用。所以,Feign在此基础上做了进一步封装,由他来帮助我们定义和实现依赖服务接口的定义。在Feign的实现下,我们只需创建一个接口并使用注解的方式来配置它(以前是Dao接口上面标注Mapper注解,现在是一个微服务接口上面标注一个Feign注解即可),即可完成对服务提供方的接口绑定,简化了使用Spring cloud Ribbon时,自动封装服务调用客户端的开发量。

我还是解释一下:

其实Fegin就是对http调用的封装,直接代码调用http地址,这种调用其实就是分布式系统的核心之一,至于为什么一定要用Fegin,其实也不一定,主要人家封装的好,支持SpringMvc。比如要调用一个访问地址,直接写过Java的Controller层的代码就好了,直接就完成了数据绑定、使用的是POST还是Get等等,只要写过Controller层的代码,就会使用Fegin了,还不懂的看代码吧。

 

不说了,贴代码了:

在目前这个版本中,eureka的依赖中包含了ribbon的依赖,所以只需要添加Feign的依赖就好了。

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
配置问题:

Ribbon呢,有个好处,就是可以自定义负载均衡规则,而且不同的微服务项目之间的调用,还可以使用不同的负载均衡策略,
还可以重写负载均衡策略的代码,这里就不演示怎么重写了。反正就是实现一个类,再重写里面的方法。


为了完成,不同微服务项目调用使用不同的负载均衡策略,就需要把配置放在Spring的扫描包外面。

开始配置:


1. 配置Ribbon负载均衡启动
@SpringBootApplication
@EnableEurekaClient
@RibbonClients({ // 指定某个微服务使用某个负载均衡策略
        @RibbonClient(name = "SERVER-ORDER", configuration = OrderRuleConfig.class),
        @RibbonClient(name = "SERVER-ITEM", configuration = ItemRuleConfig.class)
})
@EnableFeignClients
public class LoginApplication {

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

}



自定义一个Ribbon负载均衡策略的类:
package com.ribbonconfig;

import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @author: wangqinmin
 * @date : 2020/6/11
 * @description: 仰天大笑出门去,我辈岂是蓬蒿人
 */
@Configuration
public class OrderRuleConfig {

    /**
     * 配置Ribbon的负载均衡策略,默认是轮循,就是说可以不配置。
     * 还有七种负载均衡策略:
     * 策略类  	            命名	描述
     * RandomRule	             随机策略	        随机选择server
     * RoundRobinRule	         轮询策略	        按照顺序选择server(ribbon默认策略)
     * 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
     *
     * @return
     */
    @Bean
    public IRule iRule() {
        return new RandomRule();
    }
}





然后自定义一个Feign的配置类:
package com.springcloud.web.fegin;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * @author: wangqinmin
 * @date : 2020/6/12
 * @description: 仰天大笑出门去,我辈岂是蓬蒿人
 * 
 * @FeignClient(name = "SERVER-ORDER")中的name,就是需要调用的微服务名字,在Eureka配置中有提到。
 * 就是yml配置文件中的:
 * spring:
 *  application:
 *  name: server-order 
 */
@FeignClient(name = "SERVER-ORDER")
public interface FeginOrderService {

    /**
     * /order/query 这个地址,就是Order微服务中,controller层某个方法,配置的访问地址。
     */
    @GetMapping("/order/query")
    @ResponseBody
    Object getOrder();
}



Feign的使用:

package com.springcloud.web.controller;

import com.springcloud.utils.R;
import com.springcloud.web.fegin.FeginItemService;
import com.springcloud.web.fegin.FeginOrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;

/**
 * @author: wangqinmin
 * @date : 2020/6/11
 * @description: 仰天大笑出门去,我辈岂是蓬蒿人
 */
@RestController
@RequestMapping("/login")
public class LoginController {

    /**
     * 注入上面自定义Fegin的配置类,用起来,和平时一样,也是注入。
     */
    @Autowired
    FeginOrderService feginOrderService;



    @GetMapping("/getFeginOrder")
    @ResponseBody
    public Object getFeginOrder() {
        /**
         * 这里使用起来,也很简单,直接调用上面Fegin配置中的方法
         * 然后就直接调用这个项目的地址,就可以访问  SERVER-ORDER/order/query 这个接口的方法了。
         */
        Object obj = feginOrderService.getOrder();
        return R.success("成功", obj);
    }

}


这样,就完成了真正的负载均衡功能了。
不用feign的话,就是再JavaConfig配置的调用类上加  @LoadBalanced注解,也就可以完成负载均衡了。
这里就不贴代码了,不会可以留言,或者百度,这个很简单。
算了算了,还是把这个配置贴出来,这样就不需要上面的Fegin配置 和 Ribbon配置,直接这个就好,但是实际看法中,应该没有人会这么用,这只是说,是一种方式:

package com.springcloud.config;

import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

/**
 * @author: wangqinmin
 * @date : 2020/6/11
 * @description: 仰天大笑出门去,我辈岂是蓬蒿人
 */
@Configuration
public class JavaConfig {

    /**
     * 当使用了@LoadBalanced这个注解之后,就可以完成负载均衡的调用了。
     *
     * @return
     */
    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }


    /**
     * 配置Ribbon的负载均衡策略,默认是轮循,就是说可以不配置。
     * 还有七种负载均衡策略:
     * 策略类  	            命名	描述
     * RandomRule	             随机策略	        随机选择server
     * RoundRobinRule	         轮询策略	        按照顺序选择server(ribbon默认策略)
     * 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
     *
     * @return
     */
    // 将配置放在扫描包外面,可以指定使用微服务的负载均衡策略。
    @Bean
    public IRule iRule() {
        return new RandomRule();
    }

}


 

 

------------------------------------------------------------------------------------------

这里是,我写Hystrix的博客时,遇到的一个Feign调用超时的问题。

今天测试降级方法的时候,给被调用微服务的一个接口的代码里设置了一个 休眠时间(线程的sleep方法)。

搞得头都大了。

报了一个错: java.net.SocketTimeoutException: Read timed out

就是说,当我用feign调用代码的时候,被调用端我设置了一个休眠时间,导致访问失败。每次都进了降级方法,按常理来说,我使用Hystrix的功能,我专门把调用端微服务的Hystrix的超时时间设置的非常大,应该就不会出问题了,结果还是报了上面的错。看了下SpringCloud官网文档,找到了这么一段话:


Figure 3. Hystrix Dashboard

6. Hystrix Timeouts And Ribbon Clients

When using Hystrix commands that wrap Ribbon clients you want to make sure your Hystrix timeout is configured to be longer than the configured Ribbon timeout, including any potential retries that might be made. For example, if your Ribbon connection timeout is one second and the Ribbon client might retry the request three times, than your Hystrix timeout should be slightly more than three seconds.


意思就是说,Hystrix设置超时时间应该,比Ribbon的超时时间更长。因为服务端被调用如果超时1秒钟,那么Ribbon重试请求要发过来的话,一定是在Hystrix没有超时之前发过来。

这句话,其实跟我的这个报错,没有关系,但是提醒我了。

我就在想,上面那个报错,到底是Ribbon报的还是Feign报的 ?

看了下源代码后,发现,如果没有配置Feign的超时时间,就直接会用Ribbon的超时时间,而Ribbon的超时时间是1秒,而我上面为了测试Hystrix的线程降级,代码里整整设置了5秒的等待时间,导致报错,知道原因了,但是还是没有解决方案。

我开始其实也想到了这个问题,还试着配置了Feign,结果在idea配置yml的时候没有对时间配置的提示(编译器的问题),有一个对httpClient的超时配置,完全没用。

然后再去Feign的官方文档找配置。

https://cloud.spring.io/spring-cloud-static/spring-cloud-openfeign/2.2.0.RELEASE/reference/html/

在1.2的目录中,看见了这个配置:

feign:
  client:
    config:
      default:
        connectTimeout: 5000
        readTimeout: 5000
        loggerLevel: basic

然而在yml中,config之后,就没有提示了。然后我把这个连接时间乘以10倍,然后配置上,终于测试成功了。

多看文档,才是王道。简直浪费时间。

 


后来在网上也找到一个解决方案,突然感觉自己对Spring的理解又上了一层,以前还没这种解决问题的思想。

就是用Spring的@Bean配置某个类。

传送门:hystrix ,feign,ribbon的超时时间配置,以及原理分析  这也是对Spring理解运用很牛的一个大神了,他的文档几乎都是对源码的分析。


    @Bean
    public Request.Options feignRequestOptions() {
        Request.Options options = new Request.Options(2000, TimeUnit.MILLISECONDS,
                10000, TimeUnit.MILLISECONDS,
                true);

        return  options;
    }

 

这个样写呢 ? 虽然解决我想测试的结果,但是修改Ribbon的超时时间,我还是不建议这样写,如果有需求要修改Ribbon的超时时间的时候可以这样用。

但是Ribbon的超时时间应该也可以配置,不过我没有在文档中找到,我看了文档,应该没有。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值