Nacos 服務注冊與發(fā)現(xiàn)原理分析

Nacos 另一個非常重要的特性就是服務注冊與發(fā)現(xiàn),說到服務的注冊與發(fā)現(xiàn)相信大家應該都不陌生,在微服務盛行的今天,服務是非常重要的,而在 Nacos 中服務更被稱為他的一等公民。

Nacos 支持幾乎所有主流類型的 “服務” 的發(fā)現(xiàn)、配置和管理。

了解過 Dubbo 的同學,應該對 Dubbo 的架構(gòu)非常熟悉,最經(jīng)典的一張架構(gòu)圖如下所示:

dubbo-arch.jpg

圖中的6個步驟的含義解釋如下:

0、服務容器負責啟動,加載,運行服務提供者。

1、服務提供者在啟動時,向注冊中心注冊自己提供的服務。

2、服務消費者在啟動時,向注冊中心訂閱自己所需的服務。

3、注冊中心返回服務提供者地址列表給消費者,如果有變更,注冊中心將基于長連接推送變更數(shù)據(jù)給消費者。

4、服務消費者,從提供者地址列表中,基于軟負載均衡算法,選一臺提供者進行調(diào)用,如果調(diào)用失敗,再選另一臺調(diào)用。

5、服務消費者和提供者,在內(nèi)存中累計調(diào)用次數(shù)和調(diào)用時間,定時每分鐘發(fā)送一次統(tǒng)計數(shù)據(jù)到監(jiān)控中心。

其中圖中最上方的 Registry 就是注冊中心,負責服務的注冊與發(fā)現(xiàn)。Dubbo 有自己的 Registry 實現(xiàn),而 Nacos 則是另一種 Registry 的實現(xiàn)。

現(xiàn)在我們來了解下 Nacos 的服務注冊與發(fā)現(xiàn),首先在本地將 Nacos 服務端啟動起來,具體怎么操作這里不在贅述,不清楚的同學可以參考我的其他文章。

模擬服務注冊

我們模擬將同一個服務的兩個實例注冊到 Nacos 中,代碼如下圖所示:

service-provider.jpg

通過 NamingService 接口的 registerInstance 方法就可以將服務進行注冊了,該方法有很多重載的方法,這里我們選擇一個簡單的來調(diào)用就好了。

注冊完成后,通過調(diào)用 getAllInstances 方法,立即獲取所有可用的實例,然后讓主線程等待,打印如下:

service-provider-effect.jpg

從打印結(jié)果中可以發(fā)現(xiàn) naming 客戶端成功獲取到了兩個實例。

模擬服務發(fā)現(xiàn)

服務注冊之后,服務的消費者就可以向注冊中心訂閱自己所需要的服務了,注冊中心會將所有服務的實例“推送”給消費者,這里我在推送上打了引號,原因是實際上獲取服務是客戶端主動輪詢的,跟客戶端獲取配置中心的配置項的原理一樣。這里不進行具體的描述,有興趣的可以跟一下代碼就知道了。

現(xiàn)在我創(chuàng)建一個服務消費者,然后向注冊中心訂閱一個服務,當接收到注冊中心返回的服務列表之后,執(zhí)行5次 select 服務實例的操作,相當于進行一個模擬的服務請求,具體的代碼如下圖所示:

service-consumer.jpg

其中的 printInstances 方法主要是打印出所有服務的實例,為了節(jié)省篇幅就不寫出來了,將 ServiceConsumer 類啟動之后,打印出如下的日志:

service-consumer-effect.jpg

消費者每次獲取一個健康的實例進行調(diào)用,接下來我就來分析下整個服務注冊與發(fā)現(xiàn)的過程和大致的設(shè)計原理和思路。

服務如何注冊

服務注冊最重要的就是將服務注冊到哪里,在注冊中心服務端,肯定有一個用來管理服務的容器,他保存著所有服務的實例。

我們暫時不需要知道該容器具體的實現(xiàn)細節(jié),只需要知道有這樣一個概念。

nacos-registry-princple-1.jpg

nacos-registry-princple-2.jpg

nacos-registry-princple-3.jpg

nacos-registry-princple-4.jpg

服務如何發(fā)現(xiàn)

服務注冊到注冊中心后,服務的消費者就可以進行服務發(fā)現(xiàn)的流程了,消費者可以直接向注冊中心發(fā)送獲取某個服務實例的請求,這種情況下注冊中心將返回所有可用的服務實例給消費者,但是一般不推薦這種情況。另一種方法就是服務的消費者向注冊中心訂閱某個服務,并提交一個監(jiān)聽器,當注冊中心中服務發(fā)生變更時,監(jiān)聽器會收到通知,這時消費者更新本地的服務實例列表,以保證所有的服務均是可用的。

nacos-registry-princple-5.jpg

nacos-registry-princple-6.jpg

負載均衡

負載均衡有很多中實現(xiàn)方式,包括輪詢法,隨機方法法,對請求ip做hash后取模等等,從負載的維度考慮又分為:服務端負載均衡和客戶端負載均衡。

Nacos 的客戶端在獲取到服務的完整實例列表后,會在客戶端進行負載均衡算法來獲取一個可用的實例,模式使用的是隨機獲取的方式。

nacos-registry-princple-7.jpg

Nacos 服務注冊與訂閱的完整流程

Nacos 客戶端進行服務注冊有兩個部分組成,一個是將服務信息注冊到服務端,另一個是像服務端發(fā)送心跳包,這兩個操作都是通過 NamingProxy 和服務端進行數(shù)據(jù)交互的。

Nacos 客戶端進行服務訂閱時也有兩部分組成,一個是不斷從服務端查詢可用服務實例的定時任務,另一個是不斷從已變服務隊列中取出服務并通知 EventListener 持有者的定時任務。

nacos-service-register-found.png

官方提供的demo具有一定的迷惑性,不過這能迫使你去了解事物的本質(zhì)。

你如果直接官方的demo,你會發(fā)現(xiàn)如下有趣的情況:

1、第一次注冊了兩個實例,獲取實例時返回的是2個

2、然后解除注冊其中的一個實例,再次獲取實例時返回的還是2個

3、訂閱服務的監(jiān)聽器將會收到兩次 onEvent 回調(diào),第一次是2個實例,第二次是1個實例

按照正常的情況,注冊了兩個實例,然后解除注冊了一個只會,再次獲取實例應該返回1個實例才對,但是返回了2個。

深入了解下源碼就能知道原因:

客戶端將獲取到的服務實例保存在一個 map 中,而該 map 中的內(nèi)容是由調(diào)度任務定時去更新的,存在一定的延時。

總結(jié)一下

服務注冊

服務提供者向注冊中心注冊實例信息,注冊中心維護一個服務名對應服務列表的Map。

服務注冊成功后,提供者將與注冊中心維持心跳。心跳機制保證了注冊中心及時剔除失效的實例。

服務發(fā)現(xiàn)

消費者向注冊中心發(fā)送獲取某個服務實例的請求,并提交一個監(jiān)聽器,即服務訂閱,后續(xù)不斷從注冊中心查詢可用服務實例。

當注冊中心中服務發(fā)生變更時,監(jiān)聽器會收到通知,這時消費者更新本地的服務實例列表,以保證所有的服務均是可用的。

注冊中心將所有可用的服務實例返回,消費者緩存在本地。

消費者在本地維護一個服務列表??蛻舳诉M行負載均衡算法來獲取一個健康的實例,默認是隨機方式。

Nacos通過心跳機制推拉模式保證了服務的及時有效性。本地緩存保證了通信代價最小,負載均衡保證了服務的高可用。


逅弈逐碼,專注于原創(chuàng)分享,用通俗易懂的圖文描述源碼及原理

作者:逅弈

鏈接:http://www.itdecent.cn/p/61608ff86344

來源:簡書

著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請注明出處。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內(nèi)容