首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >SpringCloud——Ribbon&OpenFeign

SpringCloud——Ribbon&OpenFeign

作者头像
爪哇缪斯
发布2023-05-10 09:53:16
发布2023-05-10 09:53:16
6930
举报
文章被收录于专栏:爪哇缪斯爪哇缪斯

今天我们针对SpringCloud中服务之间的通讯方式全面的聊一聊。如下是本篇文章的大纲

第一部分:RestTemplate

1> 服务通信概述

  • 服务通信产生的背景
  • 由于随着系统的演变,从单体服务转变为微服务,那么将单体应用围绕业务进行了服务的拆分,拆分出来每一个服务独立运行、独立部署,且运行在自己计算机进程中。那么基于分布式服务直接的交互问题,就产生了服务通信的概念。
  • 首先,我们先了解一下OSI的七层模型
  • 应用层 OSI参考模型中最靠近用户的一层,是为计算机用户提供应用接口,也为用户直接提供各种网络服务。我们常见应用层的网络服务协议有:HTTP,HTTPS,FTP,POP3、SMTP等。
  • 表示层 表示层提供各种用于应用层数据的编码和转换功能,确保一个系统的应用层发送的数据能被另一个系统的应用层识别。如果必要,该层可提供一种标准表示形式,用于将计算机内部的多种数据格式转换成通信中采用的标准表示形式。数据压缩和加密也是表示层可提供的转换功能之一。
  • 会话层 会话层就是负责建立、管理和终止表示层实体之间的通信会话。该层的通信由不同设备中的应用程序之间的服务请求和响应组成。
  • 传输层 传输层建立了主机端到端的链接,传输层的作用是为上层协议提供端到端的可靠和透明的数据传输服务,包括处理差错控制和流量控制等问题。该层向高层屏蔽了下层数据通信的细节,使高层用户看到的只是在两个传输实体间的一条主机到主机的、可由用户控制和设定的、可靠的数据通路。我们通常说的,RPC,TCP,UDP就是在这一层。端口号既是这里的“端”。
  • 网络层 本层通过IP寻址来建立两个节点之间的连接,为远端的传输层送来的分组,选择合适的路由和交换节点,正确无误地按照地址传送给目的端的运输层。就是通常说的IP层。这一层就是我们经常说的IP协议层。IP协议是Internet的基础。
  • 数据链路层 将比特组合成字节,再将字节组合成帧,使用链路层地址 (以太网使用MAC地址)来访问介质,并进行差错检测。数据链路层又分为2个子层:逻辑链路控制子层(LLC)和媒体访问控制子层(MAC)。MAC子层处理CSMA/CD算法、数据出错校验、成帧等;LLC子层定义了一些字段使上次协议能共享数据链路层。 在实际使用中,LLC子层并非必需的。
  • 物理层 实际最终信号的传输是通过物理层实现的。通过物理介质传输比特流。规定了电平、速度和电缆针脚。常用设备有(各种物理设备)集线器、中继器、调制解调器、网线、双绞线、同轴电缆。这些都是物理层的传输介质。
  • 在每一层都工作着不同的设备
  • 下面我们用一个生活中的例子来说明一下OSI七层模型的工作方式
  • 微服务通信的两套解决方案:HTTP的Rest方式RPC方式
  • HTTP是基于OSI第七层应用层,采用传输Json的方式进行通信。传输速度没有RPC快,但是可以与编程语言解耦。
  • RPC是基于OSI第四层传输层,传输二进制数据流。传输速度比HTTP快,但是耦合度高,通信两端必须使用同一种编程语言。
  • 所以,针对以上对比,SpringCloud一直推荐采用基于HTTP的通信方式进行服务间的通信调用。
  • 为了发起Http请求,Spring框架提供RestTemplate对象,来负责发送Http请求。

2> 实例演示

  • 首先:创建两个项目ribbon-producer和ribbon-consumer,分别引入springboot的web依赖
  • 其次:配置两个项目的application.yml文件(producer:7000,consumer:7002 )
  • 第三:创建两个项目的Controller

  • 第四:也可以声明RestTemplate为Bean
  • 第五:改造ComsumerController,使用Template的Bean

3> 存在的问题

  • 由于在请求的url中写死了ip和端口调用,所以无法实现请求的负载均衡,并且微服务一般都会部署在云环境上,ip和端口会随着上线、重启等操作产生变化,所以,写死ip和端口也不是明智的选择。那么针对这种情况,引出下面的Spring Cloud负载均衡组件——RIbbon。

第二部分:Ribbon

1> 概述

  • Spring Cloud Ribbon是一个基于HTTPTCP的客户端负载均衡工具,它基于Netflix Ribbon实现,通过Spring Cloud的封装,可以让我们轻松地将面向服务的Rest模板请求自动转换成客户端负载均衡的服务调用。
  • Ribbon只具有负载均衡的能力并不具有发送请求的能力。所以,需要配合服务通信组件,如:RestTemplate

2> 在微服务中的Ribbon

【解释】

  • Ribbon实现了从注册中心获取服务列表的能力。
  • 然后通过获取到的服务列表,采用负载均衡算法(Ribbon默认采用的是轮训方式),利用通信框架(RestTemplate或Feign等)进行服务调用。


3> 使用Ribbon+RestTemplate实现服务间请求调用

  • 有三种方式可以实现基于服务名+负载均衡的服务间通信方式。分别是:
    • DiscoveryClient + 自实现负载均衡 + RestTemplate
    • LoadBalanceClient + RestTemplate
    • @LoadBalanced + RestTemplate
  • 首先,启动Nacos,两个项目都加入Nacos的依赖
  • 由于Nacos已经集成了Ribbon,所以,我们就不需要额外引入Ribbon了
  • 其次,在consumer和producer的application.yml配置文件中加入Nacos的配置信息

3.1> DiscoveryClient

  • 优点:客户获得指定服务名称下的所有服务实例。
  • 缺点:没有负载均衡,需要通过获取服务列表,来编程实现负载均衡。
  • 实现方式(【注意】不能加@LoadBalanced,否则请求失败)
  • DiscoveryClient的实现类是NacosDiscoveryClient

3.2> LoadBalanceClient

  • 优点:自带负载均衡算法,不需要自己实现了。
  • 缺点:使用时需要每次先根据服务id获取一个负载均衡机器,然后再通过RestTemplate调用服务。
  • 实现方式(【注意】不能加@LoadBalanced,否则请求失败)
  • LoadBalanceClient的实现类是RibbonLoadBalancerClient

3.3> @LoadBalanced

  • 基于LoadBalanceClient,提供了使用更方便的@LoadBalanced注解。
  • 优点:使得RestTemplate实例具有了负载均衡的能力,不需要特殊调用loadBalanceClient实例的choose方法获得负载均衡计算出的实例了。使用方式,跟普通RestTemplate一样。非常简单。
  • 缺点:依然还需要指定请求的uri和返回值类型。调用依然没有基于rpc方式简洁和直观。
  • 修饰范围:方法上
  • 作用:让restTemplate具有ribbon负载均衡特性。使用更简单。
  • 实现方式


4> Ribbon实现负载均衡原理

4.1> 负载均衡相关源码解析

  • 源码分析入口。因为@LoadBalanced注解是基于LoadBalanceClient的。所以。我们从红框这块代码分析入手:
  • RibbonLoadBalancerClient.choose(...)
  • RibbonLoadBalancerClient.getServer(...)
  • BaseLoadBalancer.chooseServer(...)
  • 默认负载均衡算法

4.2> 负载均衡策略

  • 负载均衡规则的类关系图
  • 每个类具体负责功能
    • RoundRobinRule 轮询策略 按顺序循环选择服务实例
    • RandomRule 随机策略 随机选择服务实例
    • AvaliabilityFilteringRule 可用过滤策略 会先过滤由于多次访问故障而处于断路器跳闸状态的服务,还有并发的连接数量超过阈值的服务。然后对剩余的服务列表按照轮询策略进行访问。
    • WeightedResponseTimeRule 响应时间加权策略(对于不同配置或负载的服务,请求偏向于打到负载小或性能高的服务上) 根据平均响应的时间计算所有服务的权重,响应时间越快服务权重越大,也就越大概率被选中,刚启动时如果统计信息不足,则使用RoundRobinRule策略,等统计信息足够了,会切换到本策略。
    • RetryRule 重试策略(会使客户对于服务列表中不可用服务的调用无感,因为会retry到别的服务) 先按照RoundRobinRule的策略获取服务,如果获取失败,则在制定时间内进行重试,获取可用服务。
    • BestAvailableRule 最低并发策略 会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务。

4.3> 自定义负载均衡策略

  • 在调用方,即:ribbon-consumer工程的application.yml文件中,加入指定负载均衡策略的配置,如下所示:

【解释】

  • ribbon-producer:指定的是服务提供方spring.application.name指定的值。
  • RandomRule:采用的是随机策略。即:随机请求某个服务实例。

  • 进行测试,请求http://localhost:7002/consumer/loadBalancerAnnotation,已经是随机访问服务了,不是默认的轮询方式了。结果如下所示:
代码语言:javascript
复制
provider hello! port:7001
provider hello! port:7001
provider hello! port:7000
provider hello! port:7001
provider hello! port:7001
provider hello! port:7000
provider hello! port:7000

第三部分:OpenFeign

1> 概述

  • 由于Netflix的Feign组件进入的维护阶段,所以Spring Cloud团队开始吸收开源的Feign组件的简化,封装开发了OpenFeign组件,而使用上,OpenFeign与Feign是一样的
  • OpenFeign属于Spring Cloud自己的组件。
  • 官网地址:https://cloud.spring.io/spring-cloud-openfeign/reference/html/
  • OpenFeign是一个声明式的伪Http客户端(即:封装了Http请求,底层还是使用的RestTemplate发送的http请求),它使得编写Http客户端变得更简单。只需要创建一个接口并加入相关注解。它具有可插拔的注解特性(可以使用SpringMVC注解),可以使用Feign注解和JAX-RS注解。它将支持可插拔的编码器和解码器。默认继承了Ribbon和实现了负载均衡。并且SpringCloud团队为Feign添加了Spring MVC注解的支持。
  • 到目前为止,如果A服务和B服务要实现Http方式的调用。有如下三种方式:
    • 1> RestTemplate + 自实现的负载均衡策略
    • 2> RestTemplate + Ribbon
    • 3> OpenFeign

2> 实现OpenFeign的请求调用

2.1> 创建两个项目openfeign-producer和openfeign-consumer

2.2> 引入服务注册中心Nacos的依赖

  • openfeign-producer项目和openfeign-consumer项目的pom文件

2.3> 加入Nacos的配置信息

  • openfeign-producer项目的配置文件application.yml
  • openfeign-consumer项目的配置文件application.yml

2.4> 开启服务发现和FeignClient

  • openfeign-producer项目的OpenFeignProducerApplication.java类
  • openfeign-consumer项目的OpenFeignConsumerApplication.java 同上,略。

2.5> 创建ProducerController类

  • openfeign-producer项目的ProducerController.java类

2.6> 在openfeign-consumer项目中创建OpenFeign接口

  • openfeign-consumer项目的ProviderService.java类

【注意】

  • ProviderService接口中定义的方法,方法名称可以不与目标调用方法相同,但是返回值、请求路径必须相同。

2.7> 创建ConsumerController类

  • openfeign-consumer项目的ConsumerController.java类

2.8> 进行测试

  • 请求http://localhost:8002/consumer/hello


3> OpenFeign的参数传递

3.1> 传递基本类型参数

3.1.1> queryString方式传递参数
  • 请求参数中必须要加入@RequestParam。否则如果传入多个参数的话,会报如下错误。

  • openfeign-producer项目的ProducerController.java类
  • openfeign-consumer项目的ProviderService.java类
  • openfeign-consumer项目的ConsumerController.java类

3.1.2> 路径方式传递参数
  • 采用@PathVariable注解的方式
  • openfeign-producer项目的ProducerController.java类
  • openfeign-consumer项目的ProviderService.java类
  • openfeign-consumer项目的ConsumerController.java类

3.2> 传递对象类型参数

  • 使用@PostMapping@RequestBody的注解方式
  • openfeign-producer和openfeign-consumer都增加User实体类
  • openfeign-producer项目的ProducerController.java类
  • openfeign-consumer项目的ProviderService.java类
  • openfeign-consumer项目的ConsumerController.java类

3.3> 传递数组类型参数

  • 使用@GetMapping@RequestParam的注解方式传递数组类型
  • openfeign-producer项目的ProducerController.java类
  • openfeign-consumer项目的ProviderService.java类
  • openfeign-consumer项目的ConsumerController.java类

3.4> 传递集合类型参数

  • 与数组调用方式一样的。
  • openfeign-producer项目的ProducerController.java类
  • openfeign-consumer项目的ProviderService.java类
  • openfeign-consumer项目的ConsumerController.java类

4> OpenFeign的返回值处理

4.1> 使用OpenFeign调用服务,并返回对象

  • 以对象类型返回即可
  • openfeign-producer项目的ProducerController.java类
  • openfeign-consumer项目的ProviderService.java类
  • openfeign-consumer项目的ConsumerController.java类

5> OpenFeign的细节

5.1> OpenFeign默认超时处理

  • 调用服务时,默认是1秒超时,如果服务提供方的服务1秒内没有响应,则会抛异常。
  • 如何修改指定服务的超时配置;
    • 【application.properties文件】 feign.client.config.[服务提供者的服务名].connectTimeout=5000 feign.client.config.[服务提供者的服务名].readTimeout=5000
    • 【application.yaml文件】 feign: client: config: [服务提供者的服务名]: connectTimeout: 5000 readTimeout: 5000
  • 针对所有微服务,修改超时设置
    • 【application.properties文件】 feign.client.config.default.connectTimeout=5000 feign.client.config.default.readTimeout=5000
  • openfeign-producer项目的ProducerController.java类
  • openfeign-consumer项目的ProviderService.java类
  • openfeign-consumer项目的ConsumerController.java类
  • 测试请求http://localhost:8002/consumer/timeoutDemo,结果如下:
  • 修改application.yml文件,将默认超时时间修改为5秒
  • 再次执行http://localhost:8002/consumer/timeoutDemo,结果如下,没有报超时异常:
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-05-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 爪哇缪斯 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1> 服务通信概述
  • 2> 实例演示
  • 3> 存在的问题
  • 第二部分:Ribbon
    • 1> 概述
    • 2> 在微服务中的Ribbon
    • 3> 使用Ribbon+RestTemplate实现服务间请求调用
      • 3.1> DiscoveryClient
      • 3.2> LoadBalanceClient
      • 3.3> @LoadBalanced
    • 4> Ribbon实现负载均衡原理
      • 4.1> 负载均衡相关源码解析
      • 4.2> 负载均衡策略
      • 4.3> 自定义负载均衡策略
  • 第三部分:OpenFeign
    • 1> 概述
    • 2> 实现OpenFeign的请求调用
      • 2.1> 创建两个项目openfeign-producer和openfeign-consumer
      • 2.2> 引入服务注册中心Nacos的依赖
      • 2.3> 加入Nacos的配置信息
      • 2.4> 开启服务发现和FeignClient
      • 2.5> 创建ProducerController类
      • 2.6> 在openfeign-consumer项目中创建OpenFeign接口
      • 2.7> 创建ConsumerController类
      • 2.8> 进行测试
    • 3> OpenFeign的参数传递
      • 3.1> 传递基本类型参数
      • 3.2> 传递对象类型参数
      • 3.3> 传递数组类型参数
      • 3.4> 传递集合类型参数
    • 4> OpenFeign的返回值处理
      • 4.1> 使用OpenFeign调用服务,并返回对象
    • 5> OpenFeign的细节
      • 5.1> OpenFeign默认超时处理
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档