大家好,我是三友~~
前几天有个大兄弟问了我一个问题,注册中心要集成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>
示例代码
Propertiesproperties=newProperties();
properties.setProperty("serverAddr","localhost");
properties.setProperty("namespace","8848");
NamingServicenaming=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
ServiceInstance
从ServiceInstance的接口定义能够看出,这是一个服务实例数据的封装,比方这个服务的ip是多少,端口号是多少。
所以Registration便是当时服务实例数据封装,封装了当时服务的地点的机器ip和端口号等信息。
Nacos已然要整合SpringCloud,自然而然也完成了这个接口
NacosRegistration
这样当时服务需求被注册到注册中心的信息就封装好了。
服务注册–ServiceRegistry
ServiceRegistry也是个接口,泛型便是上面说到的服务实例数据封装的接口
ServiceRegistry
这个接口的效果便是把上面封装的当时服务的数据Registration注册经过register
办法注册到注册中心中。
Nacos也完成了这个接口。
NacosServiceRegistry
并且核心的注册办法的完成代码跟前面的demo几乎相同
服务自动注册–AutoServiceRegistration
AutoServiceRegistration
AutoServiceRegistration是一个符号接口,所以自身没有实践的含义,只是代表了自动注册的意思。
AutoServiceRegistration有个笼统完成AbstractAutoServiceRegistration
AbstractAutoServiceRegistration是个笼统类
AbstractAutoServiceRegistration完成了ApplicationListener,监听了WebServerInitializedEvent事件。
WebServerInitializedEvent这个事件是SpringBoot在项目启动时,当诸如tomcat这类Web服务启动之后就会发布,留意,只需在Web环境才会发布这个事件。
ServletWebServerInitializedEvent承继自WebServerInitializedEvent。
所以一旦当SpringBoot项目启动,tomcat等web服务器启动成功之后,就会触发AbstractAutoServiceRegistration监听器的履行。
最终就会调用ServiceRegistry注册Registration,完成服务自动注册
Nacos自然而然也承继了AbstractAutoServiceRegistration
NacosAutoServiceRegistration
关于Nacos而言,就将当时的服务注册的ip和端口等信息,就注册到了Nacos服务注册中心。
所以整个注册流程就能够用这么一张图归纳
当然,不只是是Nacos是这么完成的,常见的比方Eureka,Zookeeper等注册中心在整合SpringCloud都是完成上面的三板斧。
Ribbon
讲完了SpringCloud环境底下是怎么自动注册服务到注册中心的,下面来讲一讲Ribbon。
咱们都知道,Ribbon是负载均衡组件,他的效果便是从众多的服务实例中依据必定的算法挑选一个服务实例。
可是有个疑问,服务实例的数据都在注册中心,Ribbon是怎么知道的呢???
答案其实很简单,那便是需求注册中心去自动适配Ribbon,只需注册中心去适配了Ribbon,那么Ribbon自然而然就知道服务实例的数据了。
Ribbon供给了一个获取服务实例的接口,叫ServerList
ServerList
接口中供给了两个办法,这两个办法在众多的完成中实践是相同的,并没有差异。
当Ribbon经过ServerList获取到服务实例数据之后,会依据这些数据来做负载均衡的。
Nacos自然而然也完成了ServerList接口,为Ribbon供给Nacos注册中心中的服务数据。
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就能够获取到服务实例,当然也是需求不同注册中心的适配。
随着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
- Server便是服务实例信息的封装
- orignal便是原始的url,便是上面说到的,
http://order/order
假设获取到的orde服务地点的ip和端口分别是192.168.2.100
和8080
,最终重构后的途径便是http://192.168.2.100:8080/order
,之后OpenFeign就能够发送http恳求了。
至于前面说到的loadbalancer
,其实也是相同的,他也会依据负载均衡算法,从DiscoveryClient获取到的服务实例中挑选一个服务实例给OpenFeign,后边也会依据服务实例重构url,再发送http恳求。
loadbalancer组件重构url代码
总结
到这,就把Nacos、OpenFeign、Ribbon、loadbalancer等组件和谐作业的原理讲完了,其实便是各个组件会预留一些扩展接口,这也是很多开源结构都会干的事,当第三方结构去适配的,只需完成这些接口就能够了。
最终画一张图来总结一下上述组价的作业的原理。
最终再小小地说一句,Nacos、OpenFeign、Ribbon源码分析的文章,能够从微信大众号三友的java日记后台菜单栏中的文章分类中查看。
搜索关注大众号 三友的java日记 ,及时干货不错失,大众号致力于经过画图加上通俗易懂的言语解说技能,让技能更加容易学习。
往期抢手文章推荐
RocketMQ重复消费的7种原因
怎么去阅读源码,我总结了18条心法
怎么完成推迟使命,我总结了11种办法
怎么写出美丽代码,我总结了45个小技巧
三万字盘点Spring/Boot的那些常用扩展点
两万字盘点那些被玩烂了的规划模式