国产精品夜色视频一级区_hh99m福利毛片_国产一区二区成人久久免费影院_伊人久久大香线蕉综合影院75_国产精品久久果冻传媒

您的位置:首頁(yè) >聚焦 >

【全球報(bào)資訊】聊聊服務(wù)發(fā)現(xiàn)的推拉模型

2023-02-04 06:07:49    來(lái)源:程序員客棧

前言

過(guò)去一年,我的工作重心投入到了 API 網(wǎng)關(guān)(阿里云 CSB)中,這對(duì)于我來(lái)說(shuō)是一個(gè)新的領(lǐng)域,但和之前接觸的微服務(wù)治理方向又密不可分。API 網(wǎng)關(guān)適配微服務(wù)場(chǎng)景需要完成一些基礎(chǔ)能力的建設(shè),其一便是對(duì)接注冊(cè)中心,從而作為微服務(wù)的入口流量,例如 Zuul、SpringCloud Gateway 都實(shí)現(xiàn)了這樣的功能。實(shí)際上很多開(kāi)源網(wǎng)關(guān)在這一特性上均存在較大的局限性,本文暫不討論這些局限性,而是針對(duì)服務(wù)發(fā)現(xiàn)這一通用的場(chǎng)景,分享我對(duì)它的一些思考。


(資料圖)

概念澄清

服務(wù)發(fā)現(xiàn)這個(gè)詞說(shuō)實(shí)話還是有點(diǎn)抽象的,在微服務(wù)這一特定的領(lǐng)域具象化討論才有意義。“服務(wù)發(fā)現(xiàn)”指的是“服務(wù)消費(fèi)者獲取服務(wù)提供者服務(wù)地址”的這一過(guò)程,而“服務(wù)”這一名詞在不同微服務(wù)框架中代指也可能有所不同,不過(guò)大多數(shù)都是代指的應(yīng)用、接口等信息。

SpringCloud 以應(yīng)用維度表示服務(wù)Dubbo2.x 以接口維度表示服務(wù);Dubbo3.x 以應(yīng)用維度表示服務(wù)

服務(wù)從 Provider -> Registry -> Consumer 的這一流動(dòng)過(guò)程便是本文重點(diǎn)討論的內(nèi)容。

數(shù)據(jù)傳遞的兩種方式:推模型和拉模型,一直是老生常談的話題,在服務(wù)發(fā)現(xiàn)中也不妨一談。先不要急著回答服務(wù)發(fā)現(xiàn)這一場(chǎng)景中,推拉到底誰(shuí)好的問(wèn)題,讓我們先看看一些微服務(wù)框架中的服務(wù)發(fā)現(xiàn)是如何實(shí)現(xiàn)的。

微服務(wù)框架中的服務(wù)發(fā)現(xiàn)

這一節(jié)以 Dubbo 和 SpringCloud 兩個(gè)微服務(wù)框架為引子,看看它們的服務(wù)發(fā)現(xiàn)到底使用的是拉模型還是推模型。

Dubbo 服務(wù)發(fā)現(xiàn)

publicinterfaceRegistryService{voidregister(URLurl);voidunregister(URLurl);/***Subscribetoeligibleregistereddataandautomaticallypushwhentheregistereddataischanged.*/voidsubscribe(URLurl,NotifyListenerlistener);voidunsubscribe(URLurl,NotifyListenerlistener);Listlookup(URLurl);}

Dubbo 管理服務(wù)發(fā)現(xiàn)的核心接口 RegistryService直接給出了答案,通過(guò) subscribe 和 notify 這些關(guān)鍵字便可以猜測(cè)到 Dubbo 使用的是推模型。

上圖是一個(gè)推模型的工作流程。

SpringCloud 服務(wù)發(fā)現(xiàn)

publicinterfaceDiscoveryClientextendsOrdered{intDEFAULT_ORDER=0;Stringdescription();ListgetInstances(StringserviceId);ListgetServices();defaultvoidprobe(){this.getServices();}defaultintgetOrder(){return0;}}

DiscoveryClient是 SpringCloud 中一個(gè)核心服務(wù)發(fā)現(xiàn)的接口,通過(guò) getInstances基本可以看出,SpringCloud 使用的是拉模型。

上圖是一個(gè)拉模型的工作流程。

盡管我們還沒(méi)有詳細(xì)領(lǐng)略到兩個(gè)模型背后的優(yōu)化和實(shí)現(xiàn)細(xì)節(jié),但從事實(shí)來(lái)看,Dubbo 和 SpringCloud 使用了不同的服務(wù)發(fā)現(xiàn)機(jī)制,都能讓微服務(wù)玩轉(zhuǎn)起來(lái)。

此時(shí),如果你心里已經(jīng)有了 Dubbo 是推模型,SpringCloud 是拉模型的認(rèn)知,不妨再繼續(xù)看下一節(jié),可能這樣的認(rèn)知又會(huì)有了動(dòng)搖。

注冊(cè)中心中的推拉

上一節(jié)站在微服務(wù)框架的角度,介紹了服務(wù)發(fā)現(xiàn)的推拉模型,這一節(jié)則是站在注冊(cè)中心的角度來(lái)分析。說(shuō)到底,無(wú)論是 Dubbo 還是 SpringCloud,總得對(duì)接一款注冊(cè)中心才可以獲得服務(wù)發(fā)現(xiàn)的能力,可以是 Zookeeper,可以是 Nacos,可以是 Eureka,也可以是任意的其他提供了服務(wù)發(fā)現(xiàn)能力的組件。

我就先以 Nacos 為例介紹下它的推拉模型。先看 Nacos 的 Naming 模塊提供的核心接口:

publicinterfaceNamingService{voidregisterInstance(StringserviceName,Stringip,intport)throwsNacosException;voidderegisterInstance(StringserviceName,Stringip,intport)throwsNacosException;ListgetAllInstances(StringserviceName,booleansubscribe)throwsNacosException;ListselectInstances(StringserviceName,StringgroupName,booleanhealthy,booleansubscribe)throwsNacosException;voidsubscribe(StringserviceName,EventListenerlistener)throwsNacosException;voidunsubscribe(StringserviceName,Listclusters,EventListenerlistener)throwsNacosException;}

為了方便閱讀,我刪除了大部分重載的接口以及非核心的接口??梢园l(fā)現(xiàn),從 API 角度,Nacos 是同時(shí)提供了推模型和拉模型兩套接口的,這樣也是方便其被微服務(wù)框架集成,有興趣的讀者,可以自行去閱讀下 Dubbo/SpringCloud Alibaba 集成 Nacos 的代碼,Dubbo 使用的便是 subscribe 這一套推模型的接口,SpringCloud Alibaba 則是使用的 selectInstances 這一套拉模型的接口。

那是否說(shuō)"Nacos 是一個(gè)推拉模型結(jié)合的注冊(cè)中心"呢,不夠嚴(yán)謹(jǐn)。且看 getAllInstances,selectInstances 這兩個(gè)方法都有一個(gè) subscribe 入?yún)?,跟一下源碼探究一下

publicListselectInstances(StringserviceName,StringgroupName,Listclusters,booleanhealthy,booleansubscribe)throwsNacosException{ServiceInfoserviceInfo;if(subscribe){serviceInfo=hostReactor.getServiceInfo(NamingUtils.getGroupedName(serviceName,groupName),StringUtils.join(clusters,","));}else{serviceInfo=hostReactor.getServiceInfoDirectlyFromServer(NamingUtils.getGroupedName(serviceName,groupName),StringUtils.join(clusters,","));}returnselectInstances(serviceInfo,healthy);}

可以發(fā)現(xiàn) subscribe 這個(gè)參數(shù)控制的是是否直接從注冊(cè)中心拉取服務(wù),subscribe=false 時(shí),實(shí)際是從 Nacos 自身維護(hù)的一塊本地緩存中獲取到的服務(wù),大多數(shù)情況下,獲取服務(wù)使用的是 subscribe=true 的重載方法。所以,selectInstance 看起來(lái)是在拉服務(wù),subscribe 看起來(lái)是在推服務(wù),實(shí)際上 Nacos 內(nèi)核維護(hù)緩存的方式我們并未得知。

從上述 subscribe 的提示中,我們可以得出結(jié)論,我們并不能直接通過(guò)個(gè)別接口就得出該注冊(cè)中心使用的是推模型還是拉模型,究竟何種模型,還是要看 client 端是如何從 server 端加載/更新服務(wù)信息的。

那么,真實(shí)情況下,Nacos cleint 究竟是如何從 server 端獲取到服務(wù)列表的呢?也不賣(mài)關(guān)子了,直接給結(jié)論

在 Nacos 1.x 中,Nacos 采用的是定時(shí)拉 + udp 推送的機(jī)制??蛻舳藭?huì)啟動(dòng)一個(gè)定時(shí)器,每 10s 拉取一次服務(wù),確保服務(wù)端服務(wù)版本一致,為了解決 10s 間隔內(nèi)服務(wù)更新了,客戶端卻沒(méi)有及時(shí)收到通知的這一問(wèn)題,Nacos 還在服務(wù)端服務(wù)更新時(shí),觸發(fā)了一次 udp 推送。

在 Nacos 2.x 中,Nacos 采用的是服務(wù)端 tcp 推送的機(jī)制??蛻舳藛?dòng)時(shí)會(huì)跟服務(wù)端建立一條 tcp 長(zhǎng)連接,服務(wù)端服務(wù)變更后,會(huì)復(fù)用客戶端建立的這條連接進(jìn)行數(shù)據(jù)推送。

所以在回答,Nacos 到底是推模型還是拉模型時(shí),需要區(qū)分版本來(lái)回答。

結(jié)論:Nacos 1.x 是拉模型;Nacos 2.x 是推模型

不知道有沒(méi)有讀者好奇 Nacos 為什么這么設(shè)計(jì),我簡(jiǎn)單用一些 QA 快速解答一些可能的疑問(wèn):

Q:為什么 Nacos 1.x 使用了 udp 推送,卻把 Nacos 1.x 定義為拉模型?

A:Nacos 1.x 中 udp 推送主要是為了降低服務(wù)更新延時(shí)而設(shè)計(jì)的,并且在復(fù)雜網(wǎng)絡(luò)部署架構(gòu)中,例如 client 與 server 只能單向訪問(wèn),或者有 SLB 中間介質(zhì)時(shí),udp 就會(huì)失效;且 udp 本身就是不穩(wěn)定的,Nacos 嘗試兩次失敗后就會(huì)放棄推送。所以主要還是在用拉模式來(lái)保障。

Q:為什么 Nacos 1.x 一開(kāi)始不使用 Nacos 2.x 中的架構(gòu),使用 tcp 推送?

A:個(gè)人猜測(cè)是因?yàn)槔P蛯?shí)現(xiàn)起來(lái)簡(jiǎn)單,Nacos 2.x 才引入了 grpc 實(shí)現(xiàn)長(zhǎng)連接

Q:為什么 Nacos 1.x 的服務(wù)發(fā)現(xiàn)使用的是短輪詢,不像配置中心那樣使用長(zhǎng)輪詢?

A:在服務(wù)發(fā)現(xiàn)場(chǎng)景中,服務(wù)端比較在意內(nèi)存消耗,長(zhǎng)輪詢雖然不會(huì)占用線程,但服務(wù)端依舊會(huì) hold 住 request/response,造成不必要的內(nèi)存浪費(fèi)。

一些常見(jiàn)注冊(cè)中心的推拉模型:

Zookeeper:推模型Nacos 1.x:拉模型Nacos 2.x:推模型Eureka:拉模型

好,介紹完了注冊(cè)中心視角的服務(wù)發(fā)現(xiàn)推拉模型了,再回過(guò)頭來(lái)看一個(gè)問(wèn)題:如果使用了 SpringCloud Alibaba + Nacos 2.1 版本,那它的服務(wù)發(fā)現(xiàn)就是走的哪種模型呢?

正確答案:在微服務(wù)框架視角,sca 走的是拉模型這種同步拉取服務(wù)的機(jī)制;在注冊(cè)中心視角,應(yīng)用作為客戶端是使用的推模型在接收服務(wù)變更的推送。

那有一部分比較帥的人可能會(huì)有問(wèn)了,到底什么模型比較好呢?哎,下面就容我對(duì)比下二者。

推拉對(duì)比實(shí)時(shí)性

服務(wù)推送的實(shí)時(shí)性是服務(wù)發(fā)現(xiàn)主要的 SLA 指標(biāo),其指的是當(dāng)服務(wù)地址發(fā)生變化時(shí),客戶端感知到變化的延遲。試想一下,服務(wù)端正在發(fā)布,IP 地址發(fā)生了變化,但是由于地址推送不及時(shí),客戶端過(guò)了 10 分鐘還在調(diào)用舊的服務(wù)地址,這是多么可怕的一件事。

拉模型感知服務(wù)變化的延遲便是短輪詢間隔+拉取服務(wù)的耗時(shí),在 Nacos 中,SLA 為 10s。

推模型感知服務(wù)變化的延遲則為服務(wù)端推送服務(wù)的耗時(shí),在 Nacos 中,SLA 為 1s。

在實(shí)時(shí)性上,推模型有較大優(yōu)勢(shì)。

壓力

拉模型和推模型都會(huì)對(duì)服務(wù)端造成壓力,但是二者的時(shí)機(jī)不同。

拉模型的壓力是固定的,取決于輪詢間隔。推模型的壓力取決于服務(wù)變更的頻率。

用兩個(gè)場(chǎng)景來(lái)做對(duì)比:

常態(tài)化場(chǎng)景。日常運(yùn)行時(shí),服務(wù)列表一般不會(huì)變化,拉模型會(huì)導(dǎo)致不必要的開(kāi)銷(xiāo),對(duì)服務(wù)端造成較大壓力??焐峡煜聢?chǎng)景。機(jī)器快速擴(kuò)容或者縮容,導(dǎo)致服務(wù)地址頻繁變更,推送量會(huì)瞬時(shí)變大,對(duì)服務(wù)端和客戶端造成較大壓力。

針對(duì)快上快下場(chǎng)景,也可以進(jìn)行一系列的優(yōu)化,例如推送合并,增量推送,數(shù)據(jù)分離等等,目前 Nacos 支持了推送合并這一優(yōu)化。

代碼復(fù)雜度

碼齡越大,越發(fā)意識(shí)到代碼復(fù)雜度是一個(gè)非常重要的技術(shù)選型指標(biāo),越簡(jiǎn)單的代碼越容易維護(hù),也具備持久的生命力,架構(gòu)師需要在代碼復(fù)雜度和性能的 trade off 中,找到一個(gè)平衡點(diǎn),不得不承認(rèn),推模型的復(fù)雜度往往要比拉模型高出很多,例如多出了長(zhǎng)連接的狀態(tài)管理這一環(huán)節(jié)。

拉模型完全勝出。

總結(jié)

這篇文章不希望大家陷入到字眼中,判斷某一個(gè)框架或者工具是推或者拉模型,而是希望能介紹清楚服務(wù)發(fā)現(xiàn)中推拉模型的工作流程,方便大家對(duì)這些微服務(wù)框架也好,注冊(cè)中心也好,有一個(gè)更深的理解。

總結(jié)一下,主流的微服務(wù)框架和注冊(cè)中心的服務(wù)發(fā)現(xiàn)機(jī)制中,推模型和拉模型均有使用,具體如何選擇,如何優(yōu)化,可以根據(jù)自身服務(wù)的特點(diǎn),以及服務(wù)的規(guī)模去選擇使用。

在我負(fù)責(zé)的 API 網(wǎng)關(guān)(阿里云 CSB)中,采用了一套獨(dú)立的服務(wù)發(fā)現(xiàn)機(jī)制,同時(shí)支持拉模型和推模型,以適配部分僅支持推模型或者僅支持拉模型的注冊(cè)中心。

關(guān)鍵詞: 使用的是 輪詢間隔

相關(guān)閱讀