目录
Feign是什么
Feign 是一种声明式服务调用组件,它在 RestTemplate 的基础上做了进一步的封装。通过 Feign,我们只需要声明一个接口并通过注解进行简单的配置(类似于 Dao 接口上面的 Mapper 注解一样)即可实现对 HTTP 接口的绑定。
通过 Feign,我们可以像调用本地方法一样来调用远程服务,而完全感觉不到这是在进行远程调用。
Feign 对 Ribbon 进行了集成,利用 Ribbon 维护了一份可用服务清单,并通过 Ribbon 实现了客户端的负载均衡。
调用原理
1、在微服务启动时,会向服务发现中心上报自身实例信息,这里ServiceB 包含多个实例 每个实例包括:IP地址、端口号信息。
2、微服务会定期从Nacos Server(服务发现中心)获取服务实例列表。
3、当ServiceA调用ServiceB时,ribbon组件从本地服务实例列表中查找ServiceB的实例,如获取了多个实例如:Instance1、Instance2。这时ribbon会通过用户所配置的负载均衡策略从中选择一个实例。
4、最终,Feign组件会通过ribbon选取的实例发送http请求。
采用Feign+Ribbon的整合方式,是由Feign完成远程调用的整个流程。而Feign集成了Ribbon,Feign使用Ribbon完成调用实例的负载均衡。
Feign远程调用,核心就是通过一系列的封装和处理,将以JAVA注解的方式定义的远程调用API接口,最终转换成HTTP的请求形式,然后将HTTP的请求的响应结果,解码成JAVA Bean,放回给调用者。Feign远程调用的基本流程,大致如下图所示。
从上图可以看到,Feign通过处理注解,将请求模板化,当实际调用的时候,传入参数,根据参数再应用到请求上,进而转化成真正的 Request 请求。通过Feign以及JAVA的动态代理机制,使得Java 开发人员,可以不用通过HTTP框架去封装HTTP请求报文的方式,完成远程服务的HTTP调用。
加载原理
在微服务启动时,Feign会进行包扫描,对加@FeignClient注解的接口,按照注解的规则,创建远程接口的本地JDK Proxy代理实例。然后,将这些本地Proxy代理实例,注入到Spring IOC容器中。当远程接口的方法被调用,由Proxy代理实例去完成真正的远程访问,并且返回结果。
Feign 整体框架非常小巧,在处理请求转换和消息解析的过程中,基本上没什么时间消耗。真正影响性能的,是处理Http请求的环节。
负载均衡
负载均衡就是将网络流量(负载)分摊到不同的网络服务器(可以平均分配,也可以不平均),系统就可以实现服务的水平横向扩展。
那么如果让你设计一个负载均衡组件,你会怎么设计?
我们需要考虑这几个因素:
-
如何获取及同步服务器列表?涉及到与注册中心的交互。
-
如何将负载进行分摊?涉及到分摊策略。
-
如何将客户端请求进行拦截然后选择服务器进行转发?涉及到请求拦截
我们从负载均衡的原理 + Ribbon 的架构来学习如何设计一个负载均衡器。
负载均衡也是高可用网络的关键组件:
负载均衡的 两个基本点:
-
选择哪个服务器来处理客户端请求。
-
将客户端请求转发出去。
一个核心原理:通过硬件或软件的方式维护一个服务列表清单。当用户发送请求时,会将请求发送给负载均衡器,然后根据负载均衡算法从可用的服务列表中选出一台服务器的地址,将请求进行转发,完成负载功能。
负载均衡分类
硬件负载均衡
F5 就是常见的硬件负载均衡产品。
优点:性能稳定,具备很多软件负载均衡不具备的功能,如应用交换,会话交换、状态监控等。
缺点:设备价格昂贵、配置冗余,没有软件负载均衡灵活,不能满足定制化需求。
软件负载均衡
Nginx:性能好,可以负载超过 1W。工作在网络的7层之上,可以针对http应用做一些分流的策略。Nginx也可作为静态网页和图片服务器。Nginx仅能支持http、https和Email协议。
LVS(Linux Virtual Server):是一个虚拟服务器集群系统,采用 IP 地址均衡技术和内容请求分发技术实现负载均衡。接近硬件设备的网络吞吐和连接负载能力。抗负载能力强、是工作在网络4层之上仅作分发之用。自身有完整的双机热备方案,如LVS+Keepalived。软件本身不支持正则表达式处理,不能做动静分离。
服务端负载均衡
Nginx 和 F5 都可以划分到服务端的负载均衡里面,后端的服务器地址列表是存储在后端服务器中或者存在专门的 Nginx 服务器或 F5 上。
服务器的地址列表的来源是通过注册中心或者手动配置的方式来的。
客户端负载均衡
终于轮到 Ribbon 登场了,它属于客户端负载均衡器,客户端自己维护一份服务器的地址列表。这个维护的工作就是由 Ribbon 来干的。
Ribbon 会从 Eureka Server 读取服务信息列表,存储在 Ribbon 中。如果服务器宕机了,Ribbon 会从列表剔除宕机的服务器信息。
Ribbon 有多种负载均衡算法,我们可以自行设定规则从而请求到指定的服务器。
常见的均衡策略如下:
轮循均衡
权重轮询均衡
随机均衡
Ribbon 核心组件
Ribbon 主要有五大功能组件:ServerList、Rule、Ping、ServerListFilter、ServerListUpdater。
负载均衡器 LoadBalancer
用于管理负载均衡的组件。初始化的时候通过加载 YMAL 配置文件创建出来的。
服务列表 ServerList
ServerList 主要用来获取所有服务的地址信息,并存到本地。
根据获取服务信息的方式不同,又分为静态存储和动态存储。
静态存储:从配置文件中获取服务节点列表并存储到本地。
动态存储:从注册中心获取服务节点列表并存储到本地
服务列表过滤 ServerListFilter
将获取到的服务列表按照过滤规则过滤。
-
通过 Eureka 的分区规则对服务实例进行过滤。
-
比较服务实例的通信失败数和并发连接数来剔除不够健康的实例。
-
根据所属区域过滤出同区域的服务实例。
服务列表更新 ServerListUpdater
服务列表更新就是 Ribbon 会从注册中心获取最新的注册表信息。
心跳检测 Ping
IPing 接口类用来检测哪些服务可用。如果不可用了,就剔除这些服务。
实现类主要有这几个:PingUrl、PingConstant、NoOpPing、DummyPing、NIWSDiscoveryPing。
心跳检测策略对象 IPingStrategy,默认实现是轮询检测。
负载均衡策略 Rule
请求原理
第一步:Ribbon 拦截所有标注 @loadBalance 注解的 RestTemplate。RestTemplate 是用来发送 HTTP 请求的。
第二步:将 Ribbon 默认的拦截器 LoadBalancerInterceptor 添加到 RestTemplate 的执行逻辑中,当 RestTemplate 每次发送 HTTP 请求时,都会被 Ribbon 拦截。
第三步:拦截后,Ribbon 会创建一个 ILoadBalancer 实例。
第四步:ILoadBalancer 实例会使用 RibbonClientConfiguration 完成自动配置。就会配置好 IRule,IPing,ServerList。
第五步:Ribbon 会从服务列表中选择一个服务,将请求转发给这个服务。
Feign对Ribbon做了二次封装,实现了内部负载均衡。