大家好,我是不才陈某~
前几天有个大兄弟问了我一个问题,注册核心要集成 SpringCloud,想实现 SpringCloud 的负载平衡,须要实现哪些接口和标准。
Java 指南:www.java-family.cn
既然这个兄弟问到我了,而我又刚好晓得,这不得好好写一篇文章来答复这个问题,尽管在前面的聊天中我曾经答复过了。
接下来本文就来探索一下 Nacos、OpenFeign、Ribbon、loadbalancer 等组件协调工作的原理,晓得这些原理之后,就晓得应该须要是实现哪些接口了。
再多说一句,本文并没有具体地深刻分析各个组件的源码,如果有感兴趣的兄弟能够从公众号后盾菜单栏中的文章分类中查看我之前写的对于 Nacos、OpenFeign、Ribbon 源码分析的文章。
Nacos
Nacos 是什么,官网中有这么一段话
这一段话说的直白点就是 Nacos 是一个注册核心和配置核心!
在 Nacos 中有客户端和服务端的这个概念
- 服务端须要独自部署,用来保留服务实例数据的
- 客户端就是用来跟服务端通信的 SDK,反对不同语言
Java 指南:www.java-family.cn
当须要向 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 接口
从 ServiceInstance 的接口定义能够看出,这是一个服务实例数据的封装,比方这个服务的 ip 是多少,端口号是多少。
所以 Registration 就是以后服务实例数据封装,封装了以后服务的所在的机器 ip 和端口号等信息。
Nacos 既然要整合 SpringCloud,自然而然也实现了这个接口
这样以后服务须要被注册到注册核心的信息就封装好了。
服务注册 –ServiceRegistry
ServiceRegistry 也是个接口,泛型就是下面提到的服务实例数据封装的接口
这个接口的作用就是把下面封装的以后服务的数据 Registration 注册通过 register
办法注册到注册核心中。
Nacos 也实现了这个接口。
并且外围的注册办法的实现代码跟后面的 demo 简直一样
服务主动注册 –AutoServiceRegistration
AutoServiceRegistration 是一个标记接口,所以自身没有理论的意义,仅仅代表了主动注册的意思。
AutoServiceRegistration 有个形象实现 AbstractAutoServiceRegistration
AbstractAutoServiceRegistration 实现了 ApplicationListener,监听了 WebServerInitializedEvent 事件。
WebServerInitializedEvent 这个事件是 SpringBoot 在我的项目启动时,当诸如 tomcat 这类 Web 服务启动之后就会公布,留神,只有在 Web 环境才会公布这个事件。
ServletWebServerInitializedEvent 继承自 WebServerInitializedEvent。
所以一旦当 SpringBoot 我的项目启动,tomcat 等 web 服务器启动胜利之后,就会触发 AbstractAutoServiceRegistration 监听器的执行。
最终就会调用 ServiceRegistry 注册 Registration,实现服务主动注册
Nacos 自然而然也继承了 AbstractAutoServiceRegistration
对于 Nacos 而言,就将以后的服务注册的 ip 和端口等信息,就注册到了 Nacos 服务注册核心。
所以整个注册流程就能够用这么一张图概括
当然,不仅仅是 Nacos 是这么实现的,常见的比方 Eureka、Zookeeper 等注册核心在整合 SpringCloud 都是实现下面的三板斧。
Ribbon
讲完了 SpringCloud 环境底下是如何主动注册服务到注册核心的,上面来讲一讲 Ribbon。
咱们都晓得,Ribbon 是负载平衡组件,他的作用就是从泛滥的服务实例中依据肯定的算法抉择一个服务实例。
然而有个疑难,服务实例的数据都在注册核心,Ribbon 是怎么晓得的呢???
答案其实很简略,那就是须要注册核心去被动 适配Ribbon,只有注册核心去适配了 Ribbon,那么 Ribbon 自然而然就晓得服务实例的数据了。
Ribbon 提供了一个获取服务实例的接口,叫 ServerList
接口中提供了两个办法,这两个办法在泛滥的实现中理论是一样的,并没有区别。
当 Ribbon 通过 ServerList 获取到服务实例数据之后,会基于这些数据来做负载平衡的。
Nacos 自然而然也实现了 ServerList 接口,为 Ribbon 提供 Nacos 注册核心中的服务数据。
这样,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 就可能获取到服务实例,当然也是须要不同注册核心的适配。
随着 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 和端口,代码如下
- 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 申请。
总结
到这,就把 Nacos、OpenFeign、Ribbon、loadbalancer 等组件协调工作的原理讲完了,其实就是各个组件会预留一些扩大接口,这也是很多开源框架都会干的事,当第三方框架去适配的,只有实现这些接口就能够了。
最初画一张图来总结一下上述组价的工作的原理。
最初再小小地说一句,Nacos、OpenFeign、Ribbon 源码分析的文章,能够从公众号后盾菜单栏中的文章分类中查看。
最初说一句(别白嫖,求关注)
陈某每一篇文章都是精心输入,如果这篇文章对你有所帮忙,或者有所启发的话,帮忙 点赞 、 在看 、 转发 、 珍藏,你的反对就是我坚持下去的最大能源!
另外陈某的常识星球开明了,公众号回复关键词:常识星球 获取限量20 元 优惠券退出只需 109 元,星球回馈的价值微小,目前更新了 Spring 全家桶实战系列、 亿级数据分库分表实战 、DDD 微服务实战专栏、 我要进大厂、Spring,Mybatis 等框架源码、架构实战 22 讲、精尽 RocketMQ等 …. 每减少一个专栏价格将上涨 20 元
关注公众号:【码猿技术专栏】,公众号内有超赞的粉丝福利,回复:加群,能够退出技术探讨群,和大家一起探讨技术,吹牛逼!