當前位置:網站首頁>阿裏億級高可用系統架構如何搭建?(中篇)

阿裏億級高可用系統架構如何搭建?(中篇)

2022-01-27 10:56:56 技術領導力

來源:阿裏巴巴中間件

01

前言

Aliware

上一篇阿裏億級高可用系統架構如何搭建?(上篇)》 是我們基於下圖,講解了流量解析與流量接入兩個比特置做到流量無損的一些關鍵技術,這一篇我們主要從流量服務的維度,詳細聊聊正式服務過程中會影響線上流量的一些技術細節。

f6d8903a07652d5e56324f8296fad921.png

02

服務

Aliware

最近我們分析了某大型互聯網公司最近一年的線上故障原因,其中,產品自身質量問題(設計不合理、BUG 等)占比最高,為 37%;由於線上發布、產品和配置變更引起的問題占比 36%;最後是依賴服務的高可用類的問題如:設備故障,上下遊的依賴服務出現問題或者資源瓶頸等。

b76b561ef38c599b2138e8471c2aa965.png

基於左側的原因分析可以看出,如何治理好變更、產品質量、和高可用類的問題,是服務如何做到流量無損的關鍵所在。我們把這個幾點原因結合應用的生命周期劃分成為了幾個關鍵階段:

  • 應用變更態:當我們的服務(應用)進行版本發布、配置變更的整個過程中,我們需要有確切的手段做保護。

  • 運行服務態:當我們的變更完畢後,一開始是一個 “冷”的狀態,如何在正常流量甚至超常規流量到來之前的,讓系統平穩度過?

  • 高可用依賴態:當我們服務的某些節點出現問題,或者我們外部的依賴(如 其他微服務、DB、緩存)等出現瓶頸時,是否有相對應的辦法?

為了從容地應對以上這些場景,我們將分別列舉相關例子來探討相應的解决方案。


01

變更態:應用優雅下線

應用變更時有一步,是需要將原有的應用停止。而在生產環境中的在線應用停止之前,需要將服務流量的服務下線。我們常說的流量主要有兩種:

1)同步調用的流量,如:RPC、HTTP 請求等;

2)另外一種是异步流量,如:消息消費、後臺任務調度等。

以上兩種流量,如果在服務端還存在未處理完的請求時將進程停止,都會造成流量損失。要想解决這一種情况,通常情况需要分兩步進行:

1)將現有節點在相應的注册服務中摘除,場景有:將 RPC 服務在注册中心的節點中摘除、將 HTTP 服務在上遊的負載均衡處摘除、將後臺任務(消息消費等)的線程池嘗試關閉,不再進行新的消費或服務。

2)停頓一段時間(依據業務情况而定),確保進程中已經進來的流量能得到很好的處理之後,再將進程關閉。

02

變更態:應用調度

變更過程中另外一個動作就是選擇資源(機器或容器)之後發起一次部署,如何選擇資源就是我們通常意義上理解的【調度】,如果是傳統的物理機或者調度能力欠缺的虛擬機的情况,調度這一層沒有太多的發揮空間,因為他的資源基本上都是固定的;但是容器技術(尤其後來的 Kubernetes 技術的普及)的出現除了給交付領域帶來了諸多的變化之外,他也給調度領域帶來了的不一樣的故事,即他從傳統的規劃資源分配引領到了靈活調度的時代。

在 Kubernetes 中,默認可以根據應用使用的資源(CPU、內存、磁盤等)信息,來選擇一個最為合適的節點進行調度。如果我們更進一步,也可以根據自身應用的流量特征定制一個調度器,比如盡量讓流量大的應用不聚集在相同的節點上,這樣就能避免因為搶占帶寬而造成的流量損失

03

變更態:應用優雅上線

當應用調度到了相應的資源之後,接下來是部署和啟動應用。和應用停止的場景類似,應用在完全初始化完成之前,我們的節點很可能已經被注册,後臺任務的線程池也很可能開始啟動了。此時上遊服務(如 SLB 開始路由、消息開始消費)就會有流量調度進來。但是在應用被完全初始化完成之前,流量的服務質量是無法得到保證的,比如一個 Java 應用啟動之後的前幾次請求,基本上是一個“卡頓”的狀態。

如何解决這個問題呢?和應用的優雅下線動作序列相反,我們需要有意識的將服務注册、後臺任務線程池、消息消費者線程池的初始化動作滯後。要確保等到應用完全初始化之後再進行。如果有外置的負載均衡路由流量的場景,還需要應用部署的自動化工具進行相應的配合。

04

變更態:應用服務預熱

系統完成上線之後,有時如果遇到流量突增,可能會令系統水比特瞬間昇高進而導致崩潰。典型場景如大促時的零點,洪峰湧入時,應用實例會瞬間進入大量的流量,這些流量會觸發諸如 JIT 編譯、框架初始化、類加載等底層資源優化的問題,這些優化會在短時間之內給系統造成高負載的問題,進而造成業務流量損失。為了解决這個問題,我們需要控制流量緩慢增加,通過開啟類加載器並行類加載,框架提前初始化,日志异步化等方式提昇剛啟動應用的業務容量,從而實現大流量場景下的擴容、上線等操作的流量無損

05

變更態:Kubernetes 服務結合

從 2020 年開始,我們看到一個明顯的趨勢就是 Spring Cloud  + Kubernetes 已經成為了微服務體系中最流行的配搭。而在一個基於 Kubernetes 構建的微服務體系中, 如何將微服務體系和 Kubernetes 進行有效的結合是很有挑戰的一個點,Kubernetes 中的 Pod 生命周期管理本身就提供了兩個探測點:

  • RreadinessProbe,用於探測一個 Pod 是否就緒接受流量,探測失敗將會在 Kubernetes Service 中摘取該節點,且該節點的狀態為 NotReady 。

  • LivenessProbe,用於探測 Pod 是否健康,如探測失敗將會重啟 Pod。

如果我們的應用沒有配置 readinessProbe ,默認只會檢查容器內進程是否啟動運行,而對於進程中運行的業務是否真的健康是很難考量的。在發布的過程中,如果我們使用的是滾動發布策略,那麼當 Kubernetes 發現新起的 Pod 中的業務進程已經啟動了,Kubernetes 就會開始銷毀老版本的 Pod,看起來這個過程是沒有什麼問題的。但我們仔細想一下,“新起的 pod 中的業務進程已經啟動”,並不代錶“業務已經啟動就緒”,有的時候如果業務代碼存在問題,那麼我們的進程啟動了,甚至業務端口也已經暴露了,但是由於業務代碼等异常情况,導致進程起來後服務還沒來得及注册。可此時老版本的 Pod 已經銷毀。對於應用的消費者來說,可能會出現 No Provider 的問題,從而導致在發布的過程中出現大量的流量損失

同樣,如果我們的應用沒有配置 livenessProbe ,Kubernetes 默認只會檢查容器內進程是否存活,而當我們的應用的某個進程由於資源競爭、FullGc、線程池滿或者一些預期外的邏輯導致其處於假死的狀態時,進程雖然存活,但是服務質量低下甚至是為 0。那麼此刻進入到當前應用的全部流量都會報錯,出現大量的流量損失。此刻我們的應用應該通過 livenessProbe 告訴 Kubernetes 當前應用的 Pod 處於不健康且已經無法自己恢複的狀態,需要對當前 Pod 進行重啟操作。

readinessProbe 和 livenessProbe 的配置,目的是及時且靈敏地反饋當前應用的健康情况,以此來保證 Pod 內的各個進程都處於健康狀態,從而保證業務的流量無損

06

變更態:灰度

一次版本的迭代,我們很難保證新的代碼經過測試後,在線上就沒有任何問題。為什麼大部分的故障和發布相關?因為發布是整體業務發布到線上的最後一個環節,一些研發過程中累計的問題,很多時候最後發布環節才會觸發。換句話說,一個潜規則就是公認線上發布基本上不可能沒有 BUG,只是大小而已,但是發布環節要解决的問題就是:既然肯定會有問題,那如何將問題的影響面降至最小?答案是灰度。如果有一些沒有測試到的問題,恰巧我們線上也是全量一批發布的,那麼錯誤將會因為全網鋪開而被放大,出現大量且長時間的線上流量損失。如果我們系統具備灰度能力(甚至全鏈路灰度),那麼我們就可以通過灰度發布的方式將問題的影響面控制到最低。如果系統具備完整的灰度過程中的可觀測能力,那麼發布就會穩定且安全得多。如果灰度能力可以打通全鏈路流程,那麼即使是同時面對多個應用的發布都可以有效保證線上流量無損

07

運行態:服務降級

當應用遇到業務高峰期,發現下遊的服務提供者遇到性能瓶頸,甚至即將影響業務時。我們可以對部分的服務消費者進行服務降級操作,讓不重要的業務方不進行真實地調用,直接返回Mock的結果甚至异常返回,將寶貴的下遊服務提供者資源保留給重要的業務調用方使用,從而提昇整體服務的穩定性。我們把這個過程叫做:服務降級。

當應用依賴的下遊服務出現不可用的情况,導致業務流量損失。您可以通過配置服務降級能力,當下遊服務出現异常時,服務降級使流量可以在調用端 "fail fast",有效防止雪崩。

08

運行態:自動離群摘除

與服務降級類似,自動離群摘除是在流量服務的過程中,遇到單個服務不可用時自動將節點進行摘除的能力,他區別於服務降級主要是體現在兩點:

1)自動完成:服務降級是一種運維動作,需要通過控制臺進行配置,並且指定對應的服務名才能做到相應的效果;而【自動離群摘除】能力是會主動探測上遊節點的存活情况,在這條鏈路上整體做降級。

2)摘除粒度:服務降級降級的是(服務+節點 IP),以 Dubbo 舉例子,一個進程會發布以服務接口名(Interface)為服務名的微服務,如果觸發到這個服務的降級,下次將不再調用這個節點的此服務,但是還是會調用其他服務。但是【離群摘除】是整個節點都不會去嘗試調用。

09

高可用:注册中心容灾

注册中心作為承擔服務注册發現的核心組件,是微服務架構中必不可少的一環。在 CAP 的模型中,注册中心可以犧牲一點點數據一致性(C),即同一時刻每一個節點拿到的服務地址允許短暫的不一致,但必須要保證的是可用性(A)。因為一旦由於某些問題導致注册中心不可用,連接他的節點可能會因為無法獲取服務地址而對整個系統出現灾難性的打擊。除了常見的高可用手段,注册中心特有的容灾手段還有:

1)推空保護:數據中心網絡抖動或者在發布的過程中,會經常出現批量閃斷的情况,但這種情况其實不是業務服務的不可用,如果注册中心識別到這是一種异常情况(批量閃斷或地址變空時),應該采取一種保守的策略,以免誤推從而導致全部服務出現"no provider"的問題,所有微服務會因此導致大量的流量損失。

2)客戶端緩存容灾:與推空保護一樣,站在客戶端的角度邏輯同樣適用,我們經常遇見客戶端和注册中心出現網絡問題時將地址更新的情况,客戶端也不能完全相信注册中心反饋的所有結果,只有明確告知的是正常的結果才能將內存中的地址更新,尤其遇到最後一個地址時采取的策略更要慎重;同時拿到地址之後,也不能完全相信,因為很可能注册中心推送下來的地址根本就不可達。此時要有類似於心跳保活的策略可動態調整對端服務是否可用,以免將服務直接發往無法連接的地址導致流量損失。

3)本地緩存容灾:注册中心容灾了,客戶端也容灾了是否足够?通常情况如果不做變更是足够的,但是如果有一個應用在進行變更時注册中心不可用的話,會發生什麼事情呢?一個是本身地址注册不上,另外一個就是如果有服務發生依賴調用時,流量進來後會出現"no provider"而導致流量損失,甚至根本就無法啟動。如果我們把注册中心的依賴簡化理解為就是對一個服務名字的地址解析的話,其實我們可以將這個解析結果保存在本地做成容灾備份,這樣就能有效避免在變更過程中因為注册中心不可用而導致流量損失。

10

高可用:同城多機房容灾

同城的特點是 RT 一般處在一個比較低的延遲(< 3ms 以內),所以在默認情况下,我們可以基於同城的不同機房搭建起來一個大的局域網,然後把我們應用跨機房分布在多個機房中,以此來應對單機房出現故障時的流量受損風險。相比异地多活,這種基礎設施的建設成本較小,架構變動也比較小。不過在微服務體系之下,應用之間的鏈路錯綜複雜,隨著鏈路深度越來越深,治理的複雜度也會隨之增加,如下圖所示的場景就是前端流量很有可能因為在不同的機房相互調用而導致 RT 突增,最終導致流量損失

f214b749e98459a4f0c8da1fe3c54b1e.png

要解决上面的問題,關鍵是在服務框架層面需要支持同機房優先路由的能力,即:如果目標服務和自己所在機房相同,則優先將流量路由至和我同機房的節點。要實現這個能力的方法大致是注册服務時將自身所在的機房信息上報,機房信息也當成元信息推送至調用方,調用方在路由時通過定制服務框架的 Router 的能力,優先選擇和自己相同機房的地址作為目標地址路由。

03

結語

Aliware

本篇是整個《如何流量無損的在線應用架構》系列的第二篇,這一系列共三篇,旨在使用最為樸素的語言將影響在線應用流量穩定性的技術問題做一個歸類,這些問題的解决方案有的只是一些代碼層面的細節,供你借鑒。

 -END- 


5萬塊買來的《副業搞錢手册》,免費送啦!
關注副業怎麼搞,回複:fuye


騰訊/穀歌《元宇宙 研究報告 100頁》下載

關注AI熊猫教授,回複:yyz666


大家在看:

1.馬化騰慌了!web3.0幹掉互聯網巨頭?

2.快手裁員30%,大部分年薪超100萬!

3.滴滴股票延期解禁,我損失6000萬

4.如何用敏捷搞垮一個團隊?

5.為什麼CTO不寫代碼,還這麼牛逼?

6.如何快速降低一個員工的積極性

版權聲明
本文為[技術領導力]所創,轉載請帶上原文鏈接,感謝
https://cht.chowdera.com/2022/01/202201271056560967.html

隨機推薦