日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) >

SpringCloud 应用在 Kubernetes 上的最佳实践 — 线上发布(优雅上下线)

發(fā)布時(shí)間:2025/3/20 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 SpringCloud 应用在 Kubernetes 上的最佳实践 — 线上发布(优雅上下线) 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

作者 | 驕龍

導(dǎo)讀:本篇是《SpringCloud 應(yīng)用在 Kubernetes 上的最佳實(shí)踐》系列文章的第八篇,主要介紹了如何做到流量的無(wú)損上/下線。更多相關(guān)文章閱讀可查看文末。

前言

上篇我們講的是發(fā)布回滾過(guò)程,尤其是在 Kubernetes 的回滾過(guò)程中,原生有提供 Rollout 到上一個(gè)版本的能力,能保證我們?cè)诎l(fā)布過(guò)程中遇到問(wèn)題時(shí)快速回退的能力。然而在每一次上線的過(guò)程中,我們最難處理的就是正在運(yùn)行中的流量,如何做到流量的無(wú)損上/下線,是一個(gè)系統(tǒng)能保證 SLA 的關(guān)鍵。

介紹

什么是優(yōu)雅上線?就如下面這個(gè)房子一樣,未建好的房子,人住進(jìn)去會(huì)有危險(xiǎn),房子應(yīng)該建好,裝修好,人才能住進(jìn)去。

那么如何做到優(yōu)雅上線呢?我們先來(lái)看一個(gè) WEB 應(yīng)用的加載過(guò)程,就像上面造房子一樣,是個(gè)漫長(zhǎng)的過(guò)程:

應(yīng)用的加載是漫長(zhǎng)的,在加載過(guò)程,服務(wù)是不可預(yù)期的;如過(guò)早地打開(kāi) Socket 監(jiān)聽(tīng),則客戶端可能感受到漫長(zhǎng)的等待;如果數(shù)據(jù)庫(kù)、消息隊(duì)列、REDIS 客戶端未完成初始化,則服務(wù)可能因缺少關(guān)鍵的底層服務(wù)而異常。

所以在應(yīng)用準(zhǔn)備完成后,才接入服務(wù),即做到優(yōu)雅上線。當(dāng)然應(yīng)用上線后,也可能因如數(shù)據(jù)庫(kù)斷連等情況引起服務(wù)不可用;或是準(zhǔn)備完成了,但在上線前又發(fā)生數(shù)據(jù)庫(kù)斷連,導(dǎo)致服務(wù)異常。為了簡(jiǎn)化問(wèn)題,后面兩種情況作為一個(gè)應(yīng)用自愈的問(wèn)題來(lái)看待。

什么是優(yōu)雅下線?與建房子相反就像下面的危房一樣,人住在里面很危險(xiǎn),人應(yīng)該先從房子出來(lái),然后推掉房子。

那么如何做到優(yōu)雅下線呢?我們先來(lái)看一個(gè) WEB 應(yīng)用的停止過(guò)程:

所以關(guān)閉服務(wù)接入(轉(zhuǎn)移服務(wù)接入),完成正在處理的服務(wù),清理自身占用的資源后退出即做到優(yōu)雅下線。

如何實(shí)現(xiàn)優(yōu)雅下線

從上面介紹看,似乎不難,但事實(shí)上,很少有系統(tǒng)真正實(shí)現(xiàn)了優(yōu)雅上下線。因?yàn)檐浖旧碛蔁o(wú)數(shù)各種各樣相互依賴的結(jié)構(gòu)組成,每個(gè)結(jié)構(gòu)都使用一些資源,污染一些資源;通常在設(shè)計(jì)之初優(yōu)雅上下線也不被作為優(yōu)先考慮的需求,所以對(duì)于下線的過(guò)程,通常都沒(méi)被充分考慮,在設(shè)計(jì)上通常要求:

  • 結(jié)構(gòu)(組件)應(yīng)形成層次關(guān)系;
  • 用戶線程需能收到停止信號(hào)并響應(yīng)退出;否則使用 daemon 線程;
  • 結(jié)構(gòu)應(yīng)按依賴關(guān)系自下向上構(gòu)建:就像建房子一樣,自內(nèi)向外構(gòu)建而成;
  • 結(jié)構(gòu)應(yīng)按依賴關(guān)系自上向下銷(xiāo)毀:就像拆房子一樣,自外向內(nèi)拆解。

優(yōu)雅下線實(shí)現(xiàn)路徑

大致分為一個(gè)完整的過(guò)程,需要經(jīng)歷一下四個(gè)關(guān)鍵的節(jié)點(diǎn),如下圖:

  • 接收信號(hào):停止信號(hào)可能從進(jìn)程內(nèi)部觸發(fā)(比如 Crash 場(chǎng)景),如果自退出的話基本上無(wú)法保證優(yōu)雅下線;所以能保證優(yōu)雅下線的前提就是需要正確處理來(lái)自進(jìn)程外部的信號(hào);

  • 停止流量接收:由于在停止之前,我們會(huì)有一些正在處理的請(qǐng)求,貿(mào)然退出會(huì)對(duì)這些請(qǐng)求產(chǎn)生損耗。但是在這段時(shí)間之內(nèi)我們絕不能再接收新的業(yè)務(wù)請(qǐng)求,如果這是一個(gè)后臺(tái)任務(wù)型(消息消費(fèi)型或任務(wù)調(diào)度型)的程序,也要停止接收新的消息和任務(wù)。對(duì)于一個(gè)普通的 WEB 場(chǎng)景,這一塊不同的場(chǎng)景實(shí)現(xiàn)的方式也會(huì)不一樣,下面的 Srping Cloud 應(yīng)用的下線流程會(huì)詳細(xì)講解;

  • 銷(xiāo)毀資源:常見(jiàn)的是一些系統(tǒng)資源,也包括一些緩存、鎖的清理、同時(shí)也包括線程池、關(guān)閉阻塞中的的 IO 操作,等到我們這些服務(wù)器資源銷(xiāo)毀之后,就可以通知主線程退出。

Spring Cloud 應(yīng)用

一個(gè) Spring boot 應(yīng)用通常由應(yīng)用本身和一系列的 Starter 組成,對(duì)于 Spring boot 體系,需要了解如下核心概念:

  • Starter:提供一系列的模塊,由 Spring boot 核心通過(guò) auto-configuration 機(jī)制加載;

  • Bean:一切皆 Bean,starter 模塊的加載產(chǎn)生各種 Bean;

  • Context:Bean 的容器,容器擁有生命周期,Bean 需要感知生命周期事件;

  • LifeCycle:生命周期管理接口;

  • ApplicationEvent:模塊之間,模塊與容器之間,通過(guò)發(fā)送或監(jiān)聽(tīng)事件來(lái)達(dá)到互相通訊的目的。

所以對(duì)于應(yīng)用上下線這個(gè)主題,我們應(yīng)盡可能利用其豐富的原生事件機(jī)制,Spring Cloud 中內(nèi)置的 Starter 機(jī)制針對(duì)整個(gè)生命周期管理的過(guò)程有了很好的封裝。

Spring Cloud 應(yīng)用的優(yōu)雅上線

Spring Cloud 啟動(dòng)過(guò)程觸發(fā)回調(diào)及事件如下,詳細(xì)介紹見(jiàn) application-events-and-listeners,簡(jiǎn)單羅列如下:

Spring 自身及其組件大量基于這些事件構(gòu)建,如響應(yīng) WebServerInitializedEvent 事件向服務(wù)注冊(cè)中心注冊(cè)服務(wù),對(duì)于應(yīng)用一般可利用:

  • InitializingBean or @PostConstruct:在 Bean 裝配完后,被回調(diào),如完成數(shù)據(jù)源初始化連接;

  • ApplicationReadyEvent、ApplicationRunner、CommandLineRunner:如開(kāi)始監(jiān)聽(tīng)消息隊(duì)列,處理消息;注冊(cè)到SLB等;先通過(guò)配置禁用服務(wù)的自動(dòng)注冊(cè),在這里做手動(dòng)服務(wù)注冊(cè)。

Spring Cloud 應(yīng)用的優(yōu)雅下線

Spring Cloud 本身可以作為一個(gè)應(yīng)用單獨(dú)存在,也可以是依附在一個(gè)微服務(wù)集群中,同時(shí)還能作為反向代理架構(gòu)中的一個(gè)網(wǎng)關(guān)。不同的場(chǎng)景,需要用到的方法也不一樣,我們就常用的三種場(chǎng)景針對(duì)性的加以說(shuō)明。

場(chǎng)景一:直接訪問(wèn) WEB 服務(wù)

客戶端直接訪問(wèn) WEB 應(yīng)用,在這個(gè)用例下,優(yōu)雅下線需要做的事情有:

  • 正在處理的請(qǐng)求完成處理
  • 應(yīng)用自身完成安全下線并正常退出
  • 客戶端感知到連接異常

Spring-boot 從 2.3 開(kāi)始內(nèi)置了 WEB 應(yīng)用優(yōu)雅下線的能力,需配置如下,具體介紹參見(jiàn) graceful-shutdown。

server.shutdown=graceful spring.lifecycle.timeout-per-shutdown-phase=20s

其實(shí)現(xiàn)方式:

  • 首先關(guān)閉 socket 監(jiān)聽(tīng),等待正在處理的所有請(qǐng)求完成:具體可見(jiàn) WebServerGracefulShutdownLifecycle,通過(guò) getPhase 返回最大值,達(dá)到早于 WEB 容器關(guān)閉執(zhí)行的目的;

  • 然后觸發(fā) WEB 容器關(guān)閉:具體可見(jiàn) WebServerStartStopLifecycle。

但其實(shí),對(duì)于未被 WEB 容器完全接收的請(qǐng)求,客戶端仍會(huì)收到連接被重置的異常,只是這個(gè)時(shí)間窗口極小。該需求從提出到實(shí)現(xiàn)的時(shí)間跨度較長(zhǎng),感興趣的可參見(jiàn) github 上的討論。

場(chǎng)景二:經(jīng)由反向代理的服務(wù)優(yōu)雅下線

因?yàn)閷?shí)例前面還有反向代理,相比上個(gè)場(chǎng)景,需要新增“反向代理下線”這個(gè)處理流程。即若應(yīng)用已經(jīng)下線,但反向代理未摘除該應(yīng)用實(shí)例時(shí)客戶端將感知到失敗。一般采取的策略有:

  • 反向代理支持失敗轉(zhuǎn)移到其它應(yīng)用實(shí)例;
  • 在關(guān)閉應(yīng)用前,如將健康探測(cè)接口返回不健康以及等待足夠的超時(shí),讓反向代理感知并摘除實(shí)例的路由信息。

對(duì)于仍在使用 2.3 以前版本的 Spring Cloud 應(yīng)用,可參見(jiàn)一個(gè)方案,實(shí)現(xiàn)方式:

  • 使用自身的 shutdownHook 替換 Spring 的 shutdownHook;
  • 先改變 health 狀態(tài),等待一段時(shí)間,讓反向代理感知并摘除實(shí)例的路由信息。

場(chǎng)景三:在微服務(wù)集群中下線單個(gè)服務(wù)

在優(yōu)雅關(guān)閉 Spring Cloud 應(yīng)用自身之前,我們除了完成場(chǎng)景一之中的目標(biāo)之外,還需要將自身節(jié)點(diǎn)從注冊(cè)中心中下線。目前在 Spring Cloud 中針對(duì)注冊(cè)中心下線的場(chǎng)景暫未提供開(kāi)箱即用的方法,下面介紹兩種可能的實(shí)現(xiàn)方案:

方案 1:先通過(guò)腳本、或通過(guò)監(jiān)聽(tīng) ContextClosedEvent 反注冊(cè)服務(wù)摘除流量;等待足夠時(shí)間,如使用 ribbon 負(fù)載均衡器,需要長(zhǎng)于配置的刷新時(shí)間;對(duì)于基于 HTTP 的服務(wù),若 Spring Cloud 版本小于 2.3,則時(shí)間需加上預(yù)期的請(qǐng)求處理時(shí)間;

方案 2:客戶端支持連接感知重試,如重試,實(shí)現(xiàn)方案可參考Spring-retry,針對(duì)連接異常 RemoteConnectFailureException 做重試。

針對(duì) Eureka 中的場(chǎng)景,有一個(gè)很好的參考的例子,請(qǐng)參見(jiàn):https://home1-oss.github.io/home1-oss-gitbook/release/docs/oss-eureka/GRACEFUL_SHUTDOWN.html

Kubernetes 下的機(jī)制

Kubernetes 中針對(duì)應(yīng)用的的管控提供了豐富的手段,正常的情況它提供了應(yīng)用生命周期中的靈活擴(kuò)展點(diǎn),同時(shí)也支持自己擴(kuò)展它的 Operator 自定義上下線的流程。

拋開(kāi)實(shí)現(xiàn)成本,以下線的情況來(lái)說(shuō),一個(gè) Kubernetes 應(yīng)用實(shí)例下線之前,管控程序會(huì)向 POD 發(fā)送一個(gè) SIGTERM 的信號(hào),應(yīng)用響應(yīng)時(shí)除了額外響應(yīng)這一個(gè)信號(hào)之外,還能觸發(fā)一段自定義的 PreStop 的掛在腳本,代碼樣例如下:

yaml lifecycle: preStop: exec: command: - sh- -c- "sleep 5"

上面的例子一點(diǎn)特殊說(shuō)明:因服務(wù)控制面刷新與 POD 收到 SIGTERM 同時(shí)發(fā)生,所以這里通過(guò) sleep 5 讓服務(wù)控制面先完成刷新,應(yīng)用進(jìn)程再響應(yīng) SIGTERM 信號(hào)。

Spring Cloud 與 Kubernetes 的結(jié)合

Kubernetes 會(huì)根據(jù)健康檢查的情況來(lái)更新服務(wù)(Service)列表,其中如果 Liveness 失敗,則會(huì)觸發(fā)容器重建,這是一個(gè)相對(duì)很重的操作;若 Readiness 失敗,則 Kubenetes 則默認(rèn)不會(huì)將路由服務(wù)流量到相應(yīng)的容器;基于這一機(jī)理,Spring Cloud 2.3 開(kāi)始,也做了原生的的支持,具體參見(jiàn) liveness-and-readiness-probes-with-Spring-boot,這些健康檢查端點(diǎn)可對(duì)接 Kubnetes 相應(yīng)的 probe:

  • /actuator/health/liveness
  • /actuator/health/readiness

同時(shí),Spring Boot 內(nèi)置了相應(yīng)的 API、事件、Health Check 監(jiān)控,部分代碼/配置片段如下:

java // Available as a component in the application context ApplicationAvailability availability; LivenessState livenessState = availabilityProvider.getLivenessState(); ReadinessState readinessState = availabilityProvider.getReadinessState(); .... // 對(duì)于應(yīng)用,也可以通過(guò)API,發(fā)布相應(yīng)的事件,來(lái)改變應(yīng)用的狀態(tài) AvailabilityChangeEvent.publish(this.eventPublisher, ex, LivenessState.BROKEN); // 同時(shí),應(yīng)用監(jiān)控也可影響這健康狀態(tài),將監(jiān)控與健康關(guān)聯(lián),在K8S體系下,可以實(shí)現(xiàn)如離群摘除,應(yīng)用自愈的能力 // application.properties management.endpoint.health.group.liveness.include=livenessProbe,cacheCheck

回到 Spring Cloud 應(yīng)用?在微服務(wù)集群中下線單個(gè)服務(wù)?的章節(jié)中,我們的應(yīng)用如果跑在 Kuberntes 中,如果我們使用了原生的 Kubernetes 機(jī)制去管理應(yīng)用生命周期的話,只需要發(fā)布一個(gè)應(yīng)用事件 (LivenessState.BROKEN) 即可實(shí)現(xiàn)優(yōu)雅下線的能力。

EDAS提供內(nèi)置的優(yōu)雅上下線能力

通過(guò)上面兩部分了解了 Spring Cloud 和 K8s 中的機(jī)制,EDAS 基于原生的機(jī)制,衍生出來(lái)了自己的方法,除了最大化利用這些能力:主動(dòng)更新 Liveness、Readiness、Ribbon 服務(wù)列表之外,我們還提供了無(wú)代碼侵入的開(kāi)箱即用的能力,列舉如下:

  • 無(wú)損下線 Spring Cloud 應(yīng)用
  • 無(wú)損下線 dubbo 應(yīng)用
  • 使用離群實(shí)例摘除保障 Spring Cloud 應(yīng)用的可用性
  • 使用離群實(shí)例摘除保障 Dubbo 應(yīng)用的可用性

后續(xù)

這一章節(jié)之后,和發(fā)布相關(guān)的內(nèi)容都已經(jīng)更新完畢,下一章節(jié)我們要開(kāi)始高可用部分的能力,高可用也是系統(tǒng)保障 SLA 的關(guān)鍵部分,簡(jiǎn)單的理解是流量洪峰到來(lái)如何保證系統(tǒng)不會(huì)受到影響?當(dāng)然我們還有一部分要達(dá)成的是洪峰退去之后資源是否存在浪費(fèi)?敬請(qǐng)期待 …

相關(guān)文章推薦:

  • 《SpringCloud 應(yīng)用在 Kubernetes 上的最佳實(shí)踐 —— 開(kāi)發(fā)篇》

  • 《SpringCloud 應(yīng)用在 Kubernetes 上的最佳實(shí)踐 — 部署篇(開(kāi)發(fā)部署)》

  • 《SpringCloud 應(yīng)用在 Kubernetes 上的最佳實(shí)踐 — 部署篇(工具部署)》

  • 《SpringCloud 應(yīng)用在 Kubernetes 上的最佳實(shí)踐 — 線上發(fā)布(可灰度)》

  • 《SpringCloud 應(yīng)用在 Kubernetes 上的最佳實(shí)踐 — 診斷(線上聯(lián)調(diào))》

  • 《SpringCloud 應(yīng)用在 Kubernetes 上的最佳實(shí)踐 — 線上發(fā)布(可監(jiān)控)》

  • 《SpringCloud 應(yīng)用在 Kubernetes 上的最佳實(shí)踐 — 線上發(fā)布(可回滾)》

“阿里巴巴云原生關(guān)注微服務(wù)、Serverless、容器、Service Mesh 等技術(shù)領(lǐng)域、聚焦云原生流行技術(shù)趨勢(shì)、云原生大規(guī)模的落地實(shí)踐,做最懂云原生開(kāi)發(fā)者的公眾號(hào)。”

總結(jié)

以上是生活随笔為你收集整理的SpringCloud 应用在 Kubernetes 上的最佳实践 — 线上发布(优雅上下线)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。