SpringCloud-Feign(老版本)

1, 两种服务调用方式

1,Feign
2,restTemplate

1,1 RestTemplate

1, application.yml

server:
  port: 8084
spring:
  application:
    name: feign-customer-example
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848

2,在启动类中配置一个 bean

@Bean
@LoadBalanced//在注册中心里进行查找微服务,负载均衡
public RestTemplate restTemplate(){
    RestTemplate restTemplate=new RestTemplate();
    return  restTemplate;
}

3,使用 restTemplate 调用服务

package com.zgjt.controller;

import com.netflix.discovery.converters.Auto;
import com.zgjt.feign.FeignDemo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
public class EurakeTest {

    @Autowired
    private RestTemplate restTemplate;
    
    @RequestMapping("testRestTemplate")
    public void test(){
        restTemplate.getForEntity("http://EUREKA-CLIENT/eurakeTest",String.class);
    }
}

注意:高版本的时候,貌似 loadBalance 需要导包

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-loadbalancer</artifactId>
    <version>3.1.1</version>
</dependency>

2, Feign

Feign 在 restTemplate 基础上做一次封装,定义和注册中心同样的接口,就可以调用注册中心的服务
这是 openFeign,区别于 Feign,继承了 SpringMvc 的注解

1,pom

<dependencies>
    <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-feign -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-openfeign</artifactId>
        <version>2.1.3.RELEASE</version>
    </dependency>
    <dependency>
        <groupId> com.alibaba.cloud</groupId>
        <artifactId> spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        <version>2.1.0.RELEASE</version>
    </dependency>
</dependencies>

2,application.yml

server:
  port: 8084
spring:
  application:
    name: feign-customer-example
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
        ##不需要注册服务
        register-enabled: false

3,定义 feign 接口

//注册到 nacos 的服务名
@FeignClient("nacos-provider-example")
@Component
public interface NacosProviderDemo {
      
    //方法签名要相同
    @PostMapping("/test")
    String helloNacos();
}

4,新建 controller 调用 feign

package com.zgjt.controller;

import com.zgjt.feign.NacosProviderDemo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class FeignTest {

    @Autowired
    private NacosProviderDemo feignDemo;

    @RequestMapping("/feignTest")
    public String test(){
        return feignDemo.helloNacos() ;
    }
}

5,启动类添加 @EnableFeignClients

package com.zgjt;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;

@SpringBootApplication
@EnableFeignClients
public class FeignCustomerApplication {

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

2, 负载均衡 Ribbon

ribbon 负载均衡策略,默认策略是轮询

内置负载均衡规则类规则描述
RoundRobinRule简单轮询服务列表来选择服务器。它是Ribbon默认的负载均衡规则。
AvailabilityFilteringRule对以下两种服务器进行忽略: (1)在默认情况下,这台服务器如果3次连接失败,这台服务器就会被设置为“短路”状态。短路状态将持续30秒,如果再次连接失败,短路的持续时间就会几何级地增加。 (2)并发数过高的服务器。如果一个服务器的并发连接数过高,配置了AvailabilityFilteringRule规则的客户端也会将其忽略。并发连接数的上限,可以由客户端的..ActiveConnectionsLimit属性进行配置。
WeightedResponseTimeRule为每一个服务器赋予一个权重值。服务器响应时间越长,这个服务器的权重就越小。这个规则会随机选择服务器,这个权重值会影响服务器的选择。
ZoneAvoidanceRule以区域可用的服务器为基础进行服务器的选择。使用Zone对服务器进行分类,这个Zone可以理解为一个机房、一个机架等。而后再对Zone内的多个服务做轮询。
BestAvailableRule忽略那些短路的服务器,并选择并发数较低的服务器。
RandomRule随机选择一个可用的服务器。
RetryRule重试机制的选择逻辑

2.1 restTemplate

添加负载均衡策略 @LoadBalanced
修改负载均衡策略,启动类中自定义一个 bean

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class ApplicationContentConfig {

    @Bean
    @LoadBalanced //开启ribbon自带负载均衡
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }
      
    //修改轮询策略为随机
    @Bean
    public IRule myRule(){
        return new RandomRule();
    }
}

2.2, Feign

feign 已经集成了 ribbon,修改 feign 轮询策略, application.properties 中添加

EUREKA-CLIENT.ribbon.NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

EUREKA-CLIENT 是提供者服务名

或者在启动类中添加, 其中 WeightedResponseTimeRule 权重方式,需要在 nacos 中配置权重

    //修改轮询策略为随机
    @Bean
    public IRule myRule(){
        return new RandomRule();
    }

2.3 Ribbon 重试机制

当调用服务,超时未响应的时候,会根据配置重新调用服务

主要配置

ribbon:
  ReadTimeout: 1000
  ConnectTimeout: 1000
  MaxAutoRetries: 1 #同一台实例最大重试次数,不包括首次调用
  MaxAutoRetriesNextServer: 1 #重试负载均衡其他的实例最大重试次数,不包括首次调用
  OkToRetryOnAllOperations: false  #是否所有操作都重试

根据上面的参数计算重试的次数, 即重试3次 则一共产生4次调用

MaxAutoRetries + MaxAutoRetriesNextServer + ( MaxAutoRetries * MaxAutoRetriesNextServer )

另外, ribbon 默认重试一次, 读取数据时间为 1s

3. hystrix 熔断器

如果在 Ribbon 重试期间,时间超过了hystrix的超时时间,便会立即执行熔断,fallback。所以要根据上面配置的参数计算hystrix的超时时间,使得在重试期间不能达到hystrix的超时时间,不然重试机制就会没有意义

hystrix超时时间的计算:

(1 + MaxAutoRetries + MaxAutoRetriesNextServer) * ReadTimeout

hystrix 熔断机制使用(这个 pom 和 ribbon 的 pom 都已经集成再 feign 中,可以不用引入)

1,Pom

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

2,application.yml

#启动 hystrix
feign:
  hystrix:
    enabled: true

##请求进行重试
hystrix:
  command:
    Feign#test():
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 4000

3,实现 feign 接口,做降级处理

package com.zgjt.hystrix;

import com.zgjt.feign.FeignDemo;
import org.springframework.stereotype.Component;

@Component
public class HystrixDemo implements FeignDemo {
    @Override
    public String test() {
        System.out.println("hello hystrix");
        return "1";
    }
}

4,feign 接口声明调用失败使用的实现类,添加 fallback 参数

@FeignClient(name ="service-vod",fallback = HystrixDemo.class)
@Component
public interface VodClient {
    @PostMapping("/vod/videos/dropVideos")
    ResultApi dropVideos(@RequestBody String videoId);
}
posted @ 2021-08-02 17:28  primaryC  阅读(276)  评论(0)    收藏  举报