Nacos
如何進(jìn)行服務(wù)自動(dòng)注冊(cè)?
Ribbon
OpenFeign
總結(jié)
前幾天有個(gè)大兄弟問了我一個(gè)問題,注冊(cè)中心要集成SpringCloud,想實(shí)現(xiàn)SpringCloud的負(fù)載均衡,需要實(shí)現(xiàn)哪些接口和規(guī)范。
既然這個(gè)兄弟問到我了,而我又剛好知道,這不得好好寫一篇文章來回答這個(gè)問題,雖然在后面的聊天中我已經(jīng)回答過了。
接下來本文就來探究一下Nacos、OpenFeign、Ribbon、loadbalancer等組件協(xié)調(diào)工作的原理,知道這些原理之后,就知道應(yīng)該需要是實(shí)現(xiàn)哪些接口了。
Nacos
先從Nacos講起。
Nacos是什么,官網(wǎng)中有這么一段話
這一段話說的直白點(diǎn)就是Nacos是一個(gè)注冊(cè)中心和配置中心!
在Nacos中有客戶端和服務(wù)端的這個(gè)概念
服務(wù)端需要單獨(dú)部署,用來保存服務(wù)實(shí)例數(shù)據(jù)的
當(dāng)需要向Nacos服務(wù)端注冊(cè)或者獲取服務(wù)實(shí)例數(shù)據(jù)的時(shí)候,只需要通過Nacos提供的客戶端SDK就可以了,就像下面這樣:
引入依賴
com.alibaba.nacos nacos-client 1.4.4
示例代碼
Propertiesproperties=newProperties(); properties.setProperty("serverAddr","localhost"); properties.setProperty("namespace","8848"); NamingServicenaming=NamingFactory.createNamingService(properties); //服務(wù)注冊(cè),注冊(cè)一個(gè)order服務(wù),order服務(wù)的ip是192.168.2.100,端口8080 naming.registerInstance("order","192.168.2.100",8080); //服務(wù)發(fā)現(xiàn),獲取所有的order服務(wù)實(shí)例 ListinstanceList=naming.selectInstances("order",true);
當(dāng)服務(wù)注冊(cè)到Nacos服務(wù)端的時(shí)候,在服務(wù)端內(nèi)部會(huì)有一個(gè)集合去存儲(chǔ)服務(wù)的信息
這個(gè)集合在注冊(cè)中心界中有個(gè)響亮的名字,服務(wù)注冊(cè)表 。
如何進(jìn)行服務(wù)自動(dòng)注冊(cè)?
用過SpringCloud的小伙伴肯定知道,在項(xiàng)目啟動(dòng)的時(shí)候服務(wù)能夠自動(dòng)注冊(cè)到服務(wù)注冊(cè)中心,并不需要手動(dòng)寫上面那段代碼,那么服務(wù)自動(dòng)注冊(cè)是如何實(shí)現(xiàn)的呢?
服務(wù)自動(dòng)注冊(cè)三板斧
SpringCloud本身提供了一套服務(wù)自動(dòng)注冊(cè)的機(jī)制,或者說是約束,其實(shí)就是三個(gè)接口,只要注冊(cè)中心實(shí)現(xiàn)這些接口,就能夠在服務(wù)啟動(dòng)時(shí)自動(dòng)注冊(cè)到注冊(cè)中心,而這三個(gè)接口我稱為服務(wù)自動(dòng)注冊(cè)三板斧。
服務(wù)實(shí)例數(shù)據(jù)封裝--Registration
Registration是SpringCloud提供的一個(gè)接口,繼承了ServiceInstance接口
Registration ServiceInstance
從ServiceInstance的接口定義可以看出,這是一個(gè)服務(wù)實(shí)例數(shù)據(jù)的封裝,比如這個(gè)服務(wù)的ip是多少,端口號(hào)是多少。
所以Registration就是當(dāng)前服務(wù)實(shí)例數(shù)據(jù)封裝,封裝了當(dāng)前服務(wù)的所在的機(jī)器ip和端口號(hào)等信息。
Nacos既然要整合SpringCloud,自然而然也實(shí)現(xiàn)了這個(gè)接口
NacosRegistration
這樣當(dāng)前服務(wù)需要被注冊(cè)到注冊(cè)中心的信息就封裝好了。
服務(wù)注冊(cè)--ServiceRegistry
ServiceRegistry也是個(gè)接口,泛型就是上面提到的服務(wù)實(shí)例數(shù)據(jù)封裝的接口
ServiceRegistry
這個(gè)接口的作用就是把上面封裝的當(dāng)前服務(wù)的數(shù)據(jù)Registration注冊(cè)通過register方法注冊(cè)到注冊(cè)中心中。
Nacos也實(shí)現(xiàn)了這個(gè)接口。
NacosServiceRegistry
并且核心的注冊(cè)方法的實(shí)現(xiàn)代碼跟前面的demo幾乎一樣
服務(wù)自動(dòng)注冊(cè)--AutoServiceRegistration
AutoServiceRegistration
AutoServiceRegistration是一個(gè)標(biāo)記接口,所以本身沒有實(shí)際的意義,僅僅代表了自動(dòng)注冊(cè)的意思。
AutoServiceRegistration有個(gè)抽象實(shí)現(xiàn)AbstractAutoServiceRegistration
AbstractAutoServiceRegistration是個(gè)抽象類
AbstractAutoServiceRegistration實(shí)現(xiàn)了ApplicationListener,監(jiān)聽了WebServerInitializedEvent事件。
WebServerInitializedEvent這個(gè)事件是SpringBoot在項(xiàng)目啟動(dòng)時(shí),當(dāng)諸如tomcat這類Web服務(wù)啟動(dòng)之后就會(huì)發(fā)布,注意,只有在Web環(huán)境才會(huì)發(fā)布這個(gè)事件。
ServletWebServerInitializedEvent繼承自WebServerInitializedEvent。
所以一旦當(dāng)SpringBoot項(xiàng)目啟動(dòng),tomcat等web服務(wù)器啟動(dòng)成功之后,就會(huì)觸發(fā)AbstractAutoServiceRegistration監(jiān)聽器的執(zhí)行。
最終就會(huì)調(diào)用ServiceRegistry注冊(cè)Registration,實(shí)現(xiàn)服務(wù)自動(dòng)注冊(cè)
Nacos自然而然也繼承了AbstractAutoServiceRegistration
NacosAutoServiceRegistration
對(duì)于Nacos而言,就將當(dāng)前的服務(wù)注冊(cè)的ip和端口等信息,就注冊(cè)到了Nacos服務(wù)注冊(cè)中心。
所以整個(gè)注冊(cè)流程就可以用這么一張圖概括
當(dāng)然,不僅僅是Nacos是這么實(shí)現(xiàn)的,常見的比如Eureka、Zookeeper等注冊(cè)中心在整合SpringCloud都是實(shí)現(xiàn)上面的三板斧。
基于 Spring Boot + MyBatis Plus + Vue & Element 實(shí)現(xiàn)的后臺(tái)管理系統(tǒng) + 用戶小程序,支持 RBAC 動(dòng)態(tài)權(quán)限、多租戶、數(shù)據(jù)權(quán)限、工作流、三方登錄、支付、短信、商城等功能
項(xiàng)目地址:https://github.com/YunaiV/ruoyi-vue-pro
視頻教程:https://doc.iocoder.cn/video/
Ribbon
講完了SpringCloud環(huán)境底下是如何自動(dòng)注冊(cè)服務(wù)到注冊(cè)中心的,下面來講一講Ribbon。
我們都知道,Ribbon是負(fù)載均衡組件,他的作用就是從眾多的服務(wù)實(shí)例中根據(jù)一定的算法選擇一個(gè)服務(wù)實(shí)例。
但是有個(gè)疑問,服務(wù)實(shí)例的數(shù)據(jù)都在注冊(cè)中心,Ribbon是怎么知道的呢???
答案其實(shí)很簡(jiǎn)單,那就是需要注冊(cè)中心去主動(dòng)適配 Ribbon,只要注冊(cè)中心去適配了Ribbon,那么Ribbon自然而然就知道服務(wù)實(shí)例的數(shù)據(jù)了。
Ribbon提供了一個(gè)獲取服務(wù)實(shí)例的接口,叫ServerList
ServerList
接口中提供了兩個(gè)方法,這兩個(gè)方法在眾多的實(shí)現(xiàn)中實(shí)際是一樣的,并沒有區(qū)別。
當(dāng)Ribbon通過ServerList獲取到服務(wù)實(shí)例數(shù)據(jù)之后,會(huì)基于這些數(shù)據(jù)來做負(fù)載均衡的。
Nacos自然而然也實(shí)現(xiàn)了ServerList接口,為Ribbon提供Nacos注冊(cè)中心中的服務(wù)數(shù)據(jù)。
NacosServerList
這樣,Ribbon就能獲取到了Nacos服務(wù)注冊(cè)中心的數(shù)據(jù)。
同樣地,除了Nacos之外,Eureka、Zookeeper等注冊(cè)中心也都實(shí)現(xiàn)了這個(gè)接口。
到這,其實(shí)就明白了Ribbon是如何知道注冊(cè)中心的數(shù)據(jù)了,需要注冊(cè)中心來適配。
在這里插個(gè)個(gè)人的看法,其實(shí)我覺得Ribbon在適配SpringCloud時(shí)對(duì)獲取服務(wù)實(shí)例這塊支持封裝的不太好。
因?yàn)镾pringCloud本身就是一套約束、規(guī)范,只要遵守這套規(guī)范,那么就可以實(shí)現(xiàn)各個(gè)組件的替換,這就是為什么換個(gè)注冊(cè)中心只需要換個(gè)依賴,改個(gè)配置文件就行。
而Ribbon本身是一個(gè)具體的負(fù)載均衡組件,注冊(cè)中心要想整合SpringCloud,還得需要單獨(dú)去適配Ribbon,有點(diǎn)違背了SpringCloud約束的意義。
就類似mybatis一樣,mybatis依靠jdbc,但是mybatis根本不關(guān)心哪個(gè)數(shù)據(jù)庫實(shí)現(xiàn)的jdbc。
真正好的做法是Ribbon去適配SpringCloud時(shí),用SpringCloud提供的api去獲取服務(wù)實(shí)例,這樣不同的注冊(cè)中心只需要適配這個(gè)api,無需單獨(dú)適配Ribbon了。
而SpringCloud實(shí)際上是提供了這么一個(gè)獲取服務(wù)實(shí)例的api,DiscoveryClient
DiscoveryClient
通過DiscoveryClient就能夠獲取到服務(wù)實(shí)例,當(dāng)然也是需要不同注冊(cè)中心的適配。
隨著Ribbon等組件停止維護(hù)之后,SpringCloud官方自己也搞了一個(gè)負(fù)載均衡組件loadbalancer,用來平替Ribbon。
org.springframework.cloud spring-cloud-starter-loadbalancer 2.2.5.RELEASE
這個(gè)組件底層在獲取服務(wù)實(shí)例的時(shí)候,就是使用的DiscoveryClient。
所以對(duì)于loadbalancer這個(gè)負(fù)載均衡組價(jià)來說,注冊(cè)中心只需要實(shí)現(xiàn)DiscoveryClient之后就自然而然適配了loadbalancer。
基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 實(shí)現(xiàn)的后臺(tái)管理系統(tǒng) + 用戶小程序,支持 RBAC 動(dòng)態(tài)權(quán)限、多租戶、數(shù)據(jù)權(quán)限、工作流、三方登錄、支付、短信、商城等功能
項(xiàng)目地址:https://github.com/YunaiV/yudao-cloud
視頻教程:https://doc.iocoder.cn/video/
OpenFeign
OpenFeign是一個(gè)rpc框架,當(dāng)我們需要調(diào)用遠(yuǎn)程服務(wù)的時(shí)候,只需要聲明個(gè)接口就可以遠(yuǎn)程調(diào)用了,就像下面這樣
聽上去很神奇,其實(shí)本質(zhì)上就是后面會(huì)為接口創(chuàng)建一個(gè)動(dòng)態(tài)代理對(duì)象,解析類上,方法上的注解。
當(dāng)調(diào)用方法的時(shí)候,會(huì)根據(jù)方法上面的參數(shù)拼接一個(gè)http請(qǐng)求地址,這個(gè)地址的格式是這樣的http://服務(wù)名/接口路徑。
比如,上面的例子,當(dāng)調(diào)用saveOrder方法的時(shí)候,按照這種規(guī)律拼出的地址就是這樣的 http://order/order,第一個(gè)order是服務(wù)名,第二個(gè)order是PostMapping注解上面的。
但是由于只知道需要調(diào)用服務(wù)的服務(wù)名,不知道服務(wù)的ip和端口,還是無法調(diào)用遠(yuǎn)程服務(wù),這咋辦呢?
這時(shí)就輪到Ribbon登場(chǎng)了,因?yàn)镽ibbon這個(gè)大兄弟知道服務(wù)實(shí)例的數(shù)據(jù)。
于是乎,OpenFeign就對(duì)Ribbon說,兄弟,你不是可以從注冊(cè)中心獲取到order服務(wù)所有服務(wù)實(shí)例數(shù)據(jù)么,幫我從這些服務(wù)實(shí)例數(shù)據(jù)中找一個(gè)給我。
于是Ribbon就會(huì)從注冊(cè)中心獲取到的服務(wù)實(shí)例中根據(jù)負(fù)載均衡策略選擇一個(gè)服務(wù)實(shí)例返回給OpenFeign。
OpenFeign拿到了服務(wù)實(shí)例,此時(shí)就獲取到了服務(wù)所在的ip和端口,接下來就會(huì)重新構(gòu)建請(qǐng)求路徑,將路徑中的服務(wù)名替換成ip和端口,代碼如下
reconstructURIWithServer
Server就是服務(wù)實(shí)例信息的封裝
orignal就是原始的url,就是上面提到的,http://order/order
假設(shè)獲取到的orde服務(wù)所在的ip和端口分別是192.168.2.100和8080,最終重構(gòu)后的路徑就是http://192.168.2.100:8080/order,之后OpenFeign就可以發(fā)送http請(qǐng)求了。
至于前面提到的loadbalancer,其實(shí)也是一樣的,他也會(huì)根據(jù)負(fù)載均衡算法,從DiscoveryClient獲取到的服務(wù)實(shí)例中選擇一個(gè)服務(wù)實(shí)例給OpenFeign,后面也會(huì)根據(jù)服務(wù)實(shí)例重構(gòu)url,再發(fā)送http請(qǐng)求。
loadbalancer組件重構(gòu)url代碼
總結(jié)
到這,就把Nacos、OpenFeign、Ribbon、loadbalancer等組件協(xié)調(diào)工作的原理講完了,其實(shí)就是各個(gè)組件會(huì)預(yù)留一些擴(kuò)展接口,這也是很多開源框架都會(huì)干的事,當(dāng)?shù)谌娇蚣苋ミm配的,只要實(shí)現(xiàn)這些接口就可以了。
最后畫一張圖來總結(jié)一下上述組價(jià)的工作的原理。
-
接口
+關(guān)注
關(guān)注
33文章
8598瀏覽量
151164 -
服務(wù)端
+關(guān)注
關(guān)注
0文章
66瀏覽量
7010 -
nacos
+關(guān)注
關(guān)注
0文章
10瀏覽量
203
原文標(biāo)題:終于搞懂了 Nacos、OpenFeign、Ribbon 等組件協(xié)調(diào)工作的原理,太強(qiáng)了!
文章出處:【微信號(hào):芋道源碼,微信公眾號(hào):芋道源碼】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論