自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Dubbo - Go 優(yōu)雅上下線設(shè)計與實踐

開發(fā) 架構(gòu)
在分布式場景下,微服務(wù)進程都是以容器的形式存在,在容器調(diào)度系統(tǒng)例如 k8s 的支持下運行,容器組 Pod 是 K8S 的最小資源單位。

一 背景

1 優(yōu)雅上下線

在分布式場景下,微服務(wù)進程都是以容器的形式存在,在容器調(diào)度系統(tǒng)例如 k8s 的支持下運行,容器組 Pod 是 K8S 的最小資源單位。隨著服務(wù)的迭代和更新,當(dāng)新版本上線后,需要針對線上正在運行的服務(wù)進行替換,從而發(fā)布新版本。

在穩(wěn)定生產(chǎn)的過程中,容器調(diào)度完全由 k8s 管控,微服務(wù)治理由服務(wù)框架或者運維人員進行維護和管理。而在發(fā)布新版本,或者擴縮容的場景下,會終止舊的容器實例,并使用新的容器實例進行替換,對于承載高流量的線上生產(chǎn)環(huán)境,這個替換過程的銜接一但出現(xiàn)問題,將在短時間內(nèi)造成大量的錯誤請求,觸發(fā)報警甚至影響正常業(yè)務(wù)。對于體量較大的廠家,發(fā)布過程出現(xiàn)問題所造成的損失會是巨大的。

因此,優(yōu)雅上下線的訴求被提出。這要求服務(wù)框架在擁有穩(wěn)定服務(wù)調(diào)用能力,傳統(tǒng)服務(wù)治理能力的基礎(chǔ)之上,應(yīng)當(dāng)提供服務(wù)上下線過程中穩(wěn)定的保障,從而減少運維成本,提高應(yīng)用穩(wěn)定性。

2 期望效果

我認(rèn)為,理想狀態(tài)下優(yōu)雅上下線的效果,是在一個承載大量流量的分布式系統(tǒng)內(nèi),所有組件實例都可以隨意地擴容、縮容、滾動更新,在這種情況下需要保證更新過程中穩(wěn)定的 tps (每秒請求數(shù)) 和 rt(請求時延),并且保證不因為上下線造成請求錯誤。再深一步,就是系統(tǒng)的容災(zāi)能力,在一個或多個節(jié)點不可用的情況下,能保證流量的合理調(diào)度,從而盡最大能力減少錯誤請求的出現(xiàn)。

  • Dubbo-go 的優(yōu)雅上下線能力

Dubbo-go 對優(yōu)雅上下線的探究可以追溯到三年前,早在1.5早期版本,Dubbo-go 就已經(jīng)擁有優(yōu)雅下線能力。通過對終止信號量的監(jiān)聽,實現(xiàn)反注冊、端口釋放等善后工作,摘除流量,保證客戶端請求的正確響應(yīng)。

在前一段時間,隨著 Dubbo-go 3.0 的正式發(fā)版,我在一條 proposal issue (dubbo-go issue 1685) [1] 中提到了一些生產(chǎn)用戶比較看重的問題,作為 3.x 版本的發(fā)力方向,并邀請大家談?wù)搶@些方向的看法,其中用戶呼聲最高的特性就是無損上下線的能力,再次感謝社區(qū)的王曉偉同學(xué)的貢獻。

經(jīng)過不斷完善和生產(chǎn)環(huán)境測試,目前 Dubbo-go 已擁有該能力,將在后續(xù)版本中正式與大家見面。

二 Dubbo-go 優(yōu)雅上下線實現(xiàn)思路

優(yōu)雅上下線可以分為三個角度。服務(wù)端的上線,服務(wù)端的下線,和客戶端的容災(zāi)策略。這三個角度,保證了生產(chǎn)實例在正常的發(fā)布迭代中,不出現(xiàn)錯誤請求。

1 客戶端負(fù)載均衡機制

以 Apache 頂級項目 Dubbo 為典范的微服務(wù)架構(gòu)在這里就不進行贅述,在分布式場景下,即使在 K8S 內(nèi),大多數(shù)用戶也會使用第三方注冊組件提供的服務(wù)發(fā)現(xiàn)能力。站在運維成本、穩(wěn)定性、以及分層解耦等角度,除非一些特殊情況,很少會直接使用原生 Service 進行服務(wù)發(fā)現(xiàn)和負(fù)載均衡,因此這些能力成為了微服務(wù)框架的標(biāo)配能力。

熟悉 Dubbo 的同學(xué)一定了解過,Dubbo 支持多種負(fù)載均衡算法,通過可擴展機制集成到框架內(nèi)。Dubbo-go 亦是如此,針對多實例場景下,可以支持多種負(fù)載均衡算法, 例如 RR,隨機數(shù),柔性負(fù)載均衡等等。

下圖摘自 Dubbo 官網(wǎng)

Dubbo-go 的負(fù)載均衡組件

Dubbo-go 服務(wù)框架擁有一套接口級擴展機制,可以根據(jù)配置,加載同一組件接口的不同的實現(xiàn)。其中就有隨機算法負(fù)載均衡策略,它是 Dubbo-go 默認(rèn)的負(fù)載均衡算法。在使用這種算法進行負(fù)載均衡的情況下,所有 provider 都會根據(jù)一定的權(quán)重策略被隨機選擇。所有的provider 實例都有可能成為下游。

這種較為傳統(tǒng)的負(fù)載均衡算法會帶來隱患,即不會因為之前調(diào)用的結(jié)果,影響到后續(xù)調(diào)用過程中對下游實例的選擇。因此如果有部分下游實例處在上下線階段,造成短暫的服務(wù)不可用,所有隨機到該實例的請求均會報錯,在高流量的場景下,會造成巨大損失。

集群重試策略

下圖摘自Dubbo 官網(wǎng)

Dubbo-go 的集群重試策略是從 Dubbo 借鑒過來的,默認(rèn)使用 Failover(故障轉(zhuǎn)移) 邏輯,當(dāng)然也有failback,fallfast 等策略,也是依靠了組件可擴展能力集成進框架內(nèi)。

無論是上面提到的負(fù)載均衡,還是重試邏輯,都是基于“面向切面編程“的思路,構(gòu)造一個抽象化 invoker 的實現(xiàn),從而將流量層層向下游傳遞。對于 Failover 策略,會在負(fù)載均衡選擇下游實例的基礎(chǔ)上,增加對錯誤請求的重試邏輯。一旦請求報錯,會選擇下一個 invoker 進行嘗試,直到請求成功,或超過最大請求次數(shù)為止。

集群重試策略只是增加了嘗試的次數(shù),降低了錯誤率,但本質(zhì)上還是無狀態(tài)的,當(dāng)下游服務(wù)不可用時,會造成災(zāi)難性的后果。

黑名單機制

黑名單機制是我去年實習(xí),師兄安排做的第一個需求,大致思路很簡單,將請求拋錯的 invoker 對應(yīng)實例的 ip 地址加入黑名單,后續(xù)不再將流量導(dǎo)入該實例,等過一段時間,嘗試請求它,如果成功就從黑名單中刪除。

這個機制實現(xiàn)邏輯非常簡單,但本質(zhì)上是將無狀態(tài)負(fù)載均衡算法升級為了有狀態(tài)的。對于一個不可用的下游實例,一次請求會快速將該實例拉黑,其他請求就會識別出黑名單內(nèi)存在該實例,從而避免了其他的流量。

對于這種策略,在黑名單中保留的超時、嘗試從黑名單移除的策略等,這些變量都應(yīng)當(dāng)結(jié)合具體場景考慮,本質(zhì)上就是一個有狀態(tài)的故障轉(zhuǎn)移策略。普適性較強。

P2C 柔性負(fù)載均衡算法

柔性負(fù)載均衡算法是 Dubbo3 生態(tài)的一個重要特性,Dubbo-go 社區(qū)正在攜手 Dubbo 一同探索和實踐。一些讀者應(yīng)該在之前 Dubbo-go 3.0 發(fā)布的文章中看過相關(guān)介紹。簡單來說,是一個有狀態(tài)的,不像黑名單那么“一刀切”的,考慮變量更廣泛、更全面的一種負(fù)載均衡策略,會在 P2C 算法的基礎(chǔ)之上,考慮各個下游實例的請求時延、機器資源性能等變量,通過一定策略來確定哪個下游實例最合適,而具體策略,將結(jié)合具體應(yīng)用場景,交由感興趣的社區(qū)成員來探索,目前是來自字節(jié)的牛學(xué)蔚(github@justxuewei) 在負(fù)責(zé)。

上述諸多負(fù)載均衡策略,都是站在客戶端的角度,盡最大能力讓請求訪問至在健康的實例上。在無損上下線角度來考慮,對于處于發(fā)布階段的不正常工作的實例,可以由客戶端通過合理的算法和策略,例如黑名單機制來過濾掉。

我認(rèn)為客戶端負(fù)載均衡是通用能力,對無損上下線場景的作用只是錦上添花,并不是的核心要素。究其本質(zhì),還是要從被“上下線”的服務(wù)端實例來考慮,從而解決根本問題。

2 服務(wù)端優(yōu)雅上線邏輯

相較于客戶端,服務(wù)端作為服務(wù)的提供者、用戶業(yè)務(wù)邏輯的實體,在我們討論的場景下邏輯較為復(fù)雜。在討論服務(wù)端之前,我們還是先重溫一下基礎(chǔ)的服務(wù)調(diào)用模型。

傳統(tǒng)服務(wù)調(diào)用模型

參考 Dubbo 官網(wǎng)給出的架構(gòu)圖,完成一次服務(wù)調(diào)用,一般需要三個組件:注冊中心,服務(wù)端,客戶端。

  •  服務(wù)端首先需要暴露服務(wù),監(jiān)聽端口,從而具備接受請求的能力。
  •  服務(wù)端將當(dāng)前服務(wù)信息例如ip和端口,注冊在中心化的注冊中心上,例如Nacos。
  •  客戶端訪問注冊中心,獲取要調(diào)用的服務(wù)ip和端口,完成服務(wù)發(fā)現(xiàn)。
  • 服務(wù)調(diào)用,客戶端針對對應(yīng) ip 和端口進行請求。

這簡單的四個步驟,就是 Dubbo-go 優(yōu)雅上下線策略的核心關(guān)注點。正常情況下,四個步驟依此執(zhí)行下來非常順利,邏輯也非常清晰。而放在一個大規(guī)模的生產(chǎn)集群內(nèi),在服務(wù)上下線時就會出現(xiàn)很多值得考量的細(xì)節(jié)。

我們要明白,上下線過程中的錯誤是怎么產(chǎn)生的?我們只需要關(guān)注兩個錯誤,就是:“一個請求被發(fā)送給了一個不健康的實例”,以及“正在處理請求的進程被殺死”,上下線過程中幾乎所有的錯誤都是來自于他們。

服務(wù)優(yōu)雅上線邏輯細(xì)節(jié)

服務(wù)上線時,按照上述的步驟,首先要暴露服務(wù),監(jiān)聽端口。在保證服務(wù)提供者可以正常提供服務(wù)之后,再將自身信息注冊在注冊中心上,從而會有來自客戶端的流量發(fā)送至自己的ip。這個順序一定不能亂,否則將會出現(xiàn)服務(wù)沒有準(zhǔn)備好,就收到了請求的情況,造成錯誤。

上面所說的只是簡單的情況。在真實場景下,我們所說的一個服務(wù)端實例,往往包含一組相互依賴的客戶端和服務(wù)端。在 Dubbo 生態(tài)的配置中,被稱為 Service (服務(wù))和 Reference(引用) 。

舉一個業(yè)務(wù)同學(xué)非常熟悉的例子,在一個服務(wù)函數(shù)內(nèi),會執(zhí)行一些業(yè)務(wù)邏輯,并且針對多個下游服務(wù)發(fā)起調(diào)用,這些下游可能包含數(shù)據(jù)庫、緩存、或者其他服務(wù)提供者,執(zhí)行完畢后,返回獲得的結(jié)果。這對應(yīng)到 Dubbo 生態(tài)的概念中,其實現(xiàn)就是:Service 負(fù)責(zé)監(jiān)聽端口和接受請求,接受的請求會向上層轉(zhuǎn)發(fā)至應(yīng)用業(yè)務(wù)代碼,而開發(fā)者編寫的業(yè)務(wù)代碼會通過客戶端,也就是 Reference,請求下游對象。當(dāng)然這里的下游協(xié)議有多種,我們只考慮 dubbo 協(xié)議棧。

由上面提到這種常見的服務(wù)模型,我們可以認(rèn)為 Service 是 依賴 Reference 的,一個 Service 的所有 Reference 必須都正常工作后,當(dāng)前 Service 才能正確接受來自上游的服務(wù)。這也就推導(dǎo)出了,Service 應(yīng)該在 Reference 之后加載,當(dāng)加載完成所有 Reference 后,保證這些客戶端都可用,再加載 Service,暴露能工作的服務(wù),最后再注冊到注冊中心,喊上游來調(diào)用。如果反過來,Service 準(zhǔn)備好了而 Reference 沒有,則會造成請求錯誤。

因此,服務(wù)上線邏輯是 Consumer 加載 -> Provider 加載 -> Registry 服務(wù)注冊。

有讀者可能會疑惑,如果 Consumer 依賴當(dāng)前 實例自己的 Provider 怎么辦,Dubbo 的實現(xiàn)是可以不走網(wǎng)絡(luò)直接發(fā)起函數(shù)調(diào)用,Go 這邊也可以按照這種思路來處理,不過實現(xiàn)還待開發(fā)。這種情況相對較少,更多的還是上述大家熟悉的情況。

3 服務(wù)端優(yōu)雅下線邏輯

相比于服務(wù)上線,服務(wù)下線需要考慮的點更多一些。我們重新回到上一節(jié)提到的服務(wù)調(diào)用模型四步驟:

  • 服務(wù)端首先需要暴露服務(wù),監(jiān)聽端口,從而具備接受請求的能力。
  •  服務(wù)端將當(dāng)前服務(wù)信息例如ip和端口,注冊在中心化的注冊中心上,例如Nacos。
  • 客戶端訪問注冊中心,獲取要調(diào)用的服務(wù)ip和端口,完成服務(wù)發(fā)現(xiàn)。
  • 服務(wù)調(diào)用,客戶端針對對應(yīng) ip 和端口進行請求。

如果一個服務(wù)將要下線,則一定要把相關(guān)的善后工作做好。現(xiàn)在的線上情況是這樣:客戶端正在源源不斷地給當(dāng)前實例請求,如果這個時候直接結(jié)束當(dāng)前進程,一方面,將在一瞬間會有大量的 tcp 建立連接失敗,只能寄希望于第一章提到的客戶端負(fù)載均衡策略了;另一方面,有大量正在處理的請求被強制丟棄。這很不優(yōu)雅!所以當(dāng)實例知道自己要被終止后,首先要做的就是告訴客戶端:“我這個服務(wù)要被終止了,快把流量切走”。這體現(xiàn)在實現(xiàn)中,就是把自身的服務(wù)信息從注冊中心刪除。客戶端拿不到當(dāng)前實例IP后,不會再將請求發(fā)過來,這個時候再終止進程才優(yōu)雅。

上面所說的,也只是簡單的情況。在真實場景之下,客戶端可能并沒有那么快地把流量切走,并且當(dāng)前服務(wù)手里還有一大批正在處理的任務(wù),如果貿(mào)然終止進程,可以形象地理解成將端在手里的一盆水撒了一地。

有了這些鋪墊,我們來詳細(xì)地聊一聊服務(wù)下線的步驟。

優(yōu)雅下線的使用和觸發(fā)

上面的小故事里面提到,進程首先要知道自己“要被終止”了,從而觸發(fā)優(yōu)雅下線邏輯。這個消息可以是信號量,當(dāng) k8s 要終止容器進程,會由 kubelet 向進程發(fā)送 SIGTERM 信號量。在 Dubbo-go 框架內(nèi)預(yù)置了一系列終止信號量的監(jiān)聽邏輯,從而在收到終止信號后,依然能由進程自己來控制自己的行動,也就是執(zhí)行優(yōu)雅下線邏輯。

不過有些應(yīng)用會自己監(jiān)聽 SIGTERM 信號處理下線邏輯。比如,關(guān)閉 db 連接、清理緩存等,尤其是充當(dāng)接入層的網(wǎng)關(guān)類型應(yīng)用,web 容器和 RPC 容器同時存在。這個時候先關(guān)閉 web 容器還是先關(guān)閉 RPC 容器就顯得尤其最重要。所以 Dubbo-go 允許用戶通過配置internal.signal來控制 signal信號監(jiān)聽的時機,并通過 graceful_shutdown.BeforeShutdown()在合適的時機優(yōu)雅關(guān)閉 rpc 容器。同樣,Dubbo-go 也允許用戶在配置中選擇是否啟用新號監(jiān)聽。

反注冊

上面提到,服務(wù)端需要告訴客戶端自己要終止了,這個過程就是通過注冊中心進行反注冊(Unregister)。常見的服務(wù)注冊中間件,例如 Nacos 、Zookeeper、Polaris 等都會支持服務(wù)反注冊,并將刪除動作以事件的形式通知給上游客戶端。客戶端一定是隨時保持對注冊中心的監(jiān)聽的,能否成功請求與否,很大程度取決于來自注冊中心的消息有沒有被客戶端及時監(jiān)聽和作出響應(yīng)。

在 Dubbo-go 的實現(xiàn)中,客戶端會第一時間拿到刪除事件,將該實例對應(yīng) invoker 從緩存中刪除。從而保證后續(xù)的請求不會再流向該 invoker 對應(yīng)的下游。

反注冊過程雖然很快,但畢竟是跨越三個組件之間的事情,無法保證瞬間完成。因此便有了下一步:等待客戶端更新。

和后面步驟有些關(guān)聯(lián)的是,在當(dāng)前階段只進行反注冊,而不能進行反訂閱,因為在優(yōu)雅下線執(zhí)行的過程中,還會有來自自身客戶端向下游的請求,如果反訂閱,將會無法接收到下游的更新信息,可能導(dǎo)致錯誤。

等待客戶端更新

服務(wù)端在優(yōu)雅下線邏輯的反注冊執(zhí)行后,不能快速殺死當(dāng)前服務(wù),而會阻塞當(dāng)前優(yōu)雅下線邏輯一小段時間,這段時間由開發(fā)人員配置,默認(rèn)3s,應(yīng)該大于從反注冊到客戶端刪除緩存的時間。

經(jīng)過了這段等待更新的時間,服務(wù)端就可以認(rèn)為,客戶端已經(jīng)沒有新的請求發(fā)送過來了,便可以亮起紅燈,邏輯是拒絕一切新的請求。

等待來自上游的請求完成

這里還是不能殺死當(dāng)前進程,這就像自己的手里還端著那盆水,之前做的只是離開了注水的水龍頭,但并沒有把盆里的水倒干凈。因此要做的還是等待,等待當(dāng)前實例正在處理的,所有來自上游的請求都完成。

服務(wù)端會在一層 filter 維護一個并發(fā)安全的計數(shù)器,記錄所有進入當(dāng)前實例但未返回的請求數(shù)目。優(yōu)雅下線邏輯會在這時輪詢計數(shù)器,一旦計數(shù)器歸零,視為再也沒有來自上游的請求了,手里端著的來自上游的水也就倒干凈了。

等待自己發(fā)出的請求得到響應(yīng)

走到這一步,整條鏈路中,自己上游的請求都移除干凈了。但自己往下游發(fā)出的請求還是個未知數(shù),此時此刻也許有大量由當(dāng)前實例發(fā)出,但未得到響應(yīng)的請求。如果這時貿(mào)然終止當(dāng)前進程,會造成不可預(yù)知的問題。

因此還是類似于上述的邏輯,服務(wù)在客戶端 filter 維護一個線程安全的計數(shù)器,由優(yōu)雅下線邏輯來輪詢,等待所有請求都已經(jīng)返回,計數(shù)器歸零,方可完成這一階段的等待。

如果當(dāng)前實例存在一個客戶端,源源不斷地主動向下游發(fā)起請求,計數(shù)器可能一直不歸零,那就要依靠這一階段的超時配置,來強行結(jié)束這一階段了。

銷毀協(xié)議,釋放端口

這時,就可以放心大膽地做最后的工作了,銷毀協(xié)議、關(guān)閉監(jiān)聽,釋放端口,反訂閱注冊中心。用戶可能希望在下線邏輯徹底結(jié)束后,端口釋放后,執(zhí)行一些自己的邏輯,所以可以提供給開發(fā)者一個回調(diào)接口。

三 優(yōu)雅上下線的效果

按照上述的介紹,我們在集群內(nèi)進行了壓測實驗和模擬上下線實驗。

使用一個 client 實例,5個 proxy 實例,5個 provider 實例,請求鏈路為:

client -> proxy -> provider

因為資源問題,我們選擇讓客戶端保證 5000 tps 的壓力,通過 dubbo-go 的 prometheus 可視化接口暴露出成功率和錯誤請求計數(shù),之后針對鏈路中游的 proxy 實例和鏈路下游的 provider 實例進行滾動發(fā)布、擴容、縮容、實例刪除等一系列實驗,模擬生產(chǎn)發(fā)布過程。

期間我記錄了很多數(shù)據(jù),可以把一個比較明顯的對比展示出來。

不使用優(yōu)雅上下線邏輯:更新時成功率大幅降低,錯誤數(shù)目持續(xù)升高,客戶端被迫重啟。

優(yōu)雅上下線優(yōu)化后:無錯誤請求,成功率保持在100%

四 Dubbo-go 在服務(wù)治理能力的展望

Dubbo-go v3.0 從去年年底正式發(fā)版,到現(xiàn)在過了一個多月左右的時間,3.0 發(fā)布對我們而言不是大功告成,而是踏上了展望未來的一個新階梯。我們即將發(fā)布 3.1 版本,這一版本將擁有優(yōu)雅上下線能力。

在 3.0 籌備階段,我有想過如果一款服務(wù)框架從傳統(tǒng)設(shè)計走向未來,需要一步一步走下來,需要有多個必經(jīng)之路:從最基本的用戶友好性支持、配置重構(gòu)、易用性、集成測試、文檔建設(shè);到實現(xiàn)傳輸協(xié)議(Dubbo3) Triple-go 的跨生態(tài)、穩(wěn)定、高性能、可擴展、生產(chǎn)可用;再到我們 3.0 發(fā)版之后的 服務(wù)治理能力、運維能力、可視化能力、穩(wěn)定性,其中就包括了優(yōu)雅上下線、流量治理、proxyless;再到形成生態(tài),跨生態(tài)集成。這樣走,才能一步一個腳印,不斷積累,不斷迭代。

運維能力和服務(wù)治理的充實和優(yōu)化,將作為后續(xù)版本的重要 Feature ,我們將會進一步完善流量治理、路由、Proxyless Service Mesh、還有文中提到的柔性負(fù)載均衡算法等方面,這些都是今年社區(qū)工作的重點。

Dubbo-go 生態(tài),同開發(fā)者同在!

[1] https://github.com/apache/dubbo-go/issues/1685


責(zé)任編輯:武曉燕 來源: 阿里技術(shù)
相關(guān)推薦

2021-04-20 10:20:27

Dubbo網(wǎng)絡(luò)通信通信協(xié)議

2023-07-14 21:34:40

JVM上下線線程

2024-10-14 08:46:50

Controller開發(fā)代碼

2022-11-16 09:27:58

flexbox左右布局均分布局

2022-08-22 13:29:42

微服務(wù)應(yīng)用Java

2018-04-09 14:26:06

Go語法實踐

2023-09-21 22:02:22

Go語言高級特性

2023-02-28 08:57:06

Spring上下線緩存

2023-06-02 18:37:14

Dubbo異步化接口

2021-06-04 10:52:51

kubernetes場景容器

2025-01-13 06:00:00

Go語言gRPC

2025-04-01 00:06:50

JavaK8sSpring

2021-07-07 07:44:20

微服務(wù)Nacos緩存

2022-06-22 06:49:39

Hertz開源HTTP 框架

2021-02-05 18:22:51

GoC剖析

2023-10-09 18:35:37

得物Redis架構(gòu)

2023-05-17 00:15:11

TCCXA模式

2024-12-03 12:02:05

2024-03-14 09:19:49

2024-02-19 08:12:15

DIKW 模型指標(biāo)系統(tǒng)數(shù)據(jù)倉庫
點贊
收藏

51CTO技術(shù)棧公眾號