首页 > 其他分享 >扒一扒Nacos、OpenFeign、Ribbon、loadbalancer组件协调工作的原理

扒一扒Nacos、OpenFeign、Ribbon、loadbalancer组件协调工作的原理

时间:2023-04-11 13:22:52浏览次数:55  
标签:服务 OpenFeign SpringCloud Nacos 实例 loadbalancer 注册 Ribbon

大家好,我是三友~~

前几天有个大兄弟问了我一个问题,注册中心要集成SpringCloud,想实现SpringCloud的负载均衡,需要实现哪些接口和规范。

既然这个兄弟问到我了,而我又刚好知道,这不得好好写一篇文章来回答这个问题,虽然在后面的聊天中我已经回答过了。

接下来本文就以探究一下Nacos、OpenFeign、Ribbon、loadbalancer等组件协调工作的原理的方式,来讲一讲应该需要是实现哪些接口了。

再多说一句,本文并没有详细地深入剖析各个组件的源码,如果有感兴趣的兄弟可以从微信公众号三友的java日记后台菜单栏中的文章分类中查看我之前写的关于Nacos、OpenFeign、Ribbon源码剖析的文章。

Nacos

先从Nacos讲起。

Nacos是什么,官网中有这么一段话

这一段话说的直白点就是Nacos是一个注册中心和配置中心!

在Nacos中有客户端和服务端的这个概念

  • 服务端需要单独部署,用来保存服务实例数据的
  • 客户端就是用来跟服务端通信的SDK,支持不同语言

当需要向Nacos服务端注册或者获取服务实例数据的时候,只需要通过Nacos提供的客户端SDK就可以了,就像下面这样:

引入依赖

<dependency>
    <groupId>com.alibaba.nacos</groupId>
    <artifactId>nacos-client</artifactId>
    <version>1.4.4</version>
</dependency>

示例代码

Properties properties = new Properties();
properties.setProperty("serverAddr", "localhost");
properties.setProperty("namespace", "8848");

NamingService naming = NamingFactory.createNamingService(properties);

//服务注册,注册一个order服务,order服务的ip是192.168.2.100,端口8080
naming.registerInstance("order", "192.168.2.100", 8080);

//服务发现,获取所有的order服务实例
List<Instance> instanceList = naming.selectInstances("order", true);

当服务注册到Nacos服务端的时候,在服务端内部会有一个集合去存储服务的信息

这个集合在注册中心界中有个响亮的名字,服务注册表

如何进行服务自动注册?

用过SpringCloud的小伙伴肯定知道,在项目启动的时候服务能够自动注册到服务注册中心,并不需要手动写上面那段代码,那么服务自动注册是如何实现的呢?

服务自动注册三板斧

SpringCloud本身提供了一套服务自动注册的机制,或者说是约束,其实就是三个接口,只要注册中心实现这些接口,就能够在服务启动时自动注册到注册中心,而这三个接口我称为服务自动注册三板斧。

服务实例数据封装--Registration

Registration是SpringCloud提供的一个接口,继承了ServiceInstance接口

Registration
Registration
ServiceInstance
ServiceInstance

从ServiceInstance的接口定义可以看出,这是一个服务实例数据的封装,比如这个服务的ip是多少,端口号是多少。

所以Registration就是当前服务实例数据封装,封装了当前服务的所在的机器ip和端口号等信息。

Nacos既然要整合SpringCloud,自然而然也实现了这个接口

NacosRegistration
NacosRegistration

这样当前服务需要被注册到注册中心的信息就封装好了。

服务注册--ServiceRegistry

ServiceRegistry也是个接口,泛型就是上面提到的服务实例数据封装的接口

ServiceRegistry
ServiceRegistry

这个接口的作用就是把上面封装的当前服务的数据Registration注册通过register方法注册到注册中心中。

Nacos也实现了这个接口。

NacosServiceRegistry
NacosServiceRegistry

并且核心的注册方法的实现代码跟前面的demo几乎一样

服务自动注册--AutoServiceRegistration
AutoServiceRegistration
AutoServiceRegistration

AutoServiceRegistration是一个标记接口,所以本身没有实际的意义,仅仅代表了自动注册的意思。

AutoServiceRegistration有个抽象实现AbstractAutoServiceRegistration

AbstractAutoServiceRegistration是个抽象类
AbstractAutoServiceRegistration是个抽象类

AbstractAutoServiceRegistration实现了ApplicationListener,监听了WebServerInitializedEvent事件。

WebServerInitializedEvent这个事件是SpringBoot在项目启动时,当诸如tomcat这类Web服务启动之后就会发布,注意,只有在Web环境才会发布这个事件。

ServletWebServerInitializedEvent继承自WebServerInitializedEvent。

所以一旦当SpringBoot项目启动,tomcat等web服务器启动成功之后,就会触发AbstractAutoServiceRegistration监听器的执行。

最终就会调用ServiceRegistry注册Registration,实现服务自动注册

Nacos自然而然也继承了AbstractAutoServiceRegistration

NacosAutoServiceRegistration
NacosAutoServiceRegistration

对于Nacos而言,就将当前的服务注册的ip和端口等信息,就注册到了Nacos服务注册中心。

所以整个注册流程就可以用这么一张图概括

当然,不仅仅是Nacos是这么实现的,常见的比如Eureka,Zookeeper等注册中心在整合SpringCloud都是实现上面的三板斧。

Ribbon

讲完了SpringCloud环境底下是如何自动注册服务到注册中心的,下面来讲一讲Ribbon。

我们都知道,Ribbon是负载均衡组件,他的作用就是从众多的服务实例中根据一定的算法选择一个服务实例。

但是有个疑问,服务实例的数据都在注册中心,Ribbon是怎么知道的呢???

答案其实很简单,那就是需要注册中心去主动适配Ribbon,只要注册中心去适配了Ribbon,那么Ribbon自然而然就知道服务实例的数据了。

Ribbon提供了一个获取服务实例的接口,叫ServerList

ServerList
ServerList

接口中提供了两个方法,这两个方法在众多的实现中实际是一样的,并没有区别。

当Ribbon通过ServerList获取到服务实例数据之后,会基于这些数据来做负载均衡的。

Nacos自然而然也实现了ServerList接口,为Ribbon提供Nacos注册中心中的服务数据。

NacosServerList
NacosServerList

这样,Ribbon就能获取到了Nacos服务注册中心的数据。

同样地,除了Nacos之外,Eureka、Zookeeper等注册中心也都实现了这个接口。

到这,其实就明白了Ribbon是如何知道注册中心的数据了,需要注册中心来适配。

在这里插个个人的看法,其实我觉得Ribbon在适配SpringCloud时对获取服务实例这块支持封装的不太好。

因为SpringCloud本身就是一套约束、规范,只要遵守这套规范,那么就可以实现各个组件的替换,这就是为什么换个注册中心只需要换个依赖,改个配置文件就行。

而Ribbon本身是一个具体的负载均衡组件,注册中心要想整合SpringCloud,还得需要单独去适配Ribbon,有点违背了SpringCloud约束的意义。

就类似mybatis一样,mybatis依靠jdbc,但是mybatis根本不关心哪个数据库实现的jdbc。

真正好的做法是Ribbon去适配SpringCloud时,用SpringCloud提供的api去获取服务实例,这样不同的注册中心只需要适配这个api,无需单独适配Ribbon了。

而SpringCloud实际上是提供了这么一个获取服务实例的api,DiscoveryClient

DiscoveryClient
DiscoveryClient

通过DiscoveryClient就能够获取到服务实例,当然也是需要不同注册中心的适配。

随着Ribbon等组件停止维护之后,SpringCloud官方自己也搞了一个负载均衡组件loadbalancer,用来平替Ribbon。

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-loadbalancer</artifactId>
    <version>2.2.5.RELEASE</version>
</dependency>

这个组件底层在获取服务实例的时候,就是使用的DiscoveryClient。

所以对于loadbalancer这个负载均衡组价来说,注册中心只需要实现DiscoveryClient之后就自然而然适配了loadbalancer

OpenFeign

OpenFeign是一个rpc框架,当我们需要调用远程服务的时候,只需要声明个接口就可以远程调用了,就像下面这样

听上去很神奇,其实本质上就是后面会为接口创建一个动态代理对象,解析类上,方法上的注解。

当调用方法的时候,会根据方法上面的参数拼接一个http请求地址,这个地址的格式是这样的http://服务名/接口路径

比如,上面的例子,当调用saveOrder方法的时候,按照这种规律拼出的地址就是这样的 http://order/order,第一个order是服务名,第二个order是PostMapping注解上面的。

但是由于只知道需要调用服务的服务名,不知道服务的ip和端口,还是无法调用远程服务,这咋办呢?

这时就轮到Ribbon登场了,因为Ribbon这个大兄弟知道服务实例的数据。

于是乎,OpenFeign就对Ribbon说,兄弟,你不是可以从注册中心获取到order服务所有服务实例数据么,帮我从这些服务实例数据中找一个给我。

于是Ribbon就会从注册中心获取到的服务实例中根据负载均衡策略选择一个服务实例返回给OpenFeign。

OpenFeign拿到了服务实例,此时就获取到了服务所在的ip和端口,接下来就会重新构建请求路径,将路径中的服务名替换成ip和端口,代码如下

reconstructURIWithServer
reconstructURIWithServer
  • Server就是服务实例信息的封装
  • orignal就是原始的url,就是上面提到的,http://order/order

假设获取到的orde服务所在的ip和端口分别是192.168.2.1008080,最终重构后的路径就是http://192.168.2.100:8080/order,之后OpenFeign就可以发送http请求了。

至于前面提到的loadbalancer,其实也是一样的,他也会根据负载均衡算法,从DiscoveryClient获取到的服务实例中选择一个服务实例给OpenFeign,后面也会根据服务实例重构url,再发送http请求。

loadbalancer组件重构url代码
loadbalancer组件重构url代码

总结

到这,就把Nacos、OpenFeign、Ribbon、loadbalancer等组件协调工作的原理讲完了,其实就是各个组件会预留一些扩展接口,这也是很多开源框架都会干的事,当第三方框架去适配的,只要实现这些接口就可以了。

最后画一张图来总结一下上述组价的工作的原理。

最后再小小地说一句,Nacos、OpenFeign、Ribbon源码剖析的文章,可以从微信公众号三友的java日记后台菜单栏中的文章分类中查看。

往期热门文章推荐

RocketMQ重复消费的7种原因

如何去阅读源码,我总结了18条心法

如何实现延迟任务,我总结了11种方法

如何写出漂亮代码,我总结了45个小技巧

三万字盘点Spring/Boot的那些常用扩展点

两万字盘点那些被玩烂了的设计模式

扫码或者搜索关注公众号 三友的java日记 ,及时干货不错过,公众号致力于通过画图加上通俗易懂的语言讲解技术,让技术更加容易学习,回复 面试 即可获得一套面试真题。

标签:服务,OpenFeign,SpringCloud,Nacos,实例,loadbalancer,注册,Ribbon
From: https://www.cnblogs.com/zzyang/p/17305903.html

相关文章

  • nacos 启动DataSource Set解决办法
    通过查看config-fatal.log日志文件发现   报错:com.mysql.cj.exceptions.CJException:PublicKeyRetrievalisnotallowed经调查资料得知,此原因跟mySql版本有关,最核心的原因是mysql8.0.13开始,使用sslMode属性代替了原来的useSSL属性,所以吧useSSL改成sslMode=DISAB......
  • ava: 程序包com.alibaba.nacos.api.common不存在_RuoYi-Cloud-Plus-master_jar包不存
    来看看原因吧,jar包是存在的,但是就是在idea中引用不到,来看看怎么回事: 原来就是这个包找不到,但是从下面看是有的: 但是注意,这里的com.alibaba.nacos.api...原来可不是这样的,这个是我后来修改过的,原来是只有com.alibaba.nacos.common,而引用的是com.alibaba.nacos.api.commo......
  • SpringCloud源码学习笔记3——Nacos服务注册源码分析
    系列文章目录和关于我一丶基本概念&Nacos架构1.为什么需要注册中心实现服务治理、服务动态扩容,以及调用时能有负载均衡的效果。如果我们将服务提供方的ip地址配置在服务消费方的配置文件中,当服务提供方实例上线下线,消费方都需要重启服务,导致二者耦合度过高。注册中心就是在......
  • MySQL数据库与Nacos搭建监控服务
    目录Nacos部署项目环境快速开始nacos2.2.0版本配置说明MySQL部署安装方式Linux平台(CentOS-Stream-9)部署MySQL调试防火墙管理工具MySQL用户权限MySQL导入mysql-schema脚本Springboot项目构建项目环境项目构建Nacos联动测试Nacos监控(控制台)基本功能演示验证数据库表我相信有不少小......
  • nacos
    Nacos致力于帮助您发现、配置和管理微服务。Nacos帮助您更敏捷和容易地构建、交付和管理微服务平台。Nacos是构建以“服务”为中心的现代应用架构(例如微服务范式、云原生范式)的服务基础设施。 服务发现和服务健康监测Nacos支持基于DNS和基于RPC的服务发现。......
  • 2-nacos运行环境部署
    1、下载nacos最新的二进制压缩包;下载地址:https://github.com/alibaba/nacos/releases 2、解压下载下来的nacos最新的二进制压缩包;tar-zxvfnacos-server-1.3.1.tar.gzcdnacos/bin3、启动nacosserver./startup.sh-mstandalone 注:单机环境必须带-mstandalone参数启动......
  • openfeign超时重试
    通过http调用服务受网络影响较大,当网络波动时,http调用可能会失败,需要去重试,可以手动重试,这样代码会很不优雅。所幸feign有自己的超时重试机制,Ribbon的重试机制和Feign的重试机制有冲突,所以源码中默认关闭Feign的重试机制。 样例搭建修改Producer模块中的controller,将@Request......
  • Spring Cloud LoadBalancer
    ReactiveLoadBalancer与ServiceInstanceListSupplierSpringCloud提供了client的load-balance抽象和实现。在load-balance机制中添加了ReactiveLoadBalancer接口,并且为其提供了Round-Robin-based和Random实现。为了从反应式服务中选择服务实例,使用了ServiceInstanceListSupplier......
  • nacos默认配置启动
    1.相关组件组件说明版本地址Nacos配置及注册中心https://github.com/alibaba/nacos/releasesps:SpringBoot、SpringCloud和nacos集成版本对应关系对照(版本若对应不上,应用可能会启动报错):https://github.com/alibaba/spring-cloud-alibaba/wiki/版本说明2.组件......
  • openfeign开启日志
    openfeign的日志级别有:NONE:默认,不开启日志BASIC:只记录请求方法和URL以及响应状态代码和执行时间HEADERS:记录基本信息以及请求和响应标头。FULL:记录请求和响应的标题、正文和元数据。  全局日志加入Logger.LevelBean:@ConfigurationpublicclassMyConfigration{......