您当前的位置: 首页 >  微服务

wu@55555

暂无认证

  • 2浏览

    0关注

    201博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

springcloud:微服务如何通信?组件通信组件:feign详解(六)

wu@55555 发布时间:2022-04-04 03:42:17 ,浏览量:2

0. 引言

上一期我们搭建了网关和配置中心、注册中心。如果还没有看过往期文章的可以先了解: springcloud:什么是分布式微服务,如何学习微服务(一) springcloud:微服务涉及哪些技术、有哪些核心组件(二) springcloud:网关组件gateway详解(三) springcloud:注册中心、配置中心组件nacos详解(四) springcloud:保姆式教程-从零搭建微服务(五)

但是还有一个核心问题没有解决,那就是微服务间的通信问题。比如我们订单服务中需要调用商品列表数据,而商品列表数据是在商品服务中获取的,那么我们就需要在订单服务中调用商品服务的接口。这种服务间调用,就称为组间通信

目前常用的组件通信有RestTemplate和feign。RestTemplate的使用相对比较麻烦,需要写上服务IP等比较底层的信息,而feign则不需要,更加符合本地调用的方式。

本着最核心技术快速上手的理念,我们先针对更加常用的feign组件进行讲解。后续再详谈RestTemplate

1. Feign简介

Feign是声明式的web service客户端,它让服务间的调用更加简单。使得整个调用变得像本地调用一样简单。

Feign中包含了Hystrix和ribbon。所以feign支持接口负载均衡,以及接口的熔断、降级、限流等处理。并且支持Http请求和响应的压缩。 在这里插入图片描述

feignClient参数详解 参数名说明value指定feignClient的名称,会注册成bean,也就是bean名,如果使用了注册中心,就是服务名name同valueserviceId当要定义多个相同name的feignClient时,会报错,需要通过定义不同的serviceId来区分,新版本已弃用contextId当要定义多个相同name的feignClient时,会报错,需要通过定义不同的serviceId来区分,会被用作bean名qualifier指定@Qualifier注解的值,调用方就可通过该值来进行引用feignclient,当bean名相同时,用于标明唯一的bean。@Qualifier与@Autowired配合使用url手动指定接口调用地址decode404当接口请求404时,如果该字段为true,则会调用decoder进行解码(可在decoder中自定义错误类型、错误信息等),否则报错FeignExceptionconfigurationFeign配置类,可以自定义Feign的Encoder,Decoder等fallback用于定义接口调用报错时的回调函数fallbackFactory工厂类,用于生成fallback类示例path定义当前feignClient的统一前缀primary是否将外部代理标记为主bean,将当前类转换为bean,可以通过依赖注入引用 2. Feign使用

1、要使用feign,我们需要引入feign的依赖


            org.springframework.cloud
            spring-cloud-starter-openfeign 
            2.2.6.RELEASE

需要注意的是,Feign默认是POST请求,如果要支持带参数的GET请求,那么还需要引入feign-httpclient依赖


     io.github.openfeign
     feign-httpclient
     10.10.1

同时因为是web api,那么肯定还要引入Spring web依赖,已经引入过就不用重复引用了


    org.springframework.boot
    spring-boot-starter-web 

2、在调用方服务的启动类中添加注解@EnableFeignClients

2.1 通过IP直接调用服务

直接通过IP来调用的话只需要在调用方的服务中创建Feign接口类。其中name是服务名,url是实际的接口地址,如果有多个可以用逗号隔开

接口中书写的是对应到controller的URL地址。比如说用户controller中有一个list接口,url是list。那么Feign接口类中对应的方法也要和controller中的接口地址保持一致

@FeignClient(name = "order-server",url = "localhost:8081")
public interface OrderApi {
    
    @GetMapping("list")
    public List list();
    
}

有一个注意的点,如果controller中统一的接口前缀,比如说/user。在feign接口类中是不能通过@RequestMapping来申明的,而是必须在每个方法中添加上这个前缀,如下所示:

@FeignClient(name = "order-server",url = "localhost:8081")
public interface OrderApi {

    String PREFIX = "order";
    String LIST = PREFIX + "/list";
    String PAGE = PREFIX + "/page";

    @GetMapping(LIST)
    public List list();

    @GetMapping(PAGE)
    public List page();
    
}
2.2 通过nacos调用

直接使用服务名即可,无需定义url。在调用方中创建该接口即可

@FeignClient(name = "product-server")
public interface ProductApi {

    @GetMapping("list")
    public List list();
}
测试

我们基于上节课搭建的springcloud项目来进行测试,为了不影响上节课的代码,单独创建一个springcloud2用于本章测试

1、在order-server服务中引入依赖


            org.springframework.cloud
            spring-cloud-starter-openfeign
            2.2.7.RELEASE
        
        
            io.github.openfeign
            feign-httpclient
            10.10.1
        
        
        
            com.example
            product-server-feign
            0.0.1-SNAPSHOT
            compile
        

2、在order-server中创建ProductApi接口类

@FeignClient(name = "product-server",url = "localhost:9091")
public interface ProductApi {

    @GetMapping("list")
    public List list();
}

3、在order-server启动类中添加@EnableFeignClients注解

4、在在order-server的OrderController中创建接口用于调用feign接口类中的方法

@RestController
@AllArgsConstructor
public class OrderController {
    private final IOrderService orderService;
    private final ProductApi productApi;

    @GetMapping("list")
    public List list(){
        return orderService.list();
    }

    @GetMapping("listProduct")
    public List listProduct(){
        return productApi.list();
    }

}

5、测试访问http://localhost/order-server/listProduct

可以看到我们在order服务用调用了product服务的list接口,其结果返回来商品列表信息 在这里插入图片描述

2.3 重试与超时

feign包含了ribbon,因此可以使用ribbon的重试、超时机制,只需要在配置文件中修改:

  • 重试配置
#同一台实例最大重试次数,不包括首次调用
ribbon.MaxAutoRetries=1
#重试负载均衡其他的实例最大重试次数,不包括首次调用
ribbon.MaxAutoRetriesNextServer=1
#是否所有操作都重试
ribbon.OkToRetryOnAllOperations=false
  • 超时配置:这里的连接超时指的是连接接口的时间,而业务逻辑超时时间指的是连接成功后业务逻辑的执行时间
#连接超时时间(ms)
ribbon.ConnectTimeout=1000
#业务逻辑超时时间(ms)
ribbon.ReadTimeout=6000
2.4 服务熔断、降级

在配置熔断降级之前我们需要理解什么是服务熔断?什么是服务降级?

服务熔断:当连续连接失败次数达到阈值后,直接报错,之后的相同请求也直接报错,这个措施称为熔断。相当于我们常见的保险丝,当确定了服务不能访问时,就直接断开后续的连接

服务降级:当连续连接失败次数达到阈值或者超时后,给请求方一个保底信息,这个保底信息可以是: (1)返回友好性的页面,比如重试按钮、联系邮箱或者一些基础的静态页面 (2)返回提示信息,并把数据写入到MQ中,后续通过MQ来重试 (3)返回友好性的提示信息,比如“稍后再来”、“服务忙,请稍后重试”等,不做其他处理 我们把以上这样的措施称为降级。

默认feign是不会用Hytrix来做服务降级等处理的,所以要使用的话需要在配置文件中开启:

feign.hystrix.enabled=true
2.4.1 降级配置

feign利用fallback类来实现请求失败后的回调方法 1、创建回调类

@Component
public class UserProviderBack implements UserApi {

    @Override
	public Map findById(@RequestParam("id") Integer id){
	// 降级,给出友好性提示
        return "服务走远了,请稍后重试";
    }
    
    @Override
	public Map getMap(@RequestParam Map map){
	// 降级,直接返回空数据
       return null;
   }	
 
}

2、声明回调类

@FeignClient(name="user-provider",fallback= UserProviderBack.class)
public interface UserApi {

    @GetMapping("/findById")
	public Map findById(@RequestParam("id") Integer id);
    
    @GetMapping("/getMap")
	public Map getMap(@RequestParam Map map);	
 
}

如果需要根据不同的错误类型来进行不同的降级处理,那么可以使用FallbackFactory

@Component
public class ProductFeignCallBackFactory implements FallbackFactory {

    @Override
    public ProductFeignNacos create(Throwable cause) {
        return new ProductFeignNacos() {
            @Override
            public String getInfo() throws ClientException {
                if(cause instanceof FeignException.InternalServerError){
                    return "远程服务器挂掉咯";
                }else if(cause instanceof RuntimeException){
                    // 熔断
                    throw (RuntimeException) cause;
                }
                return "Cloud7DayProperties{'name':'兜底数据','price':0, 'size': 0}";
            }

        };
    }
}

同时@FeignClient里的调用也要改成fallbackFactory

@FeignClient(name = "product-server",
        contextId="product-server-nacos",
        fallbackFactory = ProductFeignCallBackFactory.class)
public interface ProductFeignNacos {
    ...
}
2.4.2 服务熔断

因为feign中附带了hytrix,我们通过hytrix来实现熔断

1、引入依赖


    org.springframework.cloud
    spring-cloud-starter-netflix-hystrix
    2.2.6.RELEASE

2、启动类添加注解 @EnableHystrix

3、修改配置文件

# feign对hytrix的支持默认是关闭的
feign:
  hystrix:
    enabled: true # 降级熔断:开启hytrix

#在10秒内,发生20次以上的请求时,假如超时率达到50%以上,则断路器将被打开。
hystrix:
  command:
    default:  # 或者填写具体的服务名称,default默认为全部服务
      execution:
      	timeout:
          enable: true
        isolation:
          thread:
            timeoutInMilliseconds: 3000       # 请求超时时间,单位毫秒
      circuitBreaker:
        sleepWindowInMilliseconds: 10000   # 窗口期,当触发熔断机制后指定时间内,此该接口不会再被访问
        requestVolumeThreshold: 20        # 请求阈值
        errorThresholdPercentage: 50      # 错误百分比阈值

触发效果 在这里插入图片描述

2.5 限流

因为feign集成了hytrix,而hytrix可以通过信号量SEMAPHORE或线程THREAD来实现限流

信号量形式

# 熔断
#在10秒内,发生10次以上的请求时,假如超时率达到50%以上,则断路器将被打开。
hystrix:
  command:
    default:  # 或者填写具体的服务名称,default默认为全部服务
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 3000       # 请求熔断超时时间,单位毫秒
          strategy: SEMAPHORE # 通过信号量限流
        semaphore:
          maxConcurrentRequests: 10 # 允许的最大并发
     circuitBreaker:
        sleepWindowInMilliseconds: 10000     # 窗口期
        requestVolumeThreshold: 5         # 请求阈值
        errorThresholdPercentage: 50      # 错误百分比阈值

限流效果 在这里插入图片描述

线程池形式

# 熔断
#在10秒内,发生10次以上的请求时,假如超时率达到50%以上,则断路器将被打开。
hystrix:
  command:
    default:  # 或者填写具体的服务名称,default默认为全部服务
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 3000       # 请求熔断超时时间,单位毫秒
          strategy: THREAD # 通过线程池限流,默认值
  threadpool:
    default:
      coreSize: 1 # 并发执行的最大线程数,默认10
      maxQueueSize: 2 # BlockingQueue的最大队列数,默认值-1
      queueSizeRejectionThreshold: 2 #即使maxQueueSize没有达到,达到queueSizeRejectionThreshold该值后,请求也会被拒绝,默认值5

限流效果 在这里插入图片描述

总结

好了,本期我们针对feign组件的讲解就到这里了,针对限流的配置我们并不推荐使用feign来实现,如果要做也是在fallback做处理,后续会详细讲解微服务中的限流措施。文中的测试代码也已经放到了git项目中,欢迎大家下载体验

下期预告

1、微服务框架进阶讲解

关注
打赏
1664985904
查看更多评论
立即登录/注册

微信扫码登录

0.0408s