zoukankan      html  css  js  c++  java
  • spring-cloud-feign负载均衡组件

    Feign简介:

      Feign是一个声明式的Web服务客户端,使用Feign可使得Web服务客户端的写入更加方便.它具有可插拔注释支持,包括Feign注解和JAX-RS注解、Feign还支持可插拔编码器和解码器、Spring Cloud增加了对Spring MVC注释的支持,并HttpMessageConverters在Spring Web中使用了默认使用的相同方式。Spring Cloud集成了Ribbon和Eureka,在使用Feign时提供负载平衡的http客户端。Fegin对Robbin进行了封装,如果需要配置自己的负载算法,可以自定义Ribbon的算法即可。 Spring Cloud Feign 提供的声明式服务绑定功能来实现对该服务接口的调用。

    1.创建 一 个 Spring Boot 基础工程,对pom文件修改

    <properties>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
            <java.version>1.8</java.version>
            <spring-cloud.version>Finchley.SR3</spring-cloud.version>
        </properties>
    
        <dependencyManagement>
            <dependencies>
                <dependency>
                    <!-- SpringCloud 所有子项目 版本集中管理. 统一所有SpringCloud依赖项目的版本依赖-->
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-dependencies</artifactId>
                    <version>${spring-cloud.version}</version>
                    <type>pom</type>
                    <scope>import</scope>
                </dependency>
            </dependencies>
        </dependencyManagement>
    
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-feign</artifactId>
                <version>1.4.6.RELEASE</version>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
            </dependency>
        </dependencies>
    
        <build>
            <plugins>
                <plugin><!-- SpringBoot 项目打jar包的Maven插件 -->
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>

    2.application.yml

    server:
      port: 9012
    
    spring:
      application:
        name: feign-server #服务注册到Eureka上使用的名称
    
    eureka:
      client:
        serviceUrl:
          defaultZone: http://localhost:7001/eureka/,http://localhost:7002/eureka/
      instance:
        instance-id: feign-server-9012
        prefer-ip-address: true #访问路径显示IP地址

    3.修改主启动类

    @SpringBootApplication
    @EnableDiscoveryClient
    @EnableFeignClients(basePackages = {"com.wuzz.demo"})
    public class FeignApp
    {
        public static void main( String[] args )
        {
            SpringApplication.run(FeignApp.class, args);
        }
    }

    4.负载均衡配置

    @Configuration
    public class ConfigBean {
        
    //    Eureka是基于REST(Representational State Transfer)服务,
    //    主要以AWS云服务为支撑,提供服务发现并实现负载均衡和故障转移。
    //    我们称此服务为Eureka服务。
    //    Eureka提供了Java客户端组件,Eureka Client,方便与服务端的交互。
    //    客户端内置了基于round-robin实现的简单负载均衡。
    //    在Netflix,为Eureka提供更为复杂的负载均衡方案进行封装,
    //    以实现高可用,它包括基于流量、资源利用率以及请求返回状态的加权负载均衡。
    
        /**
         * Ribbon是Netflix发布的云中间层服务开源项目,主要功能是提供客户端负载均衡算法。
        Ribbon客户端组件提供一系列完善的配置项,如,连接超时,重试等。
        简单的说,Ribbon是一个客户端负载均衡器,
        我们可以在配置文件中列出load Balancer后面所有的机器,
        Ribbon会自动的帮助你基于某种规则(如简单轮询,随机连接等)去连接这些机器,
        我们也很容易使用Ribbon实现自定义的负载均衡算法
         * 
         */
    //    Feign是一个声明式的Web服务客户端,使用Feign可使得Web服务客户端的写入更加方便。 
    //    它具有可插拔注释支持,包括Feign注解和JAX-RS注解、Feign还支持可插拔编码器和解码器、
    //    Spring Cloud增加了对Spring MVC注释的支持,
    //    并HttpMessageConverters在Spring Web中使用了默认使用的相同方式。
    //    Spring Cloud集成了Ribbon和Eureka,在使用Feign时提供负载平衡的http客户端。    
        
        @Bean
        @LoadBalanced // ribbon是客户端 的负载均衡工具
        //默认算法是轮询算法 核心组件IRule
        public  RestTemplate getRestTemplate() {
            
            return new RestTemplate();
        }
        
        @Bean
        public IRule myRule() { // 负载均衡算法。。。。
            
    //        return new RoundRobinRule();
            return new RandomRule();
        }
    }

    5.声明式服务类

    @FeignClient(value ="cloud-provider")
    public interface ClientService {
      //如果feign代理的是get请求,必须用@RequestMapping 不能用@GetMapping
      // 每个参数必须带上@RequestParam,否则会报post not support! 
      @RequestMapping(value = "/hello", method = RequestMethod.GET)
       String hello(@RequestParam("id") String id) ; 
    }

    6.controller

    @RestController
    public class FeignController {
        
        @Autowired
        private ClientService service;
        
        @RequestMapping(value ="/feign/hello")
        public String hello() {
            
            return service.hello("1");
        }
    }

      这样就配置好了。

    指定服务配置:

      大多数情况下,我们对于服务调用的超时时间可能会根据实际服务的特性做 一 些调整,所以仅仅依靠默认的全局配置是不行的。 在使用SpringCloud Feign的时候,针对各个服务客户端进行个性化配置的方式与使用SpringCloud Ribbon时的配置方式是 一 样的, 都采用<client>. ribbon.key=value 的格式进行 设置。在定义Feign客户端的时候, 我们使用了@FeignClient注解。 在初始化过程中,SpringCloud Feign会根据该注解的name属性或value属性指定的服务名, 自动创建一 个同名的Ribbon客户端。也就是说,在之前的示例中,使用@FeignClient(value= "cloud-provider")来创 建 Feign 客 户 端 的 时 候 , 同时也创建了一个 名为cloud-provider的Ribbon客户端。 既然如此, 我们就可以使用@FeignClient注解中的name或value属性值来设置对应的Ribbon参数, 比如:

    cloud-provider.ribbon.ConnectTimeout = 500 //请求连接的超时时间。
    cloud-provider.ribbon.ReadTimeout = 2000  //请求处理的超时时间。
    cloud-provider.ribbon.OkToRetryOnAllOperations = true //对所有操作请求都进行重试。
    cloud-provider.ribbon.MaxAutoRetriesNextServer = 2 //切换实例的重试次数。
    cloud-provider.ribbon.MaxAutoRetries = 1 //对当前实例的重试次数。

    重试机制:

      在 Spring Cloud Feign 中默认实 现了 请 求 的重 试 机 制 , 而上面我 们对 于 cloud-provider 客户端的配置内容就是对于请求超时以及重试机制配置的详情.

      这里需要注意一 点, Ribbon的超时 与Hystrix的超时是两个概念。 为了让上述实现有效,我们需要 让Hystrix的超时时间大于Ribbon的超时时间, 否则Hystrix命令超时后, 该命令直接熔断, 重试机制就 没有任何意义了。

      要么设置 Hystrix 的超时时间比Ribbon大(hystrix.command.default.execution.isolation.thread. timeoutInMilliseconds = 5000),要么直接关闭 Hystrix 超时配置(feign.hystrix.enabled= false).配置的时候不提示没关系,配置上就有效果。

      如果不想全局关闭可以只针对服务进行关闭:@FeignClient(name="HELLO - SERVICE", configuration = DisableHystrixConfiguration.class)

      在 feign-server应用中增加上文中提到的重试配置参数。其中,由于 cloud-provider.ribbon.MaxAutoRetries 设置为 1, 所以重试策略先尝试访问首选实例 一 次, 失败后才更换实例访问, 而更换实例访问的次数通过 cloud-provider.ribbon.MaxAutoRetriesNextServer 参数 设置为 2, 所以会尝试更换两次实例进行重试。

      最后, 启动这些应用, 并尝试访问几次 http://localhost:9012/feign­/hello 接口。可以通过 cloud-provider 服务打印请求信息,修改对应/hello接口如下

    public String hello(String id) throws InterruptedException {
            // 测试fegin 超时重试代码开始
            List<ServiceInstance> instances = client.getInstances("feign-server");
            //测试超时
            int sleepTime = new Random().nextInt(3000);
            System.out.println("sleepTime:" + sleepTime);
            Thread.sleep(sleepTime);
            System.out.println("/hello, host:" + instances.get(0).getHost() +
                    instances.get(0).getServiceId());
            // 测试fegin 超时重试代码结束
             return  "Hello Eureka Provider1";
        }

      然后控制台来查看重试的日志。

      从控制台输出中,我们可以看到这次访问的第 一 次请求延迟时间为 2088毫秒,由于超时时间设置为 2000 毫秒, Feign 客户端发起了重试,第二次请求的延迟为 1338 秒,没有超时 。Feign客户端在进行服务调用时, 虽然经历了一 次失败,但是通过重试机制, 最终还是获得了请求结果。所以, 对于 重试机制的实现, 对于构建高可用的 服务集群来说非常重要, 而 SpringCloud Feign也为其提供了足够的支持。

    其他配置:

      请求压缩。Spring Cloud Feign支持对请求与响应进行 GZIP 压缩,以减少通信过程中的性能损耗 。我们只需通过下面两个参数设置, 就能开启请求与响应的压缩功能:

    feign.compression.request.enabled = true
    feign.compression.response.enabled = true

      同时, 我们还能对请求压缩做 一 些更细致的设置, 比如下面的配置内容指定了压缩的请求数据类型, 并设置了请求压缩的大小下限, 只有超过这个大小的请求才会对其进行压缩。

    feign.compression.request.enabled = true
    feign.compression.request.mime-types = text/xml,application/xml,application/json //默认值
    feign.compression.request.min-request-size=2048 //默认值

    日志配置:

      Spring Cloud Feign 在构建被 @FeignClient 注解修饰的服务客户端时,会为每 一 个客户端都创建 一 个 feign.Logger 实例,我们可以利用该日志对象的 DEBUG 模式来帮助分析 Feign 的请求细节。可以在 application.properties 文件中使用 logging.level.<FeignClient> 的参数配置格式来开启指定 Feign 客户端的 DEBUG 日志, 其中<FeignClient> 为 Feign 客户端定义接口的完整路径, 比如针对本文中我们实现的 HelloService 可以按如下配置开启:

    logging.level.com.wuzz.demo.HelloService = DEBUG

      但是, 只是添加了如上配置, 还无法实现对 DEBUG 日志的输出。 这时由于 Feign 客户端默认的 Logger.Level 对象定义为 NONE 级别, 该级别不会记录任何 Feign 调用过程中的信息, 所以我们需要调整它的级别, 针对全局的日志级别, 可以在应用主类中直接加入 Logger.Level 的 Bean 创建, 具体如下:

    @Bean
    Logger.Level feignLoggerLevel() {
        return Logger.Level.FULL;
    }

      或者添加个配置类:

    @Configuration
    public class FullLogConfiguration {
    @Bean
    Logger.Level feignLoggerLevel() {
        return Logger.Level.FULL;
    }
    @FeignClient(name = "cloud-provider", configuration = FullLogConfiguration.class)
    public interface HelloService {
        。。。。。。
    }

      在调整日志级别为 FULL 之后, 我们可以再访问一 下之前的http://localhost:9012/feign/hello 接口,这时我们在 feign-server的控制台中就可以看到对应的日志。类似如下信息:

      对于 Feign 的 Logger 级别主要有下面 4 类, 可根据实际需要进行调整使用。

    • NONE: 不记录任何信息。
    • BASIC: 仅记录请求方法、URL以及响应状态码和执行时间。
    • HEADERS: 除了记录BASIC级别的信息之外, 还会记录请求和响应的头信息。
    • FULL: 记录所有请求与响应的明细, 包括头信息、 请求体、 元数据等。

    服务降级(Feign客户端):

      整体资源快不够了,忍痛将某些服务先关掉,待渡过难关,再开起会来。所谓降级,一般是从整体负荷考虑,就是当某个服务熔断后,服务器将不再被调用,此时客户端可以准备自己本地的一个fallback回调,返回一个缺省值,这样做,虽然服务水平下降,但好歹可用,比直接挂掉要强,服务降级是在客户端进行的.

      1. 根据目标接口,创建一个实现了FallbackFactory的类 

    @Component
    public class HystrixClientService implements FallbackFactory<ClientService> {
        @Override
        public ClientService create(Throwable throwable) {
            return new ClientService() {
                @Override
                public String hello() {
                    return "服务降级。。。。";
                }
            };
        }
    }

      2. 在目标接口上的@FeignClient中添加fallbackFactory属性值

    @FeignClient(value ="cloud-provider", fallbackFactory = HystrixClientService.class)
    public interface ClientService {
    
        @RequestMapping(value ="/hello",method= RequestMethod.GET)
        String hello() ;
    }

      3.修改 application.yml ,添加一下

    feign: 
       hystrix: 
        enabled: true
    

      这样就完成了服务降级的基本配置,可以进入测试。。。。

    Ribbon和 Feign的区别:

    • Ribbon添加maven依赖 spring-starter-ribbon    使用@RibbonClient(value="服务名称")    使用RestTemplate调用远程服务对应的方法。feign添加maven依赖 spring-starter-feign    服务提供方提供对外接口  调用方使用    在接口上使用    @FeignClient("指定服务名")
    • Ribbon和Feign都是用于调用其他服务的,不过方式不同。
    • 启动类使用的注解不同,Ribbon用的是@RibbonClient,Feign用的是@EnableFeignClients。
    • 服务的指定位置不同,Ribbon是在@RibbonClient注解上声明,Feign则是在定义抽象方法的接口中使用@FeignClient声明。
    • 调用方式不同,Ribbon需要自己构建http请求,模拟http请求然后使用RestTemplate发送给其他服务,步骤相当繁琐。
    • Feign则是在Ribbon的基础上进行了一次改进,采用接口的方式,将需要调用的其他服务的方法定义成抽象方法即可,不需要自己构建http请求。不过要注意的是抽象方法的注解、方法签名要和提供服务的方法完全一致。
  • 相关阅读:
    嵌套循环
    for循环
    while循环
    switch多选择结构
    python9--内存管理 引用计数 标记清除 分代回收
    python8--文件操作 with。。。open语法
    python7 数据类型的相互转化 字符编码
    python6-深浅拷贝 元组类型 字典类型 集合类型
    python5 数字类型 字符串类型 列表类型
    python4 分支结构,循环结构 for循环
  • 原文地址:https://www.cnblogs.com/wuzhenzhao/p/9472607.html
Copyright © 2011-2022 走看看