關於軟件系統中的高可用問題的碎碎念

什麼是高可用

在定義什麼是高可用,可以先定義下什麼是不可用,一個網站的內容最終呈現在用戶面前需要經過若干個環節,而其中只要任何一個環節出現了故障,都可能導致網站頁面不可訪問,這個也就是網站不可用的情況。

參考維基百科,看看維基怎麼定義高可用:

系統無中斷地執行其功能的能力,代表系統的可用性程度,是進行系統設計時的準則之一。

這個難點或是重點在於“無中斷”,要做到 7x24 小時無中斷無異常的服務提供。

 

爲什麼需要高可用

一套對外提供服務的系統是需要硬件,軟件相結合,但是我們的硬件總是會出故障,軟件會有 Bug,硬件會慢慢老化,網絡總是不穩定,軟件會越來越複雜和龐大。

除了硬件軟件在本質上無法做到“無中斷”,外部環境也可能導致服務的中斷,例如斷電,地震,火災,光纖被挖掘機挖斷,這些影響的程度可能更大。

 

 高可用  不難理解, 但是一系列的"如果"都疊加過來的話, 問題變得複雜而不好理解了  

 

通常, 我們會問, 如果這個機器可能出現單點故障, 那個服務器掛掉了, 怎麼辦.. 

但是, 如果業務量很少的話,  機器怎麼會那麼容易掛掉呢? 總是問這種問題,  總是顧慮這些問題, 煩不煩啊!!   其實如果業務量, 請求量不多, 數據量不是很大,  我們可能根本不需要做到高可用, 根本不需要考慮那些..

 

高可用是好的, 做不到確實會影響用戶體驗, 但是如果客戶是"自己人", 是不在意這些, 那麼其實不要緊.   況且, 影響用戶體驗的還有很多方面, 比如系統前端的美觀/ 易用性/ 操作便利性, 佈局,  功能是否清晰明確 , 是否好玩有趣, 是否炫酷,  業務邏輯是否流程? 

 

還有, 數據不能丟失, 丟失通常是不能忍的..  但是最不能忍的, 恐怕還是 不可用,  如果你的系統, 經常各種崩潰, 各種bug , 各種異常不能用, 那麼就非常考驗用戶關係了!  關係好的喫頓飯, 賠禮道歉就解決, 關係不好的就可能需要給賠償了!

 

其實呢,  如果業務量很大,   如果導致了 一個機器的長時間高負荷運行,  那麼確實就容易出現故障, 導致機器不能正常運行, 甚至down機, 死掉,  那麼就需要 事先做好 數據的備份遷移. 如果出現了故障,  那麼就立即的啓動並把業務遷移到另外一個相同功能的 服務器上去!

 如果是 能夠無縫的切換,  那麼就是熱備,   如果需要手動啓動另外一個機器,  那麼就是冷備..

 

所以說, 如果是企業用戶, 基本上, 上班時間可用就可以了 ,  互聯網用戶, 那麼需要很高的可用性了!  但是不要總是說什麼集羣 , 高可用 什麼的, 重要的是 可用, 好用!

 

高可用 並不是說100% 可用, 基本上很難做到100% 無影響.  一般還是需要暫停一下業務的,  少則幾毫秒, 幾秒,  幾分鐘,  多則幾個小時,  幾天... 

 

如果是低併發, 或者很少人訪問, 比如半夜, 那麼就不需要 什麼高可用了, 不可用也不會有影響 ,

如果是高併發, 特別是對於那些很重要的業務, 那麼需要保證 不管什麼 機器/服務節點 故障, 都應該能夠提供正常服務. 即使不能快速的處理完用戶請求, 但至少能夠比較快的處理, 比如準實時的, 或者過幾分鐘/ 幾小時後 給處理結果的通知的方式.

當然, 出現故障之後, 可能還是會造成一定的不好的影響. 比如, 如果之前是3個節點並行執行, 後面掛掉一個, 那麼就只剩兩個, 然後服務的處理能力 就自然而然的 肯定會下降大概 1/3.

但這個也不是絕對的, 如果 之前是兩個節點 做冗餘, 無論是冷備或者熱備, 那麼其中一個節點掛掉, 另外一個節點直接替換上就好了.

 

高可用的評價緯度

在業界有一套比較出名的評定網站可用性的指標,常用 N 個 9 來量化可用性,可以直接映射到網站正常運行時間的百分比上:

之前就職的一家互聯網公司也是按照這個指標去界定可用性,不過在執行的過程中也碰到了一些問題。

例如,有一些服務的升級或數據遷移明明可以在深夜停機或停服務進行,然而考慮到以後的報告要顯示出我們的系統達到了多少個 9 的高可用,而放棄停服務這種簡單的解決方案,例如停機 2 個小時,就永遠也達不到 4 個 9。

然而在一些高併發的場合,例如在秒殺或拼團,雖然服務停止了幾分鐘,但是這個對整個公司業務的影響可能是非常重大的,分分鐘丟失的訂單可能是一個龐大的數量。

所以 N 個 9 來量化可用性其實也得考慮業務的情況。

 

微服務高可用設計手段

高可用是一個比較複雜的命題,基本上在所有的處理中都會涉及到高可用,所有在設計高可用方案也涉及到了方方面面。

 

引用https://zhuanlan.zhihu.com/p/88152015 : 

高可用(HA)是系統架構設計中必須要考慮的,是指系統所能提供無故障服務的一種能力。


簡單的說就是避免因服務器宕機而造成的服務不可用的情況,像Elasticsearch並不會因爲一節點的宕機而造成整個搜索服務不可用(可以看前面分享的ES分佈式搜索原理)。

如何衡量高可用

假設你的系統全年都是正常提供服務,那麼就是說你係統的可用性是100%,當然這個值是理想狀態下,一般都是以幾個9來表示系統的可用性,99.99的可用性較多,9越多就代表可用性越強,下面來看看這個幾個9是如何計算出來的

可用性=平均故障間隔/(平均故障間隔 + 故障恢復平均時間)

如何設計系統的高可用

想要高可用就要避免使用單點,你想想看你的單臺服務器再強應用優化的再極致,只要它宕機,就啥都涼涼了,所以需要多臺機器也就是需要集羣,方法論中叫冗餘。只是有了集羣是不能完全滿足複雜業務的高可用的,我們要讓系統在當前節點宕機的情況下,自己進行切換到好的節點去,這即所謂的故障轉移。所以我們現在設計高可用系統的目標明確了,

那就是:冗餘 + 故障轉移 

 

 

設計系統高可用方法論

上面介紹了我們在宏觀方面怎麼設計系統高可用,其實我們在編碼的時候除了故障轉移方案,同樣需要考慮很多東西來保證系統的可用性,主要體現在,失敗轉移, 超時機制、降級、限流, 緩存, 橫向/縱向擴展, 異步解耦, 削峯填谷

對於rpc請求, 不管是對其他微服務的rpc 還是對數據庫/ redis/ mq 的rpc, 都應該有一個超時時間,  防止遠程服務的假死, 進而導致現有系統的過多的請求阻塞, 導致 佔用很多的資源不釋放, 導致內存不夠用溢出等問題.. 

所以呢, 是需要一個超時時間的, 但是適當的等待是需要的, 因爲不等待而返回異常, 總是體驗不好的!

 

失敗轉移

失敗轉移就是說一個節點掛掉, 立即使用其他的備用節點, 或者上游系統做探測, 發現某節點失敗, 直接把請求轉移到另外的相同功能的節點,  同時把後續的請求也不在轉發到此節點, 直到它恢復之後.

 

降級

降級就是說, 原來提供了1級水平的服務, 現在因爲某些故障, 只能提供2級或3級水平了, 相當於是下降了服務的等級.

它往往是跟遠程訪問時 遠程服務的異常/超時 有關,  此時, 如果直接把原本的錯誤返回前端, 肯定是不好的, 那麼返回一個降級的結果, 比如一個默認值,  一個估計值, 或者實在不行就返回一個友好的提示, 也總比沒有的好.

不重要的服務停掉, 或者降級掉.. 

 

異步解耦/削峯填谷

這個跟高可用沒有直接關係, 它其實跟高併發有一定關係,  而高併發跟高可用有一定關係.  我們說高可用, 一般也是在高併發的場景下.  通過 異步解耦/削峯填谷 , 我們可以一定程度的迂迴的降低系統壓力, 從而也一定程度提高了高可用.

異步解耦/削峯填谷 之後, 我們響應是沒有那麼快了,  但是我們只要保證了最終一致性, 那也是挺好的. 基本上用戶也不會有太大的怨言..

 

兜底 

兜底和降級很相似,  降級主要是講把服務停掉或部分停掉, 降低其對資源的要求, 比如原來給他4c8u, 現在給他1c2u, 或者直接停掉它, 而兜底可用理解爲 fallback, 

 

限流

限流, 這個主要就是說在客戶端請求特別大的時候, 我們一應該把請求直接在前面的服務或網關 就直接拒絕它,  避免它打到了後端的服務.  這個是很有用的一種方式,  可以說得上是一種哲學, 一種智慧. 通常是, 經過壓測之後, 我們大概知道我們的系統的處理能力/ 吞吐能力( 一般也只能精確到數據量級的水平), 這個時候 我們估計用戶的請求的併發請求總量, 然後我們就把超出處理能力那部分的請求 直接降級.

 

當然, 其實應該分場景來做限流, 對於是惡意請求, 我們全部拒絕.  比如對於黑名單的ip/ 用戶, 對於那種惡意發起大量以致海量請求的用戶, 明顯不正常, 就可以調查他, 警告他, 然後拒絕它的全部請求.

對於那種無法區分是不是惡意的請求,  我們可能選擇性的 隨機的拒絕它, 然後給他一個溫馨的,抱歉的響應.

 

秒殺場景之下,  我們的商品數量是有限的, 比如只有100 個優惠商品, 用戶請求卻有1w 甚至10w, 那麼就可以直接 拒絕其中一大部分, 比如我們可以給全國各省都分配一定的定額,  在保證定額的前提下, 選擇性的拒絕其他的請求 

當然, 我們應該至少留100個請求, 但是呢, 這100個請求, 可能有一部分請求會最終沒法完成支付, 那麼我們就把這部分的定額釋放出來,   就是說, 剩餘的優惠商品數量, 應該是可以實時查看的, 先來的有機會搶到,  後到的機會少一些, 但也是留有機會的.

同時呢, 我們可能希望活動能夠持續一段時間, 而不是, 真正的 一下子就結束,  我們把100個優惠商品, 分2個小時 放出,  如每隔10分鐘放出10個名額, 搶到的優先..

 

橫向/縱向擴展

高擴展性個高可用是兩個話題, 有一定的關聯, 怎麼說呢, 如果系統有很好的擴展性, 那麼自然的, 可用性也會得到提升.

 

 

一個簡單的高可用設計實例

我們來先看看當前大部分互聯網公司的系統架構: 

 

 

 

這個其實只有一個應用服務的架構, 如果是很大應用服務, 那麼.  紅色的表示可以允許掛掉的節點, 同名的方框表示相同的軟件系統.

 

可以看到,這樣的架構其實就保證了非常高的可用性.

1 如果nginx 掛掉一臺, 立即切換, 毫無影響 __  圖中 vip 沒畫出來, app 應該是通過vip 訪問nginx , 而不是直接範圍, 否則,  app 需要配置多個nginx ip,  其中一個發生故障, 則自動使用另外一個 

2 service1 應用節點掛掉, 毫無影響 ,  當然, 我們需要做成是無狀態的, 否則那就多少還是會有一定的影響,  特別是session狀態.  我們把所有的軟件服務看成一個大的系統,  一個整體,  它肯定是需要登錄的,  每個應用內部不需要session, 但是鑑權還是需要的吧,  鑑權怎麼做?  還是說鑑權也可以省去呢?

3 緩存從節點掛掉, 毫無影響 , 因爲我們是集羣,  主節點掛掉, 從升級爲主, 因爲緩存做了主從同步.. 所以也是幾乎沒有影響,  有影響也是影響到 那麼幾秒鐘..

4 數據庫也是類似緩存, 不過數據安全要求更高..

5 當然, 用戶終端也可以會掛點, 當然, 這種問題是用戶的問題了, 跟我們的系統沒關係, 超出我們處理範圍, 不予考慮

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章