'全面!一文理解微服務高可用的常用手段'

軟件 硬件 設計 Docker 人生第一份工作 高可用架構 2019-08-31
"

高可用並不是一套整體解決方案,而是由諸多環節組成,一環扣一環,鬼知道為了這些串聯起來的環節,我得出多少張牌去應對,才能最終組成一個整個系統的高可用落地方案。

"

高可用並不是一套整體解決方案,而是由諸多環節組成,一環扣一環,鬼知道為了這些串聯起來的環節,我得出多少張牌去應對,才能最終組成一個整個系統的高可用落地方案。

全面!一文理解微服務高可用的常用手段

圖片來自 Pexels

什麼是高可用

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

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

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

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

為什麼需要高可用

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

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

高可用的評價緯度

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

"

高可用並不是一套整體解決方案,而是由諸多環節組成,一環扣一環,鬼知道為了這些串聯起來的環節,我得出多少張牌去應對,才能最終組成一個整個系統的高可用落地方案。

全面!一文理解微服務高可用的常用手段

圖片來自 Pexels

什麼是高可用

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

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

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

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

為什麼需要高可用

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

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

高可用的評價緯度

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

全面!一文理解微服務高可用的常用手段

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

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

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

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

微服務高可用設計手段

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

"

高可用並不是一套整體解決方案,而是由諸多環節組成,一環扣一環,鬼知道為了這些串聯起來的環節,我得出多少張牌去應對,才能最終組成一個整個系統的高可用落地方案。

全面!一文理解微服務高可用的常用手段

圖片來自 Pexels

什麼是高可用

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

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

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

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

為什麼需要高可用

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

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

高可用的評價緯度

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

全面!一文理解微服務高可用的常用手段

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

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

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

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

微服務高可用設計手段

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

全面!一文理解微服務高可用的常用手段

這中間將會出現的細節是多種多樣的,所以我們需要對這樣一個微服務高可用方案進行一個頂層的設計,圍繞服務高可用,先檢查下我們手裡有多少張牌。

服務冗餘

"

高可用並不是一套整體解決方案,而是由諸多環節組成,一環扣一環,鬼知道為了這些串聯起來的環節,我得出多少張牌去應對,才能最終組成一個整個系統的高可用落地方案。

全面!一文理解微服務高可用的常用手段

圖片來自 Pexels

什麼是高可用

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

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

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

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

為什麼需要高可用

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

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

高可用的評價緯度

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

全面!一文理解微服務高可用的常用手段

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

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

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

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

微服務高可用設計手段

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

全面!一文理解微服務高可用的常用手段

這中間將會出現的細節是多種多樣的,所以我們需要對這樣一個微服務高可用方案進行一個頂層的設計,圍繞服務高可用,先檢查下我們手裡有多少張牌。

服務冗餘

全面!一文理解微服務高可用的常用手段

①冗餘策略

每一個訪問可能都會有多個服務組合而成,每個機器每個服務都可能出現問題,所以第一個考慮到的就是每個服務必須不止一份可以是多份。

所謂多份一致的服務就是服務的冗餘,這裡說的服務泛指了機器的服務,容器的服務,還有微服務本身的服務。

在機器服務層面需要考慮,各個機器間的冗餘是否有在物理空間進行隔離冗餘。

例如是否所有機器分別部署在不同機房,如果在同一個機房是否做到了部署在不同的機櫃,如果是 Docker 容器是否部署在分別不同的物理機上面。

採取的策略其實也還是根據服務的業務而定,所以需要對服務進行分級評分,從而採取不同的策略。

不同的策略安全程度不同,伴隨著的成本也是不同,安全等級更高的服務可能還不止考慮不同機房,還需要把各個機房所處的區域考慮進行。

例如,兩個機房不要處在同一個地震帶上等等。

"

高可用並不是一套整體解決方案,而是由諸多環節組成,一環扣一環,鬼知道為了這些串聯起來的環節,我得出多少張牌去應對,才能最終組成一個整個系統的高可用落地方案。

全面!一文理解微服務高可用的常用手段

圖片來自 Pexels

什麼是高可用

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

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

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

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

為什麼需要高可用

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

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

高可用的評價緯度

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

全面!一文理解微服務高可用的常用手段

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

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

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

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

微服務高可用設計手段

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

全面!一文理解微服務高可用的常用手段

這中間將會出現的細節是多種多樣的,所以我們需要對這樣一個微服務高可用方案進行一個頂層的設計,圍繞服務高可用,先檢查下我們手裡有多少張牌。

服務冗餘

全面!一文理解微服務高可用的常用手段

①冗餘策略

每一個訪問可能都會有多個服務組合而成,每個機器每個服務都可能出現問題,所以第一個考慮到的就是每個服務必須不止一份可以是多份。

所謂多份一致的服務就是服務的冗餘,這裡說的服務泛指了機器的服務,容器的服務,還有微服務本身的服務。

在機器服務層面需要考慮,各個機器間的冗餘是否有在物理空間進行隔離冗餘。

例如是否所有機器分別部署在不同機房,如果在同一個機房是否做到了部署在不同的機櫃,如果是 Docker 容器是否部署在分別不同的物理機上面。

採取的策略其實也還是根據服務的業務而定,所以需要對服務進行分級評分,從而採取不同的策略。

不同的策略安全程度不同,伴隨著的成本也是不同,安全等級更高的服務可能還不止考慮不同機房,還需要把各個機房所處的區域考慮進行。

例如,兩個機房不要處在同一個地震帶上等等。

全面!一文理解微服務高可用的常用手段

②無狀態化

服務的冗餘會要求我們可以隨時對服務進行擴容或者縮容,有可能我們會從 2 臺機器變成 3 臺機器。

想要對服務進行隨時隨地的擴縮容,就要求我們的服務是一個無狀態化,所謂無狀態化就是每個服務的服務內容和數據都是一致的。

例如,從我們的微服務架構來看,我們總共分水平劃分了好幾個層,正因為我們每個層都做到了無狀態,所以在這個水平架構的擴張是非常的簡單。

假設,我們需要對網關進行擴容,我們只需要增加服務就可以,而不需要去考慮網關是否存儲了一個額外的數據。

"

高可用並不是一套整體解決方案,而是由諸多環節組成,一環扣一環,鬼知道為了這些串聯起來的環節,我得出多少張牌去應對,才能最終組成一個整個系統的高可用落地方案。

全面!一文理解微服務高可用的常用手段

圖片來自 Pexels

什麼是高可用

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

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

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

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

為什麼需要高可用

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

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

高可用的評價緯度

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

全面!一文理解微服務高可用的常用手段

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

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

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

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

微服務高可用設計手段

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

全面!一文理解微服務高可用的常用手段

這中間將會出現的細節是多種多樣的,所以我們需要對這樣一個微服務高可用方案進行一個頂層的設計,圍繞服務高可用,先檢查下我們手裡有多少張牌。

服務冗餘

全面!一文理解微服務高可用的常用手段

①冗餘策略

每一個訪問可能都會有多個服務組合而成,每個機器每個服務都可能出現問題,所以第一個考慮到的就是每個服務必須不止一份可以是多份。

所謂多份一致的服務就是服務的冗餘,這裡說的服務泛指了機器的服務,容器的服務,還有微服務本身的服務。

在機器服務層面需要考慮,各個機器間的冗餘是否有在物理空間進行隔離冗餘。

例如是否所有機器分別部署在不同機房,如果在同一個機房是否做到了部署在不同的機櫃,如果是 Docker 容器是否部署在分別不同的物理機上面。

採取的策略其實也還是根據服務的業務而定,所以需要對服務進行分級評分,從而採取不同的策略。

不同的策略安全程度不同,伴隨著的成本也是不同,安全等級更高的服務可能還不止考慮不同機房,還需要把各個機房所處的區域考慮進行。

例如,兩個機房不要處在同一個地震帶上等等。

全面!一文理解微服務高可用的常用手段

②無狀態化

服務的冗餘會要求我們可以隨時對服務進行擴容或者縮容,有可能我們會從 2 臺機器變成 3 臺機器。

想要對服務進行隨時隨地的擴縮容,就要求我們的服務是一個無狀態化,所謂無狀態化就是每個服務的服務內容和數據都是一致的。

例如,從我們的微服務架構來看,我們總共分水平劃分了好幾個層,正因為我們每個層都做到了無狀態,所以在這個水平架構的擴張是非常的簡單。

假設,我們需要對網關進行擴容,我們只需要增加服務就可以,而不需要去考慮網關是否存儲了一個額外的數據。

全面!一文理解微服務高可用的常用手段

網關不保存任何的 Session 數據,不提供會造成一致性的服務,將不一致的數據進行幾種存儲,藉助更加擅長數據同步的中間件來完成。

這個是目前主流的方案,服務本身儘可能提供邏輯的服務,將數據的一致性保證集中式處理,這樣就可以把“狀態”抽取出來,讓網關保持一個“無狀態”。

這裡僅僅是舉了網關的例子,在微服務基本所有的服務,都應該按照這種思路去做。

如果服務中有狀態,就應該把狀態抽取出來,讓更加擅長處理數據的組件來處理,而不是在微服務中去兼容有數據的狀態。

數據存儲高可用

"

高可用並不是一套整體解決方案,而是由諸多環節組成,一環扣一環,鬼知道為了這些串聯起來的環節,我得出多少張牌去應對,才能最終組成一個整個系統的高可用落地方案。

全面!一文理解微服務高可用的常用手段

圖片來自 Pexels

什麼是高可用

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

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

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

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

為什麼需要高可用

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

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

高可用的評價緯度

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

全面!一文理解微服務高可用的常用手段

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

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

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

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

微服務高可用設計手段

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

全面!一文理解微服務高可用的常用手段

這中間將會出現的細節是多種多樣的,所以我們需要對這樣一個微服務高可用方案進行一個頂層的設計,圍繞服務高可用,先檢查下我們手裡有多少張牌。

服務冗餘

全面!一文理解微服務高可用的常用手段

①冗餘策略

每一個訪問可能都會有多個服務組合而成,每個機器每個服務都可能出現問題,所以第一個考慮到的就是每個服務必須不止一份可以是多份。

所謂多份一致的服務就是服務的冗餘,這裡說的服務泛指了機器的服務,容器的服務,還有微服務本身的服務。

在機器服務層面需要考慮,各個機器間的冗餘是否有在物理空間進行隔離冗餘。

例如是否所有機器分別部署在不同機房,如果在同一個機房是否做到了部署在不同的機櫃,如果是 Docker 容器是否部署在分別不同的物理機上面。

採取的策略其實也還是根據服務的業務而定,所以需要對服務進行分級評分,從而採取不同的策略。

不同的策略安全程度不同,伴隨著的成本也是不同,安全等級更高的服務可能還不止考慮不同機房,還需要把各個機房所處的區域考慮進行。

例如,兩個機房不要處在同一個地震帶上等等。

全面!一文理解微服務高可用的常用手段

②無狀態化

服務的冗餘會要求我們可以隨時對服務進行擴容或者縮容,有可能我們會從 2 臺機器變成 3 臺機器。

想要對服務進行隨時隨地的擴縮容,就要求我們的服務是一個無狀態化,所謂無狀態化就是每個服務的服務內容和數據都是一致的。

例如,從我們的微服務架構來看,我們總共分水平劃分了好幾個層,正因為我們每個層都做到了無狀態,所以在這個水平架構的擴張是非常的簡單。

假設,我們需要對網關進行擴容,我們只需要增加服務就可以,而不需要去考慮網關是否存儲了一個額外的數據。

全面!一文理解微服務高可用的常用手段

網關不保存任何的 Session 數據,不提供會造成一致性的服務,將不一致的數據進行幾種存儲,藉助更加擅長數據同步的中間件來完成。

這個是目前主流的方案,服務本身儘可能提供邏輯的服務,將數據的一致性保證集中式處理,這樣就可以把“狀態”抽取出來,讓網關保持一個“無狀態”。

這裡僅僅是舉了網關的例子,在微服務基本所有的服務,都應該按照這種思路去做。

如果服務中有狀態,就應該把狀態抽取出來,讓更加擅長處理數據的組件來處理,而不是在微服務中去兼容有數據的狀態。

數據存儲高可用

全面!一文理解微服務高可用的常用手段

之前上面說的服務冗餘,可以簡單的理解為計算的高可用,計算高可用只需要做到無狀態既可簡單的擴容縮容,但是對於需要存儲數據的系統來說,數據本身就是有狀態。

跟存儲與計算相比,有一個本質的差別:將數據從一臺機器搬到另一臺機器,需要經過線路進行傳輸。

網絡是不穩定的,特別是跨機房的網絡,Ping 的延時可能是幾十幾百毫秒,雖然毫秒對於人來說幾乎沒有什麼感覺,但是對於高可用系統來說,就是本質上的不同,這意味著整個系統在某個時間點上,數據肯定是不一致的。

按照“數據+邏輯=業務”的公式來看,數據不一致,邏輯一致,最後的業務表現也會不一致。

舉個例子:

"

高可用並不是一套整體解決方案,而是由諸多環節組成,一環扣一環,鬼知道為了這些串聯起來的環節,我得出多少張牌去應對,才能最終組成一個整個系統的高可用落地方案。

全面!一文理解微服務高可用的常用手段

圖片來自 Pexels

什麼是高可用

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

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

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

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

為什麼需要高可用

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

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

高可用的評價緯度

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

全面!一文理解微服務高可用的常用手段

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

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

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

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

微服務高可用設計手段

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

全面!一文理解微服務高可用的常用手段

這中間將會出現的細節是多種多樣的,所以我們需要對這樣一個微服務高可用方案進行一個頂層的設計,圍繞服務高可用,先檢查下我們手裡有多少張牌。

服務冗餘

全面!一文理解微服務高可用的常用手段

①冗餘策略

每一個訪問可能都會有多個服務組合而成,每個機器每個服務都可能出現問題,所以第一個考慮到的就是每個服務必須不止一份可以是多份。

所謂多份一致的服務就是服務的冗餘,這裡說的服務泛指了機器的服務,容器的服務,還有微服務本身的服務。

在機器服務層面需要考慮,各個機器間的冗餘是否有在物理空間進行隔離冗餘。

例如是否所有機器分別部署在不同機房,如果在同一個機房是否做到了部署在不同的機櫃,如果是 Docker 容器是否部署在分別不同的物理機上面。

採取的策略其實也還是根據服務的業務而定,所以需要對服務進行分級評分,從而採取不同的策略。

不同的策略安全程度不同,伴隨著的成本也是不同,安全等級更高的服務可能還不止考慮不同機房,還需要把各個機房所處的區域考慮進行。

例如,兩個機房不要處在同一個地震帶上等等。

全面!一文理解微服務高可用的常用手段

②無狀態化

服務的冗餘會要求我們可以隨時對服務進行擴容或者縮容,有可能我們會從 2 臺機器變成 3 臺機器。

想要對服務進行隨時隨地的擴縮容,就要求我們的服務是一個無狀態化,所謂無狀態化就是每個服務的服務內容和數據都是一致的。

例如,從我們的微服務架構來看,我們總共分水平劃分了好幾個層,正因為我們每個層都做到了無狀態,所以在這個水平架構的擴張是非常的簡單。

假設,我們需要對網關進行擴容,我們只需要增加服務就可以,而不需要去考慮網關是否存儲了一個額外的數據。

全面!一文理解微服務高可用的常用手段

網關不保存任何的 Session 數據,不提供會造成一致性的服務,將不一致的數據進行幾種存儲,藉助更加擅長數據同步的中間件來完成。

這個是目前主流的方案,服務本身儘可能提供邏輯的服務,將數據的一致性保證集中式處理,這樣就可以把“狀態”抽取出來,讓網關保持一個“無狀態”。

這裡僅僅是舉了網關的例子,在微服務基本所有的服務,都應該按照這種思路去做。

如果服務中有狀態,就應該把狀態抽取出來,讓更加擅長處理數據的組件來處理,而不是在微服務中去兼容有數據的狀態。

數據存儲高可用

全面!一文理解微服務高可用的常用手段

之前上面說的服務冗餘,可以簡單的理解為計算的高可用,計算高可用只需要做到無狀態既可簡單的擴容縮容,但是對於需要存儲數據的系統來說,數據本身就是有狀態。

跟存儲與計算相比,有一個本質的差別:將數據從一臺機器搬到另一臺機器,需要經過線路進行傳輸。

網絡是不穩定的,特別是跨機房的網絡,Ping 的延時可能是幾十幾百毫秒,雖然毫秒對於人來說幾乎沒有什麼感覺,但是對於高可用系統來說,就是本質上的不同,這意味著整個系統在某個時間點上,數據肯定是不一致的。

按照“數據+邏輯=業務”的公式來看,數據不一致,邏輯一致,最後的業務表現也會不一致。

舉個例子:

全面!一文理解微服務高可用的常用手段

無論是正常情況下的傳輸延時,還是異常情況下的傳輸中斷,都會導致系統的數據在某個時間點出現不一致。

而數據的不一致又會導致業務出現問題,但是如果數據不做冗餘,系統的高可用無法保證。

所以,存儲高可用的難點不在於怎麼備份數據,而在於如何減少或者規避數據不一致對業務造成的影響。

分佈式領域中有一個著名的 CAP 定理,從理論上論證了存儲高可用的複雜度,也就是說,存儲高可用不可能同時滿足“一致性,可用性,分區容錯性”。

最多隻能滿足 2 個,其中分區容錯在分佈式中是必須的,就意味著,我們在做架構設計時必須結合業務對一致性和可用性進行取捨。

存儲高可用方案的本質是將數據複製到多個存儲設備中,通過數據冗餘的方式來實現高可用,其複雜度主要呈現在數據複製的延遲或中斷導致數據的不一致性。

我們在設計存儲架構時必須考慮到以下幾個方面:

  • 數據怎麼進行復制

  • 架構中每個節點的職責是什麼

  • 數據複製出現延遲怎麼處理

  • 當架構中節點出現錯誤怎麼保證高可用

①數據主從複製

主從複製是最常見的也是最簡單的存儲高可用方案,例如 MySQL,Redis 等等。

"

高可用並不是一套整體解決方案,而是由諸多環節組成,一環扣一環,鬼知道為了這些串聯起來的環節,我得出多少張牌去應對,才能最終組成一個整個系統的高可用落地方案。

全面!一文理解微服務高可用的常用手段

圖片來自 Pexels

什麼是高可用

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

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

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

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

為什麼需要高可用

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

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

高可用的評價緯度

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

全面!一文理解微服務高可用的常用手段

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

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

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

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

微服務高可用設計手段

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

全面!一文理解微服務高可用的常用手段

這中間將會出現的細節是多種多樣的,所以我們需要對這樣一個微服務高可用方案進行一個頂層的設計,圍繞服務高可用,先檢查下我們手裡有多少張牌。

服務冗餘

全面!一文理解微服務高可用的常用手段

①冗餘策略

每一個訪問可能都會有多個服務組合而成,每個機器每個服務都可能出現問題,所以第一個考慮到的就是每個服務必須不止一份可以是多份。

所謂多份一致的服務就是服務的冗餘,這裡說的服務泛指了機器的服務,容器的服務,還有微服務本身的服務。

在機器服務層面需要考慮,各個機器間的冗餘是否有在物理空間進行隔離冗餘。

例如是否所有機器分別部署在不同機房,如果在同一個機房是否做到了部署在不同的機櫃,如果是 Docker 容器是否部署在分別不同的物理機上面。

採取的策略其實也還是根據服務的業務而定,所以需要對服務進行分級評分,從而採取不同的策略。

不同的策略安全程度不同,伴隨著的成本也是不同,安全等級更高的服務可能還不止考慮不同機房,還需要把各個機房所處的區域考慮進行。

例如,兩個機房不要處在同一個地震帶上等等。

全面!一文理解微服務高可用的常用手段

②無狀態化

服務的冗餘會要求我們可以隨時對服務進行擴容或者縮容,有可能我們會從 2 臺機器變成 3 臺機器。

想要對服務進行隨時隨地的擴縮容,就要求我們的服務是一個無狀態化,所謂無狀態化就是每個服務的服務內容和數據都是一致的。

例如,從我們的微服務架構來看,我們總共分水平劃分了好幾個層,正因為我們每個層都做到了無狀態,所以在這個水平架構的擴張是非常的簡單。

假設,我們需要對網關進行擴容,我們只需要增加服務就可以,而不需要去考慮網關是否存儲了一個額外的數據。

全面!一文理解微服務高可用的常用手段

網關不保存任何的 Session 數據,不提供會造成一致性的服務,將不一致的數據進行幾種存儲,藉助更加擅長數據同步的中間件來完成。

這個是目前主流的方案,服務本身儘可能提供邏輯的服務,將數據的一致性保證集中式處理,這樣就可以把“狀態”抽取出來,讓網關保持一個“無狀態”。

這裡僅僅是舉了網關的例子,在微服務基本所有的服務,都應該按照這種思路去做。

如果服務中有狀態,就應該把狀態抽取出來,讓更加擅長處理數據的組件來處理,而不是在微服務中去兼容有數據的狀態。

數據存儲高可用

全面!一文理解微服務高可用的常用手段

之前上面說的服務冗餘,可以簡單的理解為計算的高可用,計算高可用只需要做到無狀態既可簡單的擴容縮容,但是對於需要存儲數據的系統來說,數據本身就是有狀態。

跟存儲與計算相比,有一個本質的差別:將數據從一臺機器搬到另一臺機器,需要經過線路進行傳輸。

網絡是不穩定的,特別是跨機房的網絡,Ping 的延時可能是幾十幾百毫秒,雖然毫秒對於人來說幾乎沒有什麼感覺,但是對於高可用系統來說,就是本質上的不同,這意味著整個系統在某個時間點上,數據肯定是不一致的。

按照“數據+邏輯=業務”的公式來看,數據不一致,邏輯一致,最後的業務表現也會不一致。

舉個例子:

全面!一文理解微服務高可用的常用手段

無論是正常情況下的傳輸延時,還是異常情況下的傳輸中斷,都會導致系統的數據在某個時間點出現不一致。

而數據的不一致又會導致業務出現問題,但是如果數據不做冗餘,系統的高可用無法保證。

所以,存儲高可用的難點不在於怎麼備份數據,而在於如何減少或者規避數據不一致對業務造成的影響。

分佈式領域中有一個著名的 CAP 定理,從理論上論證了存儲高可用的複雜度,也就是說,存儲高可用不可能同時滿足“一致性,可用性,分區容錯性”。

最多隻能滿足 2 個,其中分區容錯在分佈式中是必須的,就意味著,我們在做架構設計時必須結合業務對一致性和可用性進行取捨。

存儲高可用方案的本質是將數據複製到多個存儲設備中,通過數據冗餘的方式來實現高可用,其複雜度主要呈現在數據複製的延遲或中斷導致數據的不一致性。

我們在設計存儲架構時必須考慮到以下幾個方面:

  • 數據怎麼進行復制

  • 架構中每個節點的職責是什麼

  • 數據複製出現延遲怎麼處理

  • 當架構中節點出現錯誤怎麼保證高可用

①數據主從複製

主從複製是最常見的也是最簡單的存儲高可用方案,例如 MySQL,Redis 等等。

全面!一文理解微服務高可用的常用手段

其架構的優點就是簡單,主機複製寫和讀,而從機只負責讀操作,在讀併發高時候可用擴張從庫的數量減低壓力,主機出現故障,讀操作也可以保證讀業務的順利進行。

缺點就是客戶端必須感知主從關係的存在,將不同的操作發送給不同的機器進行處理。

而且主從複製中,從機器負責讀操作,可能因為主從複製時延大,出現數據不一致性的問題。

②數據主從切換

剛說了主從切換存在兩個問題:

  • 主機故障寫操作無法進行。

  • 需要人工將其中一臺從機器升級為主機。

為了解決這個兩個問題,我們可以設計一套主從自動切換的方案,其中涉及到對主機的狀態檢測,切換的決策,數據丟失和衝突的問題。

主機狀態檢測:需要多個檢查點來檢測主機的機器是否正常,進程是否存在,是否出現超時,是否寫操作不可執行,是否讀操作不可執行,將其進行彙總,交給切換決策。

切換決策:確定切換的時間決策,什麼情況下從機就應該升級為主機,是進程不存在,是寫操作不可行,連續檢測多少失敗次就進行切換。

應該選擇哪一個從節點升級為主節點,一般來說或應該選同步步驟最大的從節點來進行升級。切換是自動切換還是半自動切換,通過報警方式,讓人工做一次確認。

數據丟失和數據衝突:數據寫到主機,還沒有複製到從機,主機就掛了,這個時候怎麼處理,這個也得考慮業務的方式,是要確保 CP 或 AP。

"

高可用並不是一套整體解決方案,而是由諸多環節組成,一環扣一環,鬼知道為了這些串聯起來的環節,我得出多少張牌去應對,才能最終組成一個整個系統的高可用落地方案。

全面!一文理解微服務高可用的常用手段

圖片來自 Pexels

什麼是高可用

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

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

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

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

為什麼需要高可用

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

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

高可用的評價緯度

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

全面!一文理解微服務高可用的常用手段

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

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

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

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

微服務高可用設計手段

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

全面!一文理解微服務高可用的常用手段

這中間將會出現的細節是多種多樣的,所以我們需要對這樣一個微服務高可用方案進行一個頂層的設計,圍繞服務高可用,先檢查下我們手裡有多少張牌。

服務冗餘

全面!一文理解微服務高可用的常用手段

①冗餘策略

每一個訪問可能都會有多個服務組合而成,每個機器每個服務都可能出現問題,所以第一個考慮到的就是每個服務必須不止一份可以是多份。

所謂多份一致的服務就是服務的冗餘,這裡說的服務泛指了機器的服務,容器的服務,還有微服務本身的服務。

在機器服務層面需要考慮,各個機器間的冗餘是否有在物理空間進行隔離冗餘。

例如是否所有機器分別部署在不同機房,如果在同一個機房是否做到了部署在不同的機櫃,如果是 Docker 容器是否部署在分別不同的物理機上面。

採取的策略其實也還是根據服務的業務而定,所以需要對服務進行分級評分,從而採取不同的策略。

不同的策略安全程度不同,伴隨著的成本也是不同,安全等級更高的服務可能還不止考慮不同機房,還需要把各個機房所處的區域考慮進行。

例如,兩個機房不要處在同一個地震帶上等等。

全面!一文理解微服務高可用的常用手段

②無狀態化

服務的冗餘會要求我們可以隨時對服務進行擴容或者縮容,有可能我們會從 2 臺機器變成 3 臺機器。

想要對服務進行隨時隨地的擴縮容,就要求我們的服務是一個無狀態化,所謂無狀態化就是每個服務的服務內容和數據都是一致的。

例如,從我們的微服務架構來看,我們總共分水平劃分了好幾個層,正因為我們每個層都做到了無狀態,所以在這個水平架構的擴張是非常的簡單。

假設,我們需要對網關進行擴容,我們只需要增加服務就可以,而不需要去考慮網關是否存儲了一個額外的數據。

全面!一文理解微服務高可用的常用手段

網關不保存任何的 Session 數據,不提供會造成一致性的服務,將不一致的數據進行幾種存儲,藉助更加擅長數據同步的中間件來完成。

這個是目前主流的方案,服務本身儘可能提供邏輯的服務,將數據的一致性保證集中式處理,這樣就可以把“狀態”抽取出來,讓網關保持一個“無狀態”。

這裡僅僅是舉了網關的例子,在微服務基本所有的服務,都應該按照這種思路去做。

如果服務中有狀態,就應該把狀態抽取出來,讓更加擅長處理數據的組件來處理,而不是在微服務中去兼容有數據的狀態。

數據存儲高可用

全面!一文理解微服務高可用的常用手段

之前上面說的服務冗餘,可以簡單的理解為計算的高可用,計算高可用只需要做到無狀態既可簡單的擴容縮容,但是對於需要存儲數據的系統來說,數據本身就是有狀態。

跟存儲與計算相比,有一個本質的差別:將數據從一臺機器搬到另一臺機器,需要經過線路進行傳輸。

網絡是不穩定的,特別是跨機房的網絡,Ping 的延時可能是幾十幾百毫秒,雖然毫秒對於人來說幾乎沒有什麼感覺,但是對於高可用系統來說,就是本質上的不同,這意味著整個系統在某個時間點上,數據肯定是不一致的。

按照“數據+邏輯=業務”的公式來看,數據不一致,邏輯一致,最後的業務表現也會不一致。

舉個例子:

全面!一文理解微服務高可用的常用手段

無論是正常情況下的傳輸延時,還是異常情況下的傳輸中斷,都會導致系統的數據在某個時間點出現不一致。

而數據的不一致又會導致業務出現問題,但是如果數據不做冗餘,系統的高可用無法保證。

所以,存儲高可用的難點不在於怎麼備份數據,而在於如何減少或者規避數據不一致對業務造成的影響。

分佈式領域中有一個著名的 CAP 定理,從理論上論證了存儲高可用的複雜度,也就是說,存儲高可用不可能同時滿足“一致性,可用性,分區容錯性”。

最多隻能滿足 2 個,其中分區容錯在分佈式中是必須的,就意味著,我們在做架構設計時必須結合業務對一致性和可用性進行取捨。

存儲高可用方案的本質是將數據複製到多個存儲設備中,通過數據冗餘的方式來實現高可用,其複雜度主要呈現在數據複製的延遲或中斷導致數據的不一致性。

我們在設計存儲架構時必須考慮到以下幾個方面:

  • 數據怎麼進行復制

  • 架構中每個節點的職責是什麼

  • 數據複製出現延遲怎麼處理

  • 當架構中節點出現錯誤怎麼保證高可用

①數據主從複製

主從複製是最常見的也是最簡單的存儲高可用方案,例如 MySQL,Redis 等等。

全面!一文理解微服務高可用的常用手段

其架構的優點就是簡單,主機複製寫和讀,而從機只負責讀操作,在讀併發高時候可用擴張從庫的數量減低壓力,主機出現故障,讀操作也可以保證讀業務的順利進行。

缺點就是客戶端必須感知主從關係的存在,將不同的操作發送給不同的機器進行處理。

而且主從複製中,從機器負責讀操作,可能因為主從複製時延大,出現數據不一致性的問題。

②數據主從切換

剛說了主從切換存在兩個問題:

  • 主機故障寫操作無法進行。

  • 需要人工將其中一臺從機器升級為主機。

為了解決這個兩個問題,我們可以設計一套主從自動切換的方案,其中涉及到對主機的狀態檢測,切換的決策,數據丟失和衝突的問題。

主機狀態檢測:需要多個檢查點來檢測主機的機器是否正常,進程是否存在,是否出現超時,是否寫操作不可執行,是否讀操作不可執行,將其進行彙總,交給切換決策。

切換決策:確定切換的時間決策,什麼情況下從機就應該升級為主機,是進程不存在,是寫操作不可行,連續檢測多少失敗次就進行切換。

應該選擇哪一個從節點升級為主節點,一般來說或應該選同步步驟最大的從節點來進行升級。切換是自動切換還是半自動切換,通過報警方式,讓人工做一次確認。

數據丟失和數據衝突:數據寫到主機,還沒有複製到從機,主機就掛了,這個時候怎麼處理,這個也得考慮業務的方式,是要確保 CP 或 AP。

全面!一文理解微服務高可用的常用手段

還要考慮一個數據衝突的問題,這個問題在 MySQL 中大部分是由自增主鍵引起。

就算不考慮自增主鍵會引起數據衝突的問題,其實自增主鍵還要引起很多的問題,這裡不細說,避免使用自增主鍵。

③數據分片

上述的數據冗餘可以通過數據的複製來進行解決,但是數據的擴張需要通過數據的分片來進行解決(如果在關係型數據庫是分表)。

"

高可用並不是一套整體解決方案,而是由諸多環節組成,一環扣一環,鬼知道為了這些串聯起來的環節,我得出多少張牌去應對,才能最終組成一個整個系統的高可用落地方案。

全面!一文理解微服務高可用的常用手段

圖片來自 Pexels

什麼是高可用

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

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

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

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

為什麼需要高可用

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

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

高可用的評價緯度

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

全面!一文理解微服務高可用的常用手段

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

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

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

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

微服務高可用設計手段

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

全面!一文理解微服務高可用的常用手段

這中間將會出現的細節是多種多樣的,所以我們需要對這樣一個微服務高可用方案進行一個頂層的設計,圍繞服務高可用,先檢查下我們手裡有多少張牌。

服務冗餘

全面!一文理解微服務高可用的常用手段

①冗餘策略

每一個訪問可能都會有多個服務組合而成,每個機器每個服務都可能出現問題,所以第一個考慮到的就是每個服務必須不止一份可以是多份。

所謂多份一致的服務就是服務的冗餘,這裡說的服務泛指了機器的服務,容器的服務,還有微服務本身的服務。

在機器服務層面需要考慮,各個機器間的冗餘是否有在物理空間進行隔離冗餘。

例如是否所有機器分別部署在不同機房,如果在同一個機房是否做到了部署在不同的機櫃,如果是 Docker 容器是否部署在分別不同的物理機上面。

採取的策略其實也還是根據服務的業務而定,所以需要對服務進行分級評分,從而採取不同的策略。

不同的策略安全程度不同,伴隨著的成本也是不同,安全等級更高的服務可能還不止考慮不同機房,還需要把各個機房所處的區域考慮進行。

例如,兩個機房不要處在同一個地震帶上等等。

全面!一文理解微服務高可用的常用手段

②無狀態化

服務的冗餘會要求我們可以隨時對服務進行擴容或者縮容,有可能我們會從 2 臺機器變成 3 臺機器。

想要對服務進行隨時隨地的擴縮容,就要求我們的服務是一個無狀態化,所謂無狀態化就是每個服務的服務內容和數據都是一致的。

例如,從我們的微服務架構來看,我們總共分水平劃分了好幾個層,正因為我們每個層都做到了無狀態,所以在這個水平架構的擴張是非常的簡單。

假設,我們需要對網關進行擴容,我們只需要增加服務就可以,而不需要去考慮網關是否存儲了一個額外的數據。

全面!一文理解微服務高可用的常用手段

網關不保存任何的 Session 數據,不提供會造成一致性的服務,將不一致的數據進行幾種存儲,藉助更加擅長數據同步的中間件來完成。

這個是目前主流的方案,服務本身儘可能提供邏輯的服務,將數據的一致性保證集中式處理,這樣就可以把“狀態”抽取出來,讓網關保持一個“無狀態”。

這裡僅僅是舉了網關的例子,在微服務基本所有的服務,都應該按照這種思路去做。

如果服務中有狀態,就應該把狀態抽取出來,讓更加擅長處理數據的組件來處理,而不是在微服務中去兼容有數據的狀態。

數據存儲高可用

全面!一文理解微服務高可用的常用手段

之前上面說的服務冗餘,可以簡單的理解為計算的高可用,計算高可用只需要做到無狀態既可簡單的擴容縮容,但是對於需要存儲數據的系統來說,數據本身就是有狀態。

跟存儲與計算相比,有一個本質的差別:將數據從一臺機器搬到另一臺機器,需要經過線路進行傳輸。

網絡是不穩定的,特別是跨機房的網絡,Ping 的延時可能是幾十幾百毫秒,雖然毫秒對於人來說幾乎沒有什麼感覺,但是對於高可用系統來說,就是本質上的不同,這意味著整個系統在某個時間點上,數據肯定是不一致的。

按照“數據+邏輯=業務”的公式來看,數據不一致,邏輯一致,最後的業務表現也會不一致。

舉個例子:

全面!一文理解微服務高可用的常用手段

無論是正常情況下的傳輸延時,還是異常情況下的傳輸中斷,都會導致系統的數據在某個時間點出現不一致。

而數據的不一致又會導致業務出現問題,但是如果數據不做冗餘,系統的高可用無法保證。

所以,存儲高可用的難點不在於怎麼備份數據,而在於如何減少或者規避數據不一致對業務造成的影響。

分佈式領域中有一個著名的 CAP 定理,從理論上論證了存儲高可用的複雜度,也就是說,存儲高可用不可能同時滿足“一致性,可用性,分區容錯性”。

最多隻能滿足 2 個,其中分區容錯在分佈式中是必須的,就意味著,我們在做架構設計時必須結合業務對一致性和可用性進行取捨。

存儲高可用方案的本質是將數據複製到多個存儲設備中,通過數據冗餘的方式來實現高可用,其複雜度主要呈現在數據複製的延遲或中斷導致數據的不一致性。

我們在設計存儲架構時必須考慮到以下幾個方面:

  • 數據怎麼進行復制

  • 架構中每個節點的職責是什麼

  • 數據複製出現延遲怎麼處理

  • 當架構中節點出現錯誤怎麼保證高可用

①數據主從複製

主從複製是最常見的也是最簡單的存儲高可用方案,例如 MySQL,Redis 等等。

全面!一文理解微服務高可用的常用手段

其架構的優點就是簡單,主機複製寫和讀,而從機只負責讀操作,在讀併發高時候可用擴張從庫的數量減低壓力,主機出現故障,讀操作也可以保證讀業務的順利進行。

缺點就是客戶端必須感知主從關係的存在,將不同的操作發送給不同的機器進行處理。

而且主從複製中,從機器負責讀操作,可能因為主從複製時延大,出現數據不一致性的問題。

②數據主從切換

剛說了主從切換存在兩個問題:

  • 主機故障寫操作無法進行。

  • 需要人工將其中一臺從機器升級為主機。

為了解決這個兩個問題,我們可以設計一套主從自動切換的方案,其中涉及到對主機的狀態檢測,切換的決策,數據丟失和衝突的問題。

主機狀態檢測:需要多個檢查點來檢測主機的機器是否正常,進程是否存在,是否出現超時,是否寫操作不可執行,是否讀操作不可執行,將其進行彙總,交給切換決策。

切換決策:確定切換的時間決策,什麼情況下從機就應該升級為主機,是進程不存在,是寫操作不可行,連續檢測多少失敗次就進行切換。

應該選擇哪一個從節點升級為主節點,一般來說或應該選同步步驟最大的從節點來進行升級。切換是自動切換還是半自動切換,通過報警方式,讓人工做一次確認。

數據丟失和數據衝突:數據寫到主機,還沒有複製到從機,主機就掛了,這個時候怎麼處理,這個也得考慮業務的方式,是要確保 CP 或 AP。

全面!一文理解微服務高可用的常用手段

還要考慮一個數據衝突的問題,這個問題在 MySQL 中大部分是由自增主鍵引起。

就算不考慮自增主鍵會引起數據衝突的問題,其實自增主鍵還要引起很多的問題,這裡不細說,避免使用自增主鍵。

③數據分片

上述的數據冗餘可以通過數據的複製來進行解決,但是數據的擴張需要通過數據的分片來進行解決(如果在關係型數據庫是分表)。

全面!一文理解微服務高可用的常用手段

何為數據分片(Segment,Fragment, Shard, Partition),就是按照一定的規則,將數據集劃分成相互獨立、正交的數據子集,然後將數據子集分佈到不同的節點上。

HDFS , MongoDB 的 Sharding 模式也基本是基於這種分片的模式去實現。

我們在設計分片主要考慮到的點是:

  • 做數據分片,如何將數據映射到節點。

  • 數據分片的特徵值,即按照數據中的哪一個屬性(字段)來分片。

  • 數據分片的元數據的管理,如何保證元數據服務器的高性能、高可用,如果是一組服務器,如何保證強一致性。

柔性化/異步化

"

高可用並不是一套整體解決方案,而是由諸多環節組成,一環扣一環,鬼知道為了這些串聯起來的環節,我得出多少張牌去應對,才能最終組成一個整個系統的高可用落地方案。

全面!一文理解微服務高可用的常用手段

圖片來自 Pexels

什麼是高可用

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

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

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

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

為什麼需要高可用

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

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

高可用的評價緯度

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

全面!一文理解微服務高可用的常用手段

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

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

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

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

微服務高可用設計手段

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

全面!一文理解微服務高可用的常用手段

這中間將會出現的細節是多種多樣的,所以我們需要對這樣一個微服務高可用方案進行一個頂層的設計,圍繞服務高可用,先檢查下我們手裡有多少張牌。

服務冗餘

全面!一文理解微服務高可用的常用手段

①冗餘策略

每一個訪問可能都會有多個服務組合而成,每個機器每個服務都可能出現問題,所以第一個考慮到的就是每個服務必須不止一份可以是多份。

所謂多份一致的服務就是服務的冗餘,這裡說的服務泛指了機器的服務,容器的服務,還有微服務本身的服務。

在機器服務層面需要考慮,各個機器間的冗餘是否有在物理空間進行隔離冗餘。

例如是否所有機器分別部署在不同機房,如果在同一個機房是否做到了部署在不同的機櫃,如果是 Docker 容器是否部署在分別不同的物理機上面。

採取的策略其實也還是根據服務的業務而定,所以需要對服務進行分級評分,從而採取不同的策略。

不同的策略安全程度不同,伴隨著的成本也是不同,安全等級更高的服務可能還不止考慮不同機房,還需要把各個機房所處的區域考慮進行。

例如,兩個機房不要處在同一個地震帶上等等。

全面!一文理解微服務高可用的常用手段

②無狀態化

服務的冗餘會要求我們可以隨時對服務進行擴容或者縮容,有可能我們會從 2 臺機器變成 3 臺機器。

想要對服務進行隨時隨地的擴縮容,就要求我們的服務是一個無狀態化,所謂無狀態化就是每個服務的服務內容和數據都是一致的。

例如,從我們的微服務架構來看,我們總共分水平劃分了好幾個層,正因為我們每個層都做到了無狀態,所以在這個水平架構的擴張是非常的簡單。

假設,我們需要對網關進行擴容,我們只需要增加服務就可以,而不需要去考慮網關是否存儲了一個額外的數據。

全面!一文理解微服務高可用的常用手段

網關不保存任何的 Session 數據,不提供會造成一致性的服務,將不一致的數據進行幾種存儲,藉助更加擅長數據同步的中間件來完成。

這個是目前主流的方案,服務本身儘可能提供邏輯的服務,將數據的一致性保證集中式處理,這樣就可以把“狀態”抽取出來,讓網關保持一個“無狀態”。

這裡僅僅是舉了網關的例子,在微服務基本所有的服務,都應該按照這種思路去做。

如果服務中有狀態,就應該把狀態抽取出來,讓更加擅長處理數據的組件來處理,而不是在微服務中去兼容有數據的狀態。

數據存儲高可用

全面!一文理解微服務高可用的常用手段

之前上面說的服務冗餘,可以簡單的理解為計算的高可用,計算高可用只需要做到無狀態既可簡單的擴容縮容,但是對於需要存儲數據的系統來說,數據本身就是有狀態。

跟存儲與計算相比,有一個本質的差別:將數據從一臺機器搬到另一臺機器,需要經過線路進行傳輸。

網絡是不穩定的,特別是跨機房的網絡,Ping 的延時可能是幾十幾百毫秒,雖然毫秒對於人來說幾乎沒有什麼感覺,但是對於高可用系統來說,就是本質上的不同,這意味著整個系統在某個時間點上,數據肯定是不一致的。

按照“數據+邏輯=業務”的公式來看,數據不一致,邏輯一致,最後的業務表現也會不一致。

舉個例子:

全面!一文理解微服務高可用的常用手段

無論是正常情況下的傳輸延時,還是異常情況下的傳輸中斷,都會導致系統的數據在某個時間點出現不一致。

而數據的不一致又會導致業務出現問題,但是如果數據不做冗餘,系統的高可用無法保證。

所以,存儲高可用的難點不在於怎麼備份數據,而在於如何減少或者規避數據不一致對業務造成的影響。

分佈式領域中有一個著名的 CAP 定理,從理論上論證了存儲高可用的複雜度,也就是說,存儲高可用不可能同時滿足“一致性,可用性,分區容錯性”。

最多隻能滿足 2 個,其中分區容錯在分佈式中是必須的,就意味著,我們在做架構設計時必須結合業務對一致性和可用性進行取捨。

存儲高可用方案的本質是將數據複製到多個存儲設備中,通過數據冗餘的方式來實現高可用,其複雜度主要呈現在數據複製的延遲或中斷導致數據的不一致性。

我們在設計存儲架構時必須考慮到以下幾個方面:

  • 數據怎麼進行復制

  • 架構中每個節點的職責是什麼

  • 數據複製出現延遲怎麼處理

  • 當架構中節點出現錯誤怎麼保證高可用

①數據主從複製

主從複製是最常見的也是最簡單的存儲高可用方案,例如 MySQL,Redis 等等。

全面!一文理解微服務高可用的常用手段

其架構的優點就是簡單,主機複製寫和讀,而從機只負責讀操作,在讀併發高時候可用擴張從庫的數量減低壓力,主機出現故障,讀操作也可以保證讀業務的順利進行。

缺點就是客戶端必須感知主從關係的存在,將不同的操作發送給不同的機器進行處理。

而且主從複製中,從機器負責讀操作,可能因為主從複製時延大,出現數據不一致性的問題。

②數據主從切換

剛說了主從切換存在兩個問題:

  • 主機故障寫操作無法進行。

  • 需要人工將其中一臺從機器升級為主機。

為了解決這個兩個問題,我們可以設計一套主從自動切換的方案,其中涉及到對主機的狀態檢測,切換的決策,數據丟失和衝突的問題。

主機狀態檢測:需要多個檢查點來檢測主機的機器是否正常,進程是否存在,是否出現超時,是否寫操作不可執行,是否讀操作不可執行,將其進行彙總,交給切換決策。

切換決策:確定切換的時間決策,什麼情況下從機就應該升級為主機,是進程不存在,是寫操作不可行,連續檢測多少失敗次就進行切換。

應該選擇哪一個從節點升級為主節點,一般來說或應該選同步步驟最大的從節點來進行升級。切換是自動切換還是半自動切換,通過報警方式,讓人工做一次確認。

數據丟失和數據衝突:數據寫到主機,還沒有複製到從機,主機就掛了,這個時候怎麼處理,這個也得考慮業務的方式,是要確保 CP 或 AP。

全面!一文理解微服務高可用的常用手段

還要考慮一個數據衝突的問題,這個問題在 MySQL 中大部分是由自增主鍵引起。

就算不考慮自增主鍵會引起數據衝突的問題,其實自增主鍵還要引起很多的問題,這裡不細說,避免使用自增主鍵。

③數據分片

上述的數據冗餘可以通過數據的複製來進行解決,但是數據的擴張需要通過數據的分片來進行解決(如果在關係型數據庫是分表)。

全面!一文理解微服務高可用的常用手段

何為數據分片(Segment,Fragment, Shard, Partition),就是按照一定的規則,將數據集劃分成相互獨立、正交的數據子集,然後將數據子集分佈到不同的節點上。

HDFS , MongoDB 的 Sharding 模式也基本是基於這種分片的模式去實現。

我們在設計分片主要考慮到的點是:

  • 做數據分片,如何將數據映射到節點。

  • 數據分片的特徵值,即按照數據中的哪一個屬性(字段)來分片。

  • 數據分片的元數據的管理,如何保證元數據服務器的高性能、高可用,如果是一組服務器,如何保證強一致性。

柔性化/異步化

全面!一文理解微服務高可用的常用手段

①異步化

在每一次調用,時間越長存在超時的風險就越大,邏輯越複雜執行的步驟越多,存在失敗的風險也就越大。

如果在業務允許的情況下,用戶調用只給用戶必須要的結果,而不是需要同步的結果可以放在另外的地方異步去操作,這就減少了超時的風險也把複雜業務進行拆分減低複雜度。

當然異步化的好處是非常多,例如削峰解耦等等,這裡只是從可用的角度出發。

異步化大致有這三種的實現方式:

  • 服務端接收到請求後,創建新的線程處理業務邏輯,服務端先回應答給客戶端

"

高可用並不是一套整體解決方案,而是由諸多環節組成,一環扣一環,鬼知道為了這些串聯起來的環節,我得出多少張牌去應對,才能最終組成一個整個系統的高可用落地方案。

全面!一文理解微服務高可用的常用手段

圖片來自 Pexels

什麼是高可用

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

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

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

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

為什麼需要高可用

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

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

高可用的評價緯度

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

全面!一文理解微服務高可用的常用手段

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

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

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

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

微服務高可用設計手段

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

全面!一文理解微服務高可用的常用手段

這中間將會出現的細節是多種多樣的,所以我們需要對這樣一個微服務高可用方案進行一個頂層的設計,圍繞服務高可用,先檢查下我們手裡有多少張牌。

服務冗餘

全面!一文理解微服務高可用的常用手段

①冗餘策略

每一個訪問可能都會有多個服務組合而成,每個機器每個服務都可能出現問題,所以第一個考慮到的就是每個服務必須不止一份可以是多份。

所謂多份一致的服務就是服務的冗餘,這裡說的服務泛指了機器的服務,容器的服務,還有微服務本身的服務。

在機器服務層面需要考慮,各個機器間的冗餘是否有在物理空間進行隔離冗餘。

例如是否所有機器分別部署在不同機房,如果在同一個機房是否做到了部署在不同的機櫃,如果是 Docker 容器是否部署在分別不同的物理機上面。

採取的策略其實也還是根據服務的業務而定,所以需要對服務進行分級評分,從而採取不同的策略。

不同的策略安全程度不同,伴隨著的成本也是不同,安全等級更高的服務可能還不止考慮不同機房,還需要把各個機房所處的區域考慮進行。

例如,兩個機房不要處在同一個地震帶上等等。

全面!一文理解微服務高可用的常用手段

②無狀態化

服務的冗餘會要求我們可以隨時對服務進行擴容或者縮容,有可能我們會從 2 臺機器變成 3 臺機器。

想要對服務進行隨時隨地的擴縮容,就要求我們的服務是一個無狀態化,所謂無狀態化就是每個服務的服務內容和數據都是一致的。

例如,從我們的微服務架構來看,我們總共分水平劃分了好幾個層,正因為我們每個層都做到了無狀態,所以在這個水平架構的擴張是非常的簡單。

假設,我們需要對網關進行擴容,我們只需要增加服務就可以,而不需要去考慮網關是否存儲了一個額外的數據。

全面!一文理解微服務高可用的常用手段

網關不保存任何的 Session 數據,不提供會造成一致性的服務,將不一致的數據進行幾種存儲,藉助更加擅長數據同步的中間件來完成。

這個是目前主流的方案,服務本身儘可能提供邏輯的服務,將數據的一致性保證集中式處理,這樣就可以把“狀態”抽取出來,讓網關保持一個“無狀態”。

這裡僅僅是舉了網關的例子,在微服務基本所有的服務,都應該按照這種思路去做。

如果服務中有狀態,就應該把狀態抽取出來,讓更加擅長處理數據的組件來處理,而不是在微服務中去兼容有數據的狀態。

數據存儲高可用

全面!一文理解微服務高可用的常用手段

之前上面說的服務冗餘,可以簡單的理解為計算的高可用,計算高可用只需要做到無狀態既可簡單的擴容縮容,但是對於需要存儲數據的系統來說,數據本身就是有狀態。

跟存儲與計算相比,有一個本質的差別:將數據從一臺機器搬到另一臺機器,需要經過線路進行傳輸。

網絡是不穩定的,特別是跨機房的網絡,Ping 的延時可能是幾十幾百毫秒,雖然毫秒對於人來說幾乎沒有什麼感覺,但是對於高可用系統來說,就是本質上的不同,這意味著整個系統在某個時間點上,數據肯定是不一致的。

按照“數據+邏輯=業務”的公式來看,數據不一致,邏輯一致,最後的業務表現也會不一致。

舉個例子:

全面!一文理解微服務高可用的常用手段

無論是正常情況下的傳輸延時,還是異常情況下的傳輸中斷,都會導致系統的數據在某個時間點出現不一致。

而數據的不一致又會導致業務出現問題,但是如果數據不做冗餘,系統的高可用無法保證。

所以,存儲高可用的難點不在於怎麼備份數據,而在於如何減少或者規避數據不一致對業務造成的影響。

分佈式領域中有一個著名的 CAP 定理,從理論上論證了存儲高可用的複雜度,也就是說,存儲高可用不可能同時滿足“一致性,可用性,分區容錯性”。

最多隻能滿足 2 個,其中分區容錯在分佈式中是必須的,就意味著,我們在做架構設計時必須結合業務對一致性和可用性進行取捨。

存儲高可用方案的本質是將數據複製到多個存儲設備中,通過數據冗餘的方式來實現高可用,其複雜度主要呈現在數據複製的延遲或中斷導致數據的不一致性。

我們在設計存儲架構時必須考慮到以下幾個方面:

  • 數據怎麼進行復制

  • 架構中每個節點的職責是什麼

  • 數據複製出現延遲怎麼處理

  • 當架構中節點出現錯誤怎麼保證高可用

①數據主從複製

主從複製是最常見的也是最簡單的存儲高可用方案,例如 MySQL,Redis 等等。

全面!一文理解微服務高可用的常用手段

其架構的優點就是簡單,主機複製寫和讀,而從機只負責讀操作,在讀併發高時候可用擴張從庫的數量減低壓力,主機出現故障,讀操作也可以保證讀業務的順利進行。

缺點就是客戶端必須感知主從關係的存在,將不同的操作發送給不同的機器進行處理。

而且主從複製中,從機器負責讀操作,可能因為主從複製時延大,出現數據不一致性的問題。

②數據主從切換

剛說了主從切換存在兩個問題:

  • 主機故障寫操作無法進行。

  • 需要人工將其中一臺從機器升級為主機。

為了解決這個兩個問題,我們可以設計一套主從自動切換的方案,其中涉及到對主機的狀態檢測,切換的決策,數據丟失和衝突的問題。

主機狀態檢測:需要多個檢查點來檢測主機的機器是否正常,進程是否存在,是否出現超時,是否寫操作不可執行,是否讀操作不可執行,將其進行彙總,交給切換決策。

切換決策:確定切換的時間決策,什麼情況下從機就應該升級為主機,是進程不存在,是寫操作不可行,連續檢測多少失敗次就進行切換。

應該選擇哪一個從節點升級為主節點,一般來說或應該選同步步驟最大的從節點來進行升級。切換是自動切換還是半自動切換,通過報警方式,讓人工做一次確認。

數據丟失和數據衝突:數據寫到主機,還沒有複製到從機,主機就掛了,這個時候怎麼處理,這個也得考慮業務的方式,是要確保 CP 或 AP。

全面!一文理解微服務高可用的常用手段

還要考慮一個數據衝突的問題,這個問題在 MySQL 中大部分是由自增主鍵引起。

就算不考慮自增主鍵會引起數據衝突的問題,其實自增主鍵還要引起很多的問題,這裡不細說,避免使用自增主鍵。

③數據分片

上述的數據冗餘可以通過數據的複製來進行解決,但是數據的擴張需要通過數據的分片來進行解決(如果在關係型數據庫是分表)。

全面!一文理解微服務高可用的常用手段

何為數據分片(Segment,Fragment, Shard, Partition),就是按照一定的規則,將數據集劃分成相互獨立、正交的數據子集,然後將數據子集分佈到不同的節點上。

HDFS , MongoDB 的 Sharding 模式也基本是基於這種分片的模式去實現。

我們在設計分片主要考慮到的點是:

  • 做數據分片,如何將數據映射到節點。

  • 數據分片的特徵值,即按照數據中的哪一個屬性(字段)來分片。

  • 數據分片的元數據的管理,如何保證元數據服務器的高性能、高可用,如果是一組服務器,如何保證強一致性。

柔性化/異步化

全面!一文理解微服務高可用的常用手段

①異步化

在每一次調用,時間越長存在超時的風險就越大,邏輯越複雜執行的步驟越多,存在失敗的風險也就越大。

如果在業務允許的情況下,用戶調用只給用戶必須要的結果,而不是需要同步的結果可以放在另外的地方異步去操作,這就減少了超時的風險也把複雜業務進行拆分減低複雜度。

當然異步化的好處是非常多,例如削峰解耦等等,這裡只是從可用的角度出發。

異步化大致有這三種的實現方式:

  • 服務端接收到請求後,創建新的線程處理業務邏輯,服務端先回應答給客戶端

全面!一文理解微服務高可用的常用手段
  • 服務端接收到請求後,服務端先回應答給客戶端,再繼續處理業務邏輯。

"

高可用並不是一套整體解決方案,而是由諸多環節組成,一環扣一環,鬼知道為了這些串聯起來的環節,我得出多少張牌去應對,才能最終組成一個整個系統的高可用落地方案。

全面!一文理解微服務高可用的常用手段

圖片來自 Pexels

什麼是高可用

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

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

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

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

為什麼需要高可用

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

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

高可用的評價緯度

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

全面!一文理解微服務高可用的常用手段

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

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

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

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

微服務高可用設計手段

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

全面!一文理解微服務高可用的常用手段

這中間將會出現的細節是多種多樣的,所以我們需要對這樣一個微服務高可用方案進行一個頂層的設計,圍繞服務高可用,先檢查下我們手裡有多少張牌。

服務冗餘

全面!一文理解微服務高可用的常用手段

①冗餘策略

每一個訪問可能都會有多個服務組合而成,每個機器每個服務都可能出現問題,所以第一個考慮到的就是每個服務必須不止一份可以是多份。

所謂多份一致的服務就是服務的冗餘,這裡說的服務泛指了機器的服務,容器的服務,還有微服務本身的服務。

在機器服務層面需要考慮,各個機器間的冗餘是否有在物理空間進行隔離冗餘。

例如是否所有機器分別部署在不同機房,如果在同一個機房是否做到了部署在不同的機櫃,如果是 Docker 容器是否部署在分別不同的物理機上面。

採取的策略其實也還是根據服務的業務而定,所以需要對服務進行分級評分,從而採取不同的策略。

不同的策略安全程度不同,伴隨著的成本也是不同,安全等級更高的服務可能還不止考慮不同機房,還需要把各個機房所處的區域考慮進行。

例如,兩個機房不要處在同一個地震帶上等等。

全面!一文理解微服務高可用的常用手段

②無狀態化

服務的冗餘會要求我們可以隨時對服務進行擴容或者縮容,有可能我們會從 2 臺機器變成 3 臺機器。

想要對服務進行隨時隨地的擴縮容,就要求我們的服務是一個無狀態化,所謂無狀態化就是每個服務的服務內容和數據都是一致的。

例如,從我們的微服務架構來看,我們總共分水平劃分了好幾個層,正因為我們每個層都做到了無狀態,所以在這個水平架構的擴張是非常的簡單。

假設,我們需要對網關進行擴容,我們只需要增加服務就可以,而不需要去考慮網關是否存儲了一個額外的數據。

全面!一文理解微服務高可用的常用手段

網關不保存任何的 Session 數據,不提供會造成一致性的服務,將不一致的數據進行幾種存儲,藉助更加擅長數據同步的中間件來完成。

這個是目前主流的方案,服務本身儘可能提供邏輯的服務,將數據的一致性保證集中式處理,這樣就可以把“狀態”抽取出來,讓網關保持一個“無狀態”。

這裡僅僅是舉了網關的例子,在微服務基本所有的服務,都應該按照這種思路去做。

如果服務中有狀態,就應該把狀態抽取出來,讓更加擅長處理數據的組件來處理,而不是在微服務中去兼容有數據的狀態。

數據存儲高可用

全面!一文理解微服務高可用的常用手段

之前上面說的服務冗餘,可以簡單的理解為計算的高可用,計算高可用只需要做到無狀態既可簡單的擴容縮容,但是對於需要存儲數據的系統來說,數據本身就是有狀態。

跟存儲與計算相比,有一個本質的差別:將數據從一臺機器搬到另一臺機器,需要經過線路進行傳輸。

網絡是不穩定的,特別是跨機房的網絡,Ping 的延時可能是幾十幾百毫秒,雖然毫秒對於人來說幾乎沒有什麼感覺,但是對於高可用系統來說,就是本質上的不同,這意味著整個系統在某個時間點上,數據肯定是不一致的。

按照“數據+邏輯=業務”的公式來看,數據不一致,邏輯一致,最後的業務表現也會不一致。

舉個例子:

全面!一文理解微服務高可用的常用手段

無論是正常情況下的傳輸延時,還是異常情況下的傳輸中斷,都會導致系統的數據在某個時間點出現不一致。

而數據的不一致又會導致業務出現問題,但是如果數據不做冗餘,系統的高可用無法保證。

所以,存儲高可用的難點不在於怎麼備份數據,而在於如何減少或者規避數據不一致對業務造成的影響。

分佈式領域中有一個著名的 CAP 定理,從理論上論證了存儲高可用的複雜度,也就是說,存儲高可用不可能同時滿足“一致性,可用性,分區容錯性”。

最多隻能滿足 2 個,其中分區容錯在分佈式中是必須的,就意味著,我們在做架構設計時必須結合業務對一致性和可用性進行取捨。

存儲高可用方案的本質是將數據複製到多個存儲設備中,通過數據冗餘的方式來實現高可用,其複雜度主要呈現在數據複製的延遲或中斷導致數據的不一致性。

我們在設計存儲架構時必須考慮到以下幾個方面:

  • 數據怎麼進行復制

  • 架構中每個節點的職責是什麼

  • 數據複製出現延遲怎麼處理

  • 當架構中節點出現錯誤怎麼保證高可用

①數據主從複製

主從複製是最常見的也是最簡單的存儲高可用方案,例如 MySQL,Redis 等等。

全面!一文理解微服務高可用的常用手段

其架構的優點就是簡單,主機複製寫和讀,而從機只負責讀操作,在讀併發高時候可用擴張從庫的數量減低壓力,主機出現故障,讀操作也可以保證讀業務的順利進行。

缺點就是客戶端必須感知主從關係的存在,將不同的操作發送給不同的機器進行處理。

而且主從複製中,從機器負責讀操作,可能因為主從複製時延大,出現數據不一致性的問題。

②數據主從切換

剛說了主從切換存在兩個問題:

  • 主機故障寫操作無法進行。

  • 需要人工將其中一臺從機器升級為主機。

為了解決這個兩個問題,我們可以設計一套主從自動切換的方案,其中涉及到對主機的狀態檢測,切換的決策,數據丟失和衝突的問題。

主機狀態檢測:需要多個檢查點來檢測主機的機器是否正常,進程是否存在,是否出現超時,是否寫操作不可執行,是否讀操作不可執行,將其進行彙總,交給切換決策。

切換決策:確定切換的時間決策,什麼情況下從機就應該升級為主機,是進程不存在,是寫操作不可行,連續檢測多少失敗次就進行切換。

應該選擇哪一個從節點升級為主節點,一般來說或應該選同步步驟最大的從節點來進行升級。切換是自動切換還是半自動切換,通過報警方式,讓人工做一次確認。

數據丟失和數據衝突:數據寫到主機,還沒有複製到從機,主機就掛了,這個時候怎麼處理,這個也得考慮業務的方式,是要確保 CP 或 AP。

全面!一文理解微服務高可用的常用手段

還要考慮一個數據衝突的問題,這個問題在 MySQL 中大部分是由自增主鍵引起。

就算不考慮自增主鍵會引起數據衝突的問題,其實自增主鍵還要引起很多的問題,這裡不細說,避免使用自增主鍵。

③數據分片

上述的數據冗餘可以通過數據的複製來進行解決,但是數據的擴張需要通過數據的分片來進行解決(如果在關係型數據庫是分表)。

全面!一文理解微服務高可用的常用手段

何為數據分片(Segment,Fragment, Shard, Partition),就是按照一定的規則,將數據集劃分成相互獨立、正交的數據子集,然後將數據子集分佈到不同的節點上。

HDFS , MongoDB 的 Sharding 模式也基本是基於這種分片的模式去實現。

我們在設計分片主要考慮到的點是:

  • 做數據分片,如何將數據映射到節點。

  • 數據分片的特徵值,即按照數據中的哪一個屬性(字段)來分片。

  • 數據分片的元數據的管理,如何保證元數據服務器的高性能、高可用,如果是一組服務器,如何保證強一致性。

柔性化/異步化

全面!一文理解微服務高可用的常用手段

①異步化

在每一次調用,時間越長存在超時的風險就越大,邏輯越複雜執行的步驟越多,存在失敗的風險也就越大。

如果在業務允許的情況下,用戶調用只給用戶必須要的結果,而不是需要同步的結果可以放在另外的地方異步去操作,這就減少了超時的風險也把複雜業務進行拆分減低複雜度。

當然異步化的好處是非常多,例如削峰解耦等等,這裡只是從可用的角度出發。

異步化大致有這三種的實現方式:

  • 服務端接收到請求後,創建新的線程處理業務邏輯,服務端先回應答給客戶端

全面!一文理解微服務高可用的常用手段
  • 服務端接收到請求後,服務端先回應答給客戶端,再繼續處理業務邏輯。

全面!一文理解微服務高可用的常用手段
  • 服務端接收到請求後,服務端把信息保存在消息隊列或者數據庫,迴應答給客戶端,服務端業務處理進程再從消息隊列或者數據庫上讀取信息處理業務邏輯。

"

高可用並不是一套整體解決方案,而是由諸多環節組成,一環扣一環,鬼知道為了這些串聯起來的環節,我得出多少張牌去應對,才能最終組成一個整個系統的高可用落地方案。

全面!一文理解微服務高可用的常用手段

圖片來自 Pexels

什麼是高可用

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

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

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

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

為什麼需要高可用

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

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

高可用的評價緯度

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

全面!一文理解微服務高可用的常用手段

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

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

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

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

微服務高可用設計手段

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

全面!一文理解微服務高可用的常用手段

這中間將會出現的細節是多種多樣的,所以我們需要對這樣一個微服務高可用方案進行一個頂層的設計,圍繞服務高可用,先檢查下我們手裡有多少張牌。

服務冗餘

全面!一文理解微服務高可用的常用手段

①冗餘策略

每一個訪問可能都會有多個服務組合而成,每個機器每個服務都可能出現問題,所以第一個考慮到的就是每個服務必須不止一份可以是多份。

所謂多份一致的服務就是服務的冗餘,這裡說的服務泛指了機器的服務,容器的服務,還有微服務本身的服務。

在機器服務層面需要考慮,各個機器間的冗餘是否有在物理空間進行隔離冗餘。

例如是否所有機器分別部署在不同機房,如果在同一個機房是否做到了部署在不同的機櫃,如果是 Docker 容器是否部署在分別不同的物理機上面。

採取的策略其實也還是根據服務的業務而定,所以需要對服務進行分級評分,從而採取不同的策略。

不同的策略安全程度不同,伴隨著的成本也是不同,安全等級更高的服務可能還不止考慮不同機房,還需要把各個機房所處的區域考慮進行。

例如,兩個機房不要處在同一個地震帶上等等。

全面!一文理解微服務高可用的常用手段

②無狀態化

服務的冗餘會要求我們可以隨時對服務進行擴容或者縮容,有可能我們會從 2 臺機器變成 3 臺機器。

想要對服務進行隨時隨地的擴縮容,就要求我們的服務是一個無狀態化,所謂無狀態化就是每個服務的服務內容和數據都是一致的。

例如,從我們的微服務架構來看,我們總共分水平劃分了好幾個層,正因為我們每個層都做到了無狀態,所以在這個水平架構的擴張是非常的簡單。

假設,我們需要對網關進行擴容,我們只需要增加服務就可以,而不需要去考慮網關是否存儲了一個額外的數據。

全面!一文理解微服務高可用的常用手段

網關不保存任何的 Session 數據,不提供會造成一致性的服務,將不一致的數據進行幾種存儲,藉助更加擅長數據同步的中間件來完成。

這個是目前主流的方案,服務本身儘可能提供邏輯的服務,將數據的一致性保證集中式處理,這樣就可以把“狀態”抽取出來,讓網關保持一個“無狀態”。

這裡僅僅是舉了網關的例子,在微服務基本所有的服務,都應該按照這種思路去做。

如果服務中有狀態,就應該把狀態抽取出來,讓更加擅長處理數據的組件來處理,而不是在微服務中去兼容有數據的狀態。

數據存儲高可用

全面!一文理解微服務高可用的常用手段

之前上面說的服務冗餘,可以簡單的理解為計算的高可用,計算高可用只需要做到無狀態既可簡單的擴容縮容,但是對於需要存儲數據的系統來說,數據本身就是有狀態。

跟存儲與計算相比,有一個本質的差別:將數據從一臺機器搬到另一臺機器,需要經過線路進行傳輸。

網絡是不穩定的,特別是跨機房的網絡,Ping 的延時可能是幾十幾百毫秒,雖然毫秒對於人來說幾乎沒有什麼感覺,但是對於高可用系統來說,就是本質上的不同,這意味著整個系統在某個時間點上,數據肯定是不一致的。

按照“數據+邏輯=業務”的公式來看,數據不一致,邏輯一致,最後的業務表現也會不一致。

舉個例子:

全面!一文理解微服務高可用的常用手段

無論是正常情況下的傳輸延時,還是異常情況下的傳輸中斷,都會導致系統的數據在某個時間點出現不一致。

而數據的不一致又會導致業務出現問題,但是如果數據不做冗餘,系統的高可用無法保證。

所以,存儲高可用的難點不在於怎麼備份數據,而在於如何減少或者規避數據不一致對業務造成的影響。

分佈式領域中有一個著名的 CAP 定理,從理論上論證了存儲高可用的複雜度,也就是說,存儲高可用不可能同時滿足“一致性,可用性,分區容錯性”。

最多隻能滿足 2 個,其中分區容錯在分佈式中是必須的,就意味著,我們在做架構設計時必須結合業務對一致性和可用性進行取捨。

存儲高可用方案的本質是將數據複製到多個存儲設備中,通過數據冗餘的方式來實現高可用,其複雜度主要呈現在數據複製的延遲或中斷導致數據的不一致性。

我們在設計存儲架構時必須考慮到以下幾個方面:

  • 數據怎麼進行復制

  • 架構中每個節點的職責是什麼

  • 數據複製出現延遲怎麼處理

  • 當架構中節點出現錯誤怎麼保證高可用

①數據主從複製

主從複製是最常見的也是最簡單的存儲高可用方案,例如 MySQL,Redis 等等。

全面!一文理解微服務高可用的常用手段

其架構的優點就是簡單,主機複製寫和讀,而從機只負責讀操作,在讀併發高時候可用擴張從庫的數量減低壓力,主機出現故障,讀操作也可以保證讀業務的順利進行。

缺點就是客戶端必須感知主從關係的存在,將不同的操作發送給不同的機器進行處理。

而且主從複製中,從機器負責讀操作,可能因為主從複製時延大,出現數據不一致性的問題。

②數據主從切換

剛說了主從切換存在兩個問題:

  • 主機故障寫操作無法進行。

  • 需要人工將其中一臺從機器升級為主機。

為了解決這個兩個問題,我們可以設計一套主從自動切換的方案,其中涉及到對主機的狀態檢測,切換的決策,數據丟失和衝突的問題。

主機狀態檢測:需要多個檢查點來檢測主機的機器是否正常,進程是否存在,是否出現超時,是否寫操作不可執行,是否讀操作不可執行,將其進行彙總,交給切換決策。

切換決策:確定切換的時間決策,什麼情況下從機就應該升級為主機,是進程不存在,是寫操作不可行,連續檢測多少失敗次就進行切換。

應該選擇哪一個從節點升級為主節點,一般來說或應該選同步步驟最大的從節點來進行升級。切換是自動切換還是半自動切換,通過報警方式,讓人工做一次確認。

數據丟失和數據衝突:數據寫到主機,還沒有複製到從機,主機就掛了,這個時候怎麼處理,這個也得考慮業務的方式,是要確保 CP 或 AP。

全面!一文理解微服務高可用的常用手段

還要考慮一個數據衝突的問題,這個問題在 MySQL 中大部分是由自增主鍵引起。

就算不考慮自增主鍵會引起數據衝突的問題,其實自增主鍵還要引起很多的問題,這裡不細說,避免使用自增主鍵。

③數據分片

上述的數據冗餘可以通過數據的複製來進行解決,但是數據的擴張需要通過數據的分片來進行解決(如果在關係型數據庫是分表)。

全面!一文理解微服務高可用的常用手段

何為數據分片(Segment,Fragment, Shard, Partition),就是按照一定的規則,將數據集劃分成相互獨立、正交的數據子集,然後將數據子集分佈到不同的節點上。

HDFS , MongoDB 的 Sharding 模式也基本是基於這種分片的模式去實現。

我們在設計分片主要考慮到的點是:

  • 做數據分片,如何將數據映射到節點。

  • 數據分片的特徵值,即按照數據中的哪一個屬性(字段)來分片。

  • 數據分片的元數據的管理,如何保證元數據服務器的高性能、高可用,如果是一組服務器,如何保證強一致性。

柔性化/異步化

全面!一文理解微服務高可用的常用手段

①異步化

在每一次調用,時間越長存在超時的風險就越大,邏輯越複雜執行的步驟越多,存在失敗的風險也就越大。

如果在業務允許的情況下,用戶調用只給用戶必須要的結果,而不是需要同步的結果可以放在另外的地方異步去操作,這就減少了超時的風險也把複雜業務進行拆分減低複雜度。

當然異步化的好處是非常多,例如削峰解耦等等,這裡只是從可用的角度出發。

異步化大致有這三種的實現方式:

  • 服務端接收到請求後,創建新的線程處理業務邏輯,服務端先回應答給客戶端

全面!一文理解微服務高可用的常用手段
  • 服務端接收到請求後,服務端先回應答給客戶端,再繼續處理業務邏輯。

全面!一文理解微服務高可用的常用手段
  • 服務端接收到請求後,服務端把信息保存在消息隊列或者數據庫,迴應答給客戶端,服務端業務處理進程再從消息隊列或者數據庫上讀取信息處理業務邏輯。

全面!一文理解微服務高可用的常用手段

②柔性化

什麼是柔性化?想象一個場景,我們的系統會給每個下單的用戶增加他們下單金額對應的積分,當一個用戶下單完畢後,我們給他增加積分的服務出現了問題。

這個時候,我們是要取消掉這個訂單還是先讓訂單通過,積分的問題通過重新或者報警來處理呢?

所謂的柔性化,就是在我們業務中允許的情況下,做不到給予用戶百分百可用的,通過降級的手段給到用戶儘可能多的服務,而不是非得每次都交出去要麼 100 分或 0 分的答卷。

怎麼去做柔性化,更多其實是對業務的理解和判斷,柔性化更多是一種思維,需要對業務場景有深入的瞭解。

在電商訂單的場景中,下單,扣庫存,支付是一定要執行的步驟,如果失敗則訂單失敗。

"

高可用並不是一套整體解決方案,而是由諸多環節組成,一環扣一環,鬼知道為了這些串聯起來的環節,我得出多少張牌去應對,才能最終組成一個整個系統的高可用落地方案。

全面!一文理解微服務高可用的常用手段

圖片來自 Pexels

什麼是高可用

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

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

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

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

為什麼需要高可用

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

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

高可用的評價緯度

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

全面!一文理解微服務高可用的常用手段

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

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

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

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

微服務高可用設計手段

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

全面!一文理解微服務高可用的常用手段

這中間將會出現的細節是多種多樣的,所以我們需要對這樣一個微服務高可用方案進行一個頂層的設計,圍繞服務高可用,先檢查下我們手裡有多少張牌。

服務冗餘

全面!一文理解微服務高可用的常用手段

①冗餘策略

每一個訪問可能都會有多個服務組合而成,每個機器每個服務都可能出現問題,所以第一個考慮到的就是每個服務必須不止一份可以是多份。

所謂多份一致的服務就是服務的冗餘,這裡說的服務泛指了機器的服務,容器的服務,還有微服務本身的服務。

在機器服務層面需要考慮,各個機器間的冗餘是否有在物理空間進行隔離冗餘。

例如是否所有機器分別部署在不同機房,如果在同一個機房是否做到了部署在不同的機櫃,如果是 Docker 容器是否部署在分別不同的物理機上面。

採取的策略其實也還是根據服務的業務而定,所以需要對服務進行分級評分,從而採取不同的策略。

不同的策略安全程度不同,伴隨著的成本也是不同,安全等級更高的服務可能還不止考慮不同機房,還需要把各個機房所處的區域考慮進行。

例如,兩個機房不要處在同一個地震帶上等等。

全面!一文理解微服務高可用的常用手段

②無狀態化

服務的冗餘會要求我們可以隨時對服務進行擴容或者縮容,有可能我們會從 2 臺機器變成 3 臺機器。

想要對服務進行隨時隨地的擴縮容,就要求我們的服務是一個無狀態化,所謂無狀態化就是每個服務的服務內容和數據都是一致的。

例如,從我們的微服務架構來看,我們總共分水平劃分了好幾個層,正因為我們每個層都做到了無狀態,所以在這個水平架構的擴張是非常的簡單。

假設,我們需要對網關進行擴容,我們只需要增加服務就可以,而不需要去考慮網關是否存儲了一個額外的數據。

全面!一文理解微服務高可用的常用手段

網關不保存任何的 Session 數據,不提供會造成一致性的服務,將不一致的數據進行幾種存儲,藉助更加擅長數據同步的中間件來完成。

這個是目前主流的方案,服務本身儘可能提供邏輯的服務,將數據的一致性保證集中式處理,這樣就可以把“狀態”抽取出來,讓網關保持一個“無狀態”。

這裡僅僅是舉了網關的例子,在微服務基本所有的服務,都應該按照這種思路去做。

如果服務中有狀態,就應該把狀態抽取出來,讓更加擅長處理數據的組件來處理,而不是在微服務中去兼容有數據的狀態。

數據存儲高可用

全面!一文理解微服務高可用的常用手段

之前上面說的服務冗餘,可以簡單的理解為計算的高可用,計算高可用只需要做到無狀態既可簡單的擴容縮容,但是對於需要存儲數據的系統來說,數據本身就是有狀態。

跟存儲與計算相比,有一個本質的差別:將數據從一臺機器搬到另一臺機器,需要經過線路進行傳輸。

網絡是不穩定的,特別是跨機房的網絡,Ping 的延時可能是幾十幾百毫秒,雖然毫秒對於人來說幾乎沒有什麼感覺,但是對於高可用系統來說,就是本質上的不同,這意味著整個系統在某個時間點上,數據肯定是不一致的。

按照“數據+邏輯=業務”的公式來看,數據不一致,邏輯一致,最後的業務表現也會不一致。

舉個例子:

全面!一文理解微服務高可用的常用手段

無論是正常情況下的傳輸延時,還是異常情況下的傳輸中斷,都會導致系統的數據在某個時間點出現不一致。

而數據的不一致又會導致業務出現問題,但是如果數據不做冗餘,系統的高可用無法保證。

所以,存儲高可用的難點不在於怎麼備份數據,而在於如何減少或者規避數據不一致對業務造成的影響。

分佈式領域中有一個著名的 CAP 定理,從理論上論證了存儲高可用的複雜度,也就是說,存儲高可用不可能同時滿足“一致性,可用性,分區容錯性”。

最多隻能滿足 2 個,其中分區容錯在分佈式中是必須的,就意味著,我們在做架構設計時必須結合業務對一致性和可用性進行取捨。

存儲高可用方案的本質是將數據複製到多個存儲設備中,通過數據冗餘的方式來實現高可用,其複雜度主要呈現在數據複製的延遲或中斷導致數據的不一致性。

我們在設計存儲架構時必須考慮到以下幾個方面:

  • 數據怎麼進行復制

  • 架構中每個節點的職責是什麼

  • 數據複製出現延遲怎麼處理

  • 當架構中節點出現錯誤怎麼保證高可用

①數據主從複製

主從複製是最常見的也是最簡單的存儲高可用方案,例如 MySQL,Redis 等等。

全面!一文理解微服務高可用的常用手段

其架構的優點就是簡單,主機複製寫和讀,而從機只負責讀操作,在讀併發高時候可用擴張從庫的數量減低壓力,主機出現故障,讀操作也可以保證讀業務的順利進行。

缺點就是客戶端必須感知主從關係的存在,將不同的操作發送給不同的機器進行處理。

而且主從複製中,從機器負責讀操作,可能因為主從複製時延大,出現數據不一致性的問題。

②數據主從切換

剛說了主從切換存在兩個問題:

  • 主機故障寫操作無法進行。

  • 需要人工將其中一臺從機器升級為主機。

為了解決這個兩個問題,我們可以設計一套主從自動切換的方案,其中涉及到對主機的狀態檢測,切換的決策,數據丟失和衝突的問題。

主機狀態檢測:需要多個檢查點來檢測主機的機器是否正常,進程是否存在,是否出現超時,是否寫操作不可執行,是否讀操作不可執行,將其進行彙總,交給切換決策。

切換決策:確定切換的時間決策,什麼情況下從機就應該升級為主機,是進程不存在,是寫操作不可行,連續檢測多少失敗次就進行切換。

應該選擇哪一個從節點升級為主節點,一般來說或應該選同步步驟最大的從節點來進行升級。切換是自動切換還是半自動切換,通過報警方式,讓人工做一次確認。

數據丟失和數據衝突:數據寫到主機,還沒有複製到從機,主機就掛了,這個時候怎麼處理,這個也得考慮業務的方式,是要確保 CP 或 AP。

全面!一文理解微服務高可用的常用手段

還要考慮一個數據衝突的問題,這個問題在 MySQL 中大部分是由自增主鍵引起。

就算不考慮自增主鍵會引起數據衝突的問題,其實自增主鍵還要引起很多的問題,這裡不細說,避免使用自增主鍵。

③數據分片

上述的數據冗餘可以通過數據的複製來進行解決,但是數據的擴張需要通過數據的分片來進行解決(如果在關係型數據庫是分表)。

全面!一文理解微服務高可用的常用手段

何為數據分片(Segment,Fragment, Shard, Partition),就是按照一定的規則,將數據集劃分成相互獨立、正交的數據子集,然後將數據子集分佈到不同的節點上。

HDFS , MongoDB 的 Sharding 模式也基本是基於這種分片的模式去實現。

我們在設計分片主要考慮到的點是:

  • 做數據分片,如何將數據映射到節點。

  • 數據分片的特徵值,即按照數據中的哪一個屬性(字段)來分片。

  • 數據分片的元數據的管理,如何保證元數據服務器的高性能、高可用,如果是一組服務器,如何保證強一致性。

柔性化/異步化

全面!一文理解微服務高可用的常用手段

①異步化

在每一次調用,時間越長存在超時的風險就越大,邏輯越複雜執行的步驟越多,存在失敗的風險也就越大。

如果在業務允許的情況下,用戶調用只給用戶必須要的結果,而不是需要同步的結果可以放在另外的地方異步去操作,這就減少了超時的風險也把複雜業務進行拆分減低複雜度。

當然異步化的好處是非常多,例如削峰解耦等等,這裡只是從可用的角度出發。

異步化大致有這三種的實現方式:

  • 服務端接收到請求後,創建新的線程處理業務邏輯,服務端先回應答給客戶端

全面!一文理解微服務高可用的常用手段
  • 服務端接收到請求後,服務端先回應答給客戶端,再繼續處理業務邏輯。

全面!一文理解微服務高可用的常用手段
  • 服務端接收到請求後,服務端把信息保存在消息隊列或者數據庫,迴應答給客戶端,服務端業務處理進程再從消息隊列或者數據庫上讀取信息處理業務邏輯。

全面!一文理解微服務高可用的常用手段

②柔性化

什麼是柔性化?想象一個場景,我們的系統會給每個下單的用戶增加他們下單金額對應的積分,當一個用戶下單完畢後,我們給他增加積分的服務出現了問題。

這個時候,我們是要取消掉這個訂單還是先讓訂單通過,積分的問題通過重新或者報警來處理呢?

所謂的柔性化,就是在我們業務中允許的情況下,做不到給予用戶百分百可用的,通過降級的手段給到用戶儘可能多的服務,而不是非得每次都交出去要麼 100 分或 0 分的答卷。

怎麼去做柔性化,更多其實是對業務的理解和判斷,柔性化更多是一種思維,需要對業務場景有深入的瞭解。

在電商訂單的場景中,下單,扣庫存,支付是一定要執行的步驟,如果失敗則訂單失敗。

全面!一文理解微服務高可用的常用手段

但是加積分,發貨,售後是可以柔性處理,就算出錯也可以通過日誌報警讓人工去檢查,沒必要為加積分損失整個下單的可用性。

兜底/容錯

"

高可用並不是一套整體解決方案,而是由諸多環節組成,一環扣一環,鬼知道為了這些串聯起來的環節,我得出多少張牌去應對,才能最終組成一個整個系統的高可用落地方案。

全面!一文理解微服務高可用的常用手段

圖片來自 Pexels

什麼是高可用

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

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

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

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

為什麼需要高可用

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

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

高可用的評價緯度

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

全面!一文理解微服務高可用的常用手段

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

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

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

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

微服務高可用設計手段

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

全面!一文理解微服務高可用的常用手段

這中間將會出現的細節是多種多樣的,所以我們需要對這樣一個微服務高可用方案進行一個頂層的設計,圍繞服務高可用,先檢查下我們手裡有多少張牌。

服務冗餘

全面!一文理解微服務高可用的常用手段

①冗餘策略

每一個訪問可能都會有多個服務組合而成,每個機器每個服務都可能出現問題,所以第一個考慮到的就是每個服務必須不止一份可以是多份。

所謂多份一致的服務就是服務的冗餘,這裡說的服務泛指了機器的服務,容器的服務,還有微服務本身的服務。

在機器服務層面需要考慮,各個機器間的冗餘是否有在物理空間進行隔離冗餘。

例如是否所有機器分別部署在不同機房,如果在同一個機房是否做到了部署在不同的機櫃,如果是 Docker 容器是否部署在分別不同的物理機上面。

採取的策略其實也還是根據服務的業務而定,所以需要對服務進行分級評分,從而採取不同的策略。

不同的策略安全程度不同,伴隨著的成本也是不同,安全等級更高的服務可能還不止考慮不同機房,還需要把各個機房所處的區域考慮進行。

例如,兩個機房不要處在同一個地震帶上等等。

全面!一文理解微服務高可用的常用手段

②無狀態化

服務的冗餘會要求我們可以隨時對服務進行擴容或者縮容,有可能我們會從 2 臺機器變成 3 臺機器。

想要對服務進行隨時隨地的擴縮容,就要求我們的服務是一個無狀態化,所謂無狀態化就是每個服務的服務內容和數據都是一致的。

例如,從我們的微服務架構來看,我們總共分水平劃分了好幾個層,正因為我們每個層都做到了無狀態,所以在這個水平架構的擴張是非常的簡單。

假設,我們需要對網關進行擴容,我們只需要增加服務就可以,而不需要去考慮網關是否存儲了一個額外的數據。

全面!一文理解微服務高可用的常用手段

網關不保存任何的 Session 數據,不提供會造成一致性的服務,將不一致的數據進行幾種存儲,藉助更加擅長數據同步的中間件來完成。

這個是目前主流的方案,服務本身儘可能提供邏輯的服務,將數據的一致性保證集中式處理,這樣就可以把“狀態”抽取出來,讓網關保持一個“無狀態”。

這裡僅僅是舉了網關的例子,在微服務基本所有的服務,都應該按照這種思路去做。

如果服務中有狀態,就應該把狀態抽取出來,讓更加擅長處理數據的組件來處理,而不是在微服務中去兼容有數據的狀態。

數據存儲高可用

全面!一文理解微服務高可用的常用手段

之前上面說的服務冗餘,可以簡單的理解為計算的高可用,計算高可用只需要做到無狀態既可簡單的擴容縮容,但是對於需要存儲數據的系統來說,數據本身就是有狀態。

跟存儲與計算相比,有一個本質的差別:將數據從一臺機器搬到另一臺機器,需要經過線路進行傳輸。

網絡是不穩定的,特別是跨機房的網絡,Ping 的延時可能是幾十幾百毫秒,雖然毫秒對於人來說幾乎沒有什麼感覺,但是對於高可用系統來說,就是本質上的不同,這意味著整個系統在某個時間點上,數據肯定是不一致的。

按照“數據+邏輯=業務”的公式來看,數據不一致,邏輯一致,最後的業務表現也會不一致。

舉個例子:

全面!一文理解微服務高可用的常用手段

無論是正常情況下的傳輸延時,還是異常情況下的傳輸中斷,都會導致系統的數據在某個時間點出現不一致。

而數據的不一致又會導致業務出現問題,但是如果數據不做冗餘,系統的高可用無法保證。

所以,存儲高可用的難點不在於怎麼備份數據,而在於如何減少或者規避數據不一致對業務造成的影響。

分佈式領域中有一個著名的 CAP 定理,從理論上論證了存儲高可用的複雜度,也就是說,存儲高可用不可能同時滿足“一致性,可用性,分區容錯性”。

最多隻能滿足 2 個,其中分區容錯在分佈式中是必須的,就意味著,我們在做架構設計時必須結合業務對一致性和可用性進行取捨。

存儲高可用方案的本質是將數據複製到多個存儲設備中,通過數據冗餘的方式來實現高可用,其複雜度主要呈現在數據複製的延遲或中斷導致數據的不一致性。

我們在設計存儲架構時必須考慮到以下幾個方面:

  • 數據怎麼進行復制

  • 架構中每個節點的職責是什麼

  • 數據複製出現延遲怎麼處理

  • 當架構中節點出現錯誤怎麼保證高可用

①數據主從複製

主從複製是最常見的也是最簡單的存儲高可用方案,例如 MySQL,Redis 等等。

全面!一文理解微服務高可用的常用手段

其架構的優點就是簡單,主機複製寫和讀,而從機只負責讀操作,在讀併發高時候可用擴張從庫的數量減低壓力,主機出現故障,讀操作也可以保證讀業務的順利進行。

缺點就是客戶端必須感知主從關係的存在,將不同的操作發送給不同的機器進行處理。

而且主從複製中,從機器負責讀操作,可能因為主從複製時延大,出現數據不一致性的問題。

②數據主從切換

剛說了主從切換存在兩個問題:

  • 主機故障寫操作無法進行。

  • 需要人工將其中一臺從機器升級為主機。

為了解決這個兩個問題,我們可以設計一套主從自動切換的方案,其中涉及到對主機的狀態檢測,切換的決策,數據丟失和衝突的問題。

主機狀態檢測:需要多個檢查點來檢測主機的機器是否正常,進程是否存在,是否出現超時,是否寫操作不可執行,是否讀操作不可執行,將其進行彙總,交給切換決策。

切換決策:確定切換的時間決策,什麼情況下從機就應該升級為主機,是進程不存在,是寫操作不可行,連續檢測多少失敗次就進行切換。

應該選擇哪一個從節點升級為主節點,一般來說或應該選同步步驟最大的從節點來進行升級。切換是自動切換還是半自動切換,通過報警方式,讓人工做一次確認。

數據丟失和數據衝突:數據寫到主機,還沒有複製到從機,主機就掛了,這個時候怎麼處理,這個也得考慮業務的方式,是要確保 CP 或 AP。

全面!一文理解微服務高可用的常用手段

還要考慮一個數據衝突的問題,這個問題在 MySQL 中大部分是由自增主鍵引起。

就算不考慮自增主鍵會引起數據衝突的問題,其實自增主鍵還要引起很多的問題,這裡不細說,避免使用自增主鍵。

③數據分片

上述的數據冗餘可以通過數據的複製來進行解決,但是數據的擴張需要通過數據的分片來進行解決(如果在關係型數據庫是分表)。

全面!一文理解微服務高可用的常用手段

何為數據分片(Segment,Fragment, Shard, Partition),就是按照一定的規則,將數據集劃分成相互獨立、正交的數據子集,然後將數據子集分佈到不同的節點上。

HDFS , MongoDB 的 Sharding 模式也基本是基於這種分片的模式去實現。

我們在設計分片主要考慮到的點是:

  • 做數據分片,如何將數據映射到節點。

  • 數據分片的特徵值,即按照數據中的哪一個屬性(字段)來分片。

  • 數據分片的元數據的管理,如何保證元數據服務器的高性能、高可用,如果是一組服務器,如何保證強一致性。

柔性化/異步化

全面!一文理解微服務高可用的常用手段

①異步化

在每一次調用,時間越長存在超時的風險就越大,邏輯越複雜執行的步驟越多,存在失敗的風險也就越大。

如果在業務允許的情況下,用戶調用只給用戶必須要的結果,而不是需要同步的結果可以放在另外的地方異步去操作,這就減少了超時的風險也把複雜業務進行拆分減低複雜度。

當然異步化的好處是非常多,例如削峰解耦等等,這裡只是從可用的角度出發。

異步化大致有這三種的實現方式:

  • 服務端接收到請求後,創建新的線程處理業務邏輯,服務端先回應答給客戶端

全面!一文理解微服務高可用的常用手段
  • 服務端接收到請求後,服務端先回應答給客戶端,再繼續處理業務邏輯。

全面!一文理解微服務高可用的常用手段
  • 服務端接收到請求後,服務端把信息保存在消息隊列或者數據庫,迴應答給客戶端,服務端業務處理進程再從消息隊列或者數據庫上讀取信息處理業務邏輯。

全面!一文理解微服務高可用的常用手段

②柔性化

什麼是柔性化?想象一個場景,我們的系統會給每個下單的用戶增加他們下單金額對應的積分,當一個用戶下單完畢後,我們給他增加積分的服務出現了問題。

這個時候,我們是要取消掉這個訂單還是先讓訂單通過,積分的問題通過重新或者報警來處理呢?

所謂的柔性化,就是在我們業務中允許的情況下,做不到給予用戶百分百可用的,通過降級的手段給到用戶儘可能多的服務,而不是非得每次都交出去要麼 100 分或 0 分的答卷。

怎麼去做柔性化,更多其實是對業務的理解和判斷,柔性化更多是一種思維,需要對業務場景有深入的瞭解。

在電商訂單的場景中,下單,扣庫存,支付是一定要執行的步驟,如果失敗則訂單失敗。

全面!一文理解微服務高可用的常用手段

但是加積分,發貨,售後是可以柔性處理,就算出錯也可以通過日誌報警讓人工去檢查,沒必要為加積分損失整個下單的可用性。

兜底/容錯

全面!一文理解微服務高可用的常用手段

兜底可能是我們經常談論的一種降級的方案,方案是用來實施,但是這裡兜底可能更多是一種思想,更多的是一種預案,每個操作都可以犯錯,我們也可以接受犯錯。

但是每個犯錯我們都必須有一個兜底的預案,這個兜底的預案其實就是我們的容錯或者說最大程度避免更大傷害的措施,實際上也是一個不斷降級的過程。

舉個例子:

"

高可用並不是一套整體解決方案,而是由諸多環節組成,一環扣一環,鬼知道為了這些串聯起來的環節,我得出多少張牌去應對,才能最終組成一個整個系統的高可用落地方案。

全面!一文理解微服務高可用的常用手段

圖片來自 Pexels

什麼是高可用

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

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

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

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

為什麼需要高可用

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

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

高可用的評價緯度

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

全面!一文理解微服務高可用的常用手段

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

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

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

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

微服務高可用設計手段

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

全面!一文理解微服務高可用的常用手段

這中間將會出現的細節是多種多樣的,所以我們需要對這樣一個微服務高可用方案進行一個頂層的設計,圍繞服務高可用,先檢查下我們手裡有多少張牌。

服務冗餘

全面!一文理解微服務高可用的常用手段

①冗餘策略

每一個訪問可能都會有多個服務組合而成,每個機器每個服務都可能出現問題,所以第一個考慮到的就是每個服務必須不止一份可以是多份。

所謂多份一致的服務就是服務的冗餘,這裡說的服務泛指了機器的服務,容器的服務,還有微服務本身的服務。

在機器服務層面需要考慮,各個機器間的冗餘是否有在物理空間進行隔離冗餘。

例如是否所有機器分別部署在不同機房,如果在同一個機房是否做到了部署在不同的機櫃,如果是 Docker 容器是否部署在分別不同的物理機上面。

採取的策略其實也還是根據服務的業務而定,所以需要對服務進行分級評分,從而採取不同的策略。

不同的策略安全程度不同,伴隨著的成本也是不同,安全等級更高的服務可能還不止考慮不同機房,還需要把各個機房所處的區域考慮進行。

例如,兩個機房不要處在同一個地震帶上等等。

全面!一文理解微服務高可用的常用手段

②無狀態化

服務的冗餘會要求我們可以隨時對服務進行擴容或者縮容,有可能我們會從 2 臺機器變成 3 臺機器。

想要對服務進行隨時隨地的擴縮容,就要求我們的服務是一個無狀態化,所謂無狀態化就是每個服務的服務內容和數據都是一致的。

例如,從我們的微服務架構來看,我們總共分水平劃分了好幾個層,正因為我們每個層都做到了無狀態,所以在這個水平架構的擴張是非常的簡單。

假設,我們需要對網關進行擴容,我們只需要增加服務就可以,而不需要去考慮網關是否存儲了一個額外的數據。

全面!一文理解微服務高可用的常用手段

網關不保存任何的 Session 數據,不提供會造成一致性的服務,將不一致的數據進行幾種存儲,藉助更加擅長數據同步的中間件來完成。

這個是目前主流的方案,服務本身儘可能提供邏輯的服務,將數據的一致性保證集中式處理,這樣就可以把“狀態”抽取出來,讓網關保持一個“無狀態”。

這裡僅僅是舉了網關的例子,在微服務基本所有的服務,都應該按照這種思路去做。

如果服務中有狀態,就應該把狀態抽取出來,讓更加擅長處理數據的組件來處理,而不是在微服務中去兼容有數據的狀態。

數據存儲高可用

全面!一文理解微服務高可用的常用手段

之前上面說的服務冗餘,可以簡單的理解為計算的高可用,計算高可用只需要做到無狀態既可簡單的擴容縮容,但是對於需要存儲數據的系統來說,數據本身就是有狀態。

跟存儲與計算相比,有一個本質的差別:將數據從一臺機器搬到另一臺機器,需要經過線路進行傳輸。

網絡是不穩定的,特別是跨機房的網絡,Ping 的延時可能是幾十幾百毫秒,雖然毫秒對於人來說幾乎沒有什麼感覺,但是對於高可用系統來說,就是本質上的不同,這意味著整個系統在某個時間點上,數據肯定是不一致的。

按照“數據+邏輯=業務”的公式來看,數據不一致,邏輯一致,最後的業務表現也會不一致。

舉個例子:

全面!一文理解微服務高可用的常用手段

無論是正常情況下的傳輸延時,還是異常情況下的傳輸中斷,都會導致系統的數據在某個時間點出現不一致。

而數據的不一致又會導致業務出現問題,但是如果數據不做冗餘,系統的高可用無法保證。

所以,存儲高可用的難點不在於怎麼備份數據,而在於如何減少或者規避數據不一致對業務造成的影響。

分佈式領域中有一個著名的 CAP 定理,從理論上論證了存儲高可用的複雜度,也就是說,存儲高可用不可能同時滿足“一致性,可用性,分區容錯性”。

最多隻能滿足 2 個,其中分區容錯在分佈式中是必須的,就意味著,我們在做架構設計時必須結合業務對一致性和可用性進行取捨。

存儲高可用方案的本質是將數據複製到多個存儲設備中,通過數據冗餘的方式來實現高可用,其複雜度主要呈現在數據複製的延遲或中斷導致數據的不一致性。

我們在設計存儲架構時必須考慮到以下幾個方面:

  • 數據怎麼進行復制

  • 架構中每個節點的職責是什麼

  • 數據複製出現延遲怎麼處理

  • 當架構中節點出現錯誤怎麼保證高可用

①數據主從複製

主從複製是最常見的也是最簡單的存儲高可用方案,例如 MySQL,Redis 等等。

全面!一文理解微服務高可用的常用手段

其架構的優點就是簡單,主機複製寫和讀,而從機只負責讀操作,在讀併發高時候可用擴張從庫的數量減低壓力,主機出現故障,讀操作也可以保證讀業務的順利進行。

缺點就是客戶端必須感知主從關係的存在,將不同的操作發送給不同的機器進行處理。

而且主從複製中,從機器負責讀操作,可能因為主從複製時延大,出現數據不一致性的問題。

②數據主從切換

剛說了主從切換存在兩個問題:

  • 主機故障寫操作無法進行。

  • 需要人工將其中一臺從機器升級為主機。

為了解決這個兩個問題,我們可以設計一套主從自動切換的方案,其中涉及到對主機的狀態檢測,切換的決策,數據丟失和衝突的問題。

主機狀態檢測:需要多個檢查點來檢測主機的機器是否正常,進程是否存在,是否出現超時,是否寫操作不可執行,是否讀操作不可執行,將其進行彙總,交給切換決策。

切換決策:確定切換的時間決策,什麼情況下從機就應該升級為主機,是進程不存在,是寫操作不可行,連續檢測多少失敗次就進行切換。

應該選擇哪一個從節點升級為主節點,一般來說或應該選同步步驟最大的從節點來進行升級。切換是自動切換還是半自動切換,通過報警方式,讓人工做一次確認。

數據丟失和數據衝突:數據寫到主機,還沒有複製到從機,主機就掛了,這個時候怎麼處理,這個也得考慮業務的方式,是要確保 CP 或 AP。

全面!一文理解微服務高可用的常用手段

還要考慮一個數據衝突的問題,這個問題在 MySQL 中大部分是由自增主鍵引起。

就算不考慮自增主鍵會引起數據衝突的問題,其實自增主鍵還要引起很多的問題,這裡不細說,避免使用自增主鍵。

③數據分片

上述的數據冗餘可以通過數據的複製來進行解決,但是數據的擴張需要通過數據的分片來進行解決(如果在關係型數據庫是分表)。

全面!一文理解微服務高可用的常用手段

何為數據分片(Segment,Fragment, Shard, Partition),就是按照一定的規則,將數據集劃分成相互獨立、正交的數據子集,然後將數據子集分佈到不同的節點上。

HDFS , MongoDB 的 Sharding 模式也基本是基於這種分片的模式去實現。

我們在設計分片主要考慮到的點是:

  • 做數據分片,如何將數據映射到節點。

  • 數據分片的特徵值,即按照數據中的哪一個屬性(字段)來分片。

  • 數據分片的元數據的管理,如何保證元數據服務器的高性能、高可用,如果是一組服務器,如何保證強一致性。

柔性化/異步化

全面!一文理解微服務高可用的常用手段

①異步化

在每一次調用,時間越長存在超時的風險就越大,邏輯越複雜執行的步驟越多,存在失敗的風險也就越大。

如果在業務允許的情況下,用戶調用只給用戶必須要的結果,而不是需要同步的結果可以放在另外的地方異步去操作,這就減少了超時的風險也把複雜業務進行拆分減低複雜度。

當然異步化的好處是非常多,例如削峰解耦等等,這裡只是從可用的角度出發。

異步化大致有這三種的實現方式:

  • 服務端接收到請求後,創建新的線程處理業務邏輯,服務端先回應答給客戶端

全面!一文理解微服務高可用的常用手段
  • 服務端接收到請求後,服務端先回應答給客戶端,再繼續處理業務邏輯。

全面!一文理解微服務高可用的常用手段
  • 服務端接收到請求後,服務端把信息保存在消息隊列或者數據庫,迴應答給客戶端,服務端業務處理進程再從消息隊列或者數據庫上讀取信息處理業務邏輯。

全面!一文理解微服務高可用的常用手段

②柔性化

什麼是柔性化?想象一個場景,我們的系統會給每個下單的用戶增加他們下單金額對應的積分,當一個用戶下單完畢後,我們給他增加積分的服務出現了問題。

這個時候,我們是要取消掉這個訂單還是先讓訂單通過,積分的問題通過重新或者報警來處理呢?

所謂的柔性化,就是在我們業務中允許的情況下,做不到給予用戶百分百可用的,通過降級的手段給到用戶儘可能多的服務,而不是非得每次都交出去要麼 100 分或 0 分的答卷。

怎麼去做柔性化,更多其實是對業務的理解和判斷,柔性化更多是一種思維,需要對業務場景有深入的瞭解。

在電商訂單的場景中,下單,扣庫存,支付是一定要執行的步驟,如果失敗則訂單失敗。

全面!一文理解微服務高可用的常用手段

但是加積分,發貨,售後是可以柔性處理,就算出錯也可以通過日誌報警讓人工去檢查,沒必要為加積分損失整個下單的可用性。

兜底/容錯

全面!一文理解微服務高可用的常用手段

兜底可能是我們經常談論的一種降級的方案,方案是用來實施,但是這裡兜底可能更多是一種思想,更多的是一種預案,每個操作都可以犯錯,我們也可以接受犯錯。

但是每個犯錯我們都必須有一個兜底的預案,這個兜底的預案其實就是我們的容錯或者說最大程度避免更大傷害的措施,實際上也是一個不斷降級的過程。

舉個例子:

全面!一文理解微服務高可用的常用手段

例如我們首頁請求的用戶個性化推薦商品的接口,發現推薦系統出錯,我們不應該去擴大(直接把異常拋給用戶)或保持調用接口的錯誤,而是應該兼容調用接口的錯誤,做到更加柔性化。

這時候可以選擇獲取之前沒有失敗接口的緩存數據,如果沒有則可以獲取通用商品不用個性化推薦,如果也沒有可以讀取一些靜態文字進行展示。

由於我們架構進行了分層,分層 App,網關,業務邏輯層,數據訪問層等等,在組織結構也進行了劃分,與之對應的是前端組,後端業務邏輯組,甚至有中臺組等等。

既然有代碼和人員架構的層級劃分,那麼每一層都必須有這樣的思想:包容下一層的錯誤,為上一層提供儘可能無錯的服務。

舉個例子:

"

高可用並不是一套整體解決方案,而是由諸多環節組成,一環扣一環,鬼知道為了這些串聯起來的環節,我得出多少張牌去應對,才能最終組成一個整個系統的高可用落地方案。

全面!一文理解微服務高可用的常用手段

圖片來自 Pexels

什麼是高可用

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

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

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

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

為什麼需要高可用

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

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

高可用的評價緯度

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

全面!一文理解微服務高可用的常用手段

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

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

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

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

微服務高可用設計手段

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

全面!一文理解微服務高可用的常用手段

這中間將會出現的細節是多種多樣的,所以我們需要對這樣一個微服務高可用方案進行一個頂層的設計,圍繞服務高可用,先檢查下我們手裡有多少張牌。

服務冗餘

全面!一文理解微服務高可用的常用手段

①冗餘策略

每一個訪問可能都會有多個服務組合而成,每個機器每個服務都可能出現問題,所以第一個考慮到的就是每個服務必須不止一份可以是多份。

所謂多份一致的服務就是服務的冗餘,這裡說的服務泛指了機器的服務,容器的服務,還有微服務本身的服務。

在機器服務層面需要考慮,各個機器間的冗餘是否有在物理空間進行隔離冗餘。

例如是否所有機器分別部署在不同機房,如果在同一個機房是否做到了部署在不同的機櫃,如果是 Docker 容器是否部署在分別不同的物理機上面。

採取的策略其實也還是根據服務的業務而定,所以需要對服務進行分級評分,從而採取不同的策略。

不同的策略安全程度不同,伴隨著的成本也是不同,安全等級更高的服務可能還不止考慮不同機房,還需要把各個機房所處的區域考慮進行。

例如,兩個機房不要處在同一個地震帶上等等。

全面!一文理解微服務高可用的常用手段

②無狀態化

服務的冗餘會要求我們可以隨時對服務進行擴容或者縮容,有可能我們會從 2 臺機器變成 3 臺機器。

想要對服務進行隨時隨地的擴縮容,就要求我們的服務是一個無狀態化,所謂無狀態化就是每個服務的服務內容和數據都是一致的。

例如,從我們的微服務架構來看,我們總共分水平劃分了好幾個層,正因為我們每個層都做到了無狀態,所以在這個水平架構的擴張是非常的簡單。

假設,我們需要對網關進行擴容,我們只需要增加服務就可以,而不需要去考慮網關是否存儲了一個額外的數據。

全面!一文理解微服務高可用的常用手段

網關不保存任何的 Session 數據,不提供會造成一致性的服務,將不一致的數據進行幾種存儲,藉助更加擅長數據同步的中間件來完成。

這個是目前主流的方案,服務本身儘可能提供邏輯的服務,將數據的一致性保證集中式處理,這樣就可以把“狀態”抽取出來,讓網關保持一個“無狀態”。

這裡僅僅是舉了網關的例子,在微服務基本所有的服務,都應該按照這種思路去做。

如果服務中有狀態,就應該把狀態抽取出來,讓更加擅長處理數據的組件來處理,而不是在微服務中去兼容有數據的狀態。

數據存儲高可用

全面!一文理解微服務高可用的常用手段

之前上面說的服務冗餘,可以簡單的理解為計算的高可用,計算高可用只需要做到無狀態既可簡單的擴容縮容,但是對於需要存儲數據的系統來說,數據本身就是有狀態。

跟存儲與計算相比,有一個本質的差別:將數據從一臺機器搬到另一臺機器,需要經過線路進行傳輸。

網絡是不穩定的,特別是跨機房的網絡,Ping 的延時可能是幾十幾百毫秒,雖然毫秒對於人來說幾乎沒有什麼感覺,但是對於高可用系統來說,就是本質上的不同,這意味著整個系統在某個時間點上,數據肯定是不一致的。

按照“數據+邏輯=業務”的公式來看,數據不一致,邏輯一致,最後的業務表現也會不一致。

舉個例子:

全面!一文理解微服務高可用的常用手段

無論是正常情況下的傳輸延時,還是異常情況下的傳輸中斷,都會導致系統的數據在某個時間點出現不一致。

而數據的不一致又會導致業務出現問題,但是如果數據不做冗餘,系統的高可用無法保證。

所以,存儲高可用的難點不在於怎麼備份數據,而在於如何減少或者規避數據不一致對業務造成的影響。

分佈式領域中有一個著名的 CAP 定理,從理論上論證了存儲高可用的複雜度,也就是說,存儲高可用不可能同時滿足“一致性,可用性,分區容錯性”。

最多隻能滿足 2 個,其中分區容錯在分佈式中是必須的,就意味著,我們在做架構設計時必須結合業務對一致性和可用性進行取捨。

存儲高可用方案的本質是將數據複製到多個存儲設備中,通過數據冗餘的方式來實現高可用,其複雜度主要呈現在數據複製的延遲或中斷導致數據的不一致性。

我們在設計存儲架構時必須考慮到以下幾個方面:

  • 數據怎麼進行復制

  • 架構中每個節點的職責是什麼

  • 數據複製出現延遲怎麼處理

  • 當架構中節點出現錯誤怎麼保證高可用

①數據主從複製

主從複製是最常見的也是最簡單的存儲高可用方案,例如 MySQL,Redis 等等。

全面!一文理解微服務高可用的常用手段

其架構的優點就是簡單,主機複製寫和讀,而從機只負責讀操作,在讀併發高時候可用擴張從庫的數量減低壓力,主機出現故障,讀操作也可以保證讀業務的順利進行。

缺點就是客戶端必須感知主從關係的存在,將不同的操作發送給不同的機器進行處理。

而且主從複製中,從機器負責讀操作,可能因為主從複製時延大,出現數據不一致性的問題。

②數據主從切換

剛說了主從切換存在兩個問題:

  • 主機故障寫操作無法進行。

  • 需要人工將其中一臺從機器升級為主機。

為了解決這個兩個問題,我們可以設計一套主從自動切換的方案,其中涉及到對主機的狀態檢測,切換的決策,數據丟失和衝突的問題。

主機狀態檢測:需要多個檢查點來檢測主機的機器是否正常,進程是否存在,是否出現超時,是否寫操作不可執行,是否讀操作不可執行,將其進行彙總,交給切換決策。

切換決策:確定切換的時間決策,什麼情況下從機就應該升級為主機,是進程不存在,是寫操作不可行,連續檢測多少失敗次就進行切換。

應該選擇哪一個從節點升級為主節點,一般來說或應該選同步步驟最大的從節點來進行升級。切換是自動切換還是半自動切換,通過報警方式,讓人工做一次確認。

數據丟失和數據衝突:數據寫到主機,還沒有複製到從機,主機就掛了,這個時候怎麼處理,這個也得考慮業務的方式,是要確保 CP 或 AP。

全面!一文理解微服務高可用的常用手段

還要考慮一個數據衝突的問題,這個問題在 MySQL 中大部分是由自增主鍵引起。

就算不考慮自增主鍵會引起數據衝突的問題,其實自增主鍵還要引起很多的問題,這裡不細說,避免使用自增主鍵。

③數據分片

上述的數據冗餘可以通過數據的複製來進行解決,但是數據的擴張需要通過數據的分片來進行解決(如果在關係型數據庫是分表)。

全面!一文理解微服務高可用的常用手段

何為數據分片(Segment,Fragment, Shard, Partition),就是按照一定的規則,將數據集劃分成相互獨立、正交的數據子集,然後將數據子集分佈到不同的節點上。

HDFS , MongoDB 的 Sharding 模式也基本是基於這種分片的模式去實現。

我們在設計分片主要考慮到的點是:

  • 做數據分片,如何將數據映射到節點。

  • 數據分片的特徵值,即按照數據中的哪一個屬性(字段)來分片。

  • 數據分片的元數據的管理,如何保證元數據服務器的高性能、高可用,如果是一組服務器,如何保證強一致性。

柔性化/異步化

全面!一文理解微服務高可用的常用手段

①異步化

在每一次調用,時間越長存在超時的風險就越大,邏輯越複雜執行的步驟越多,存在失敗的風險也就越大。

如果在業務允許的情況下,用戶調用只給用戶必須要的結果,而不是需要同步的結果可以放在另外的地方異步去操作,這就減少了超時的風險也把複雜業務進行拆分減低複雜度。

當然異步化的好處是非常多,例如削峰解耦等等,這裡只是從可用的角度出發。

異步化大致有這三種的實現方式:

  • 服務端接收到請求後,創建新的線程處理業務邏輯,服務端先回應答給客戶端

全面!一文理解微服務高可用的常用手段
  • 服務端接收到請求後,服務端先回應答給客戶端,再繼續處理業務邏輯。

全面!一文理解微服務高可用的常用手段
  • 服務端接收到請求後,服務端把信息保存在消息隊列或者數據庫,迴應答給客戶端,服務端業務處理進程再從消息隊列或者數據庫上讀取信息處理業務邏輯。

全面!一文理解微服務高可用的常用手段

②柔性化

什麼是柔性化?想象一個場景,我們的系統會給每個下單的用戶增加他們下單金額對應的積分,當一個用戶下單完畢後,我們給他增加積分的服務出現了問題。

這個時候,我們是要取消掉這個訂單還是先讓訂單通過,積分的問題通過重新或者報警來處理呢?

所謂的柔性化,就是在我們業務中允許的情況下,做不到給予用戶百分百可用的,通過降級的手段給到用戶儘可能多的服務,而不是非得每次都交出去要麼 100 分或 0 分的答卷。

怎麼去做柔性化,更多其實是對業務的理解和判斷,柔性化更多是一種思維,需要對業務場景有深入的瞭解。

在電商訂單的場景中,下單,扣庫存,支付是一定要執行的步驟,如果失敗則訂單失敗。

全面!一文理解微服務高可用的常用手段

但是加積分,發貨,售後是可以柔性處理,就算出錯也可以通過日誌報警讓人工去檢查,沒必要為加積分損失整個下單的可用性。

兜底/容錯

全面!一文理解微服務高可用的常用手段

兜底可能是我們經常談論的一種降級的方案,方案是用來實施,但是這裡兜底可能更多是一種思想,更多的是一種預案,每個操作都可以犯錯,我們也可以接受犯錯。

但是每個犯錯我們都必須有一個兜底的預案,這個兜底的預案其實就是我們的容錯或者說最大程度避免更大傷害的措施,實際上也是一個不斷降級的過程。

舉個例子:

全面!一文理解微服務高可用的常用手段

例如我們首頁請求的用戶個性化推薦商品的接口,發現推薦系統出錯,我們不應該去擴大(直接把異常拋給用戶)或保持調用接口的錯誤,而是應該兼容調用接口的錯誤,做到更加柔性化。

這時候可以選擇獲取之前沒有失敗接口的緩存數據,如果沒有則可以獲取通用商品不用個性化推薦,如果也沒有可以讀取一些靜態文字進行展示。

由於我們架構進行了分層,分層 App,網關,業務邏輯層,數據訪問層等等,在組織結構也進行了劃分,與之對應的是前端組,後端業務邏輯組,甚至有中臺組等等。

既然有代碼和人員架構的層級劃分,那麼每一層都必須有這樣的思想:包容下一層的錯誤,為上一層提供儘可能無錯的服務。

舉個例子:

全面!一文理解微服務高可用的常用手段

商品的美元售價假設要用商品人民幣售價/匯率,這個時候錯誤發生在低層的數據層,上一層如果直接進行除,肯定就拋出 java.lang.ArithmeticException: / by zero。

本著我們對任何一層調用服務都不可信的原則,應該對其進行容錯處理,不能讓異常擴散,更要保證我們這一層對上一次儘可能的作出最大努力確定的服務。

負載均衡

"

高可用並不是一套整體解決方案,而是由諸多環節組成,一環扣一環,鬼知道為了這些串聯起來的環節,我得出多少張牌去應對,才能最終組成一個整個系統的高可用落地方案。

全面!一文理解微服務高可用的常用手段

圖片來自 Pexels

什麼是高可用

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

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

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

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

為什麼需要高可用

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

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

高可用的評價緯度

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

全面!一文理解微服務高可用的常用手段

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

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

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

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

微服務高可用設計手段

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

全面!一文理解微服務高可用的常用手段

這中間將會出現的細節是多種多樣的,所以我們需要對這樣一個微服務高可用方案進行一個頂層的設計,圍繞服務高可用,先檢查下我們手裡有多少張牌。

服務冗餘

全面!一文理解微服務高可用的常用手段

①冗餘策略

每一個訪問可能都會有多個服務組合而成,每個機器每個服務都可能出現問題,所以第一個考慮到的就是每個服務必須不止一份可以是多份。

所謂多份一致的服務就是服務的冗餘,這裡說的服務泛指了機器的服務,容器的服務,還有微服務本身的服務。

在機器服務層面需要考慮,各個機器間的冗餘是否有在物理空間進行隔離冗餘。

例如是否所有機器分別部署在不同機房,如果在同一個機房是否做到了部署在不同的機櫃,如果是 Docker 容器是否部署在分別不同的物理機上面。

採取的策略其實也還是根據服務的業務而定,所以需要對服務進行分級評分,從而採取不同的策略。

不同的策略安全程度不同,伴隨著的成本也是不同,安全等級更高的服務可能還不止考慮不同機房,還需要把各個機房所處的區域考慮進行。

例如,兩個機房不要處在同一個地震帶上等等。

全面!一文理解微服務高可用的常用手段

②無狀態化

服務的冗餘會要求我們可以隨時對服務進行擴容或者縮容,有可能我們會從 2 臺機器變成 3 臺機器。

想要對服務進行隨時隨地的擴縮容,就要求我們的服務是一個無狀態化,所謂無狀態化就是每個服務的服務內容和數據都是一致的。

例如,從我們的微服務架構來看,我們總共分水平劃分了好幾個層,正因為我們每個層都做到了無狀態,所以在這個水平架構的擴張是非常的簡單。

假設,我們需要對網關進行擴容,我們只需要增加服務就可以,而不需要去考慮網關是否存儲了一個額外的數據。

全面!一文理解微服務高可用的常用手段

網關不保存任何的 Session 數據,不提供會造成一致性的服務,將不一致的數據進行幾種存儲,藉助更加擅長數據同步的中間件來完成。

這個是目前主流的方案,服務本身儘可能提供邏輯的服務,將數據的一致性保證集中式處理,這樣就可以把“狀態”抽取出來,讓網關保持一個“無狀態”。

這裡僅僅是舉了網關的例子,在微服務基本所有的服務,都應該按照這種思路去做。

如果服務中有狀態,就應該把狀態抽取出來,讓更加擅長處理數據的組件來處理,而不是在微服務中去兼容有數據的狀態。

數據存儲高可用

全面!一文理解微服務高可用的常用手段

之前上面說的服務冗餘,可以簡單的理解為計算的高可用,計算高可用只需要做到無狀態既可簡單的擴容縮容,但是對於需要存儲數據的系統來說,數據本身就是有狀態。

跟存儲與計算相比,有一個本質的差別:將數據從一臺機器搬到另一臺機器,需要經過線路進行傳輸。

網絡是不穩定的,特別是跨機房的網絡,Ping 的延時可能是幾十幾百毫秒,雖然毫秒對於人來說幾乎沒有什麼感覺,但是對於高可用系統來說,就是本質上的不同,這意味著整個系統在某個時間點上,數據肯定是不一致的。

按照“數據+邏輯=業務”的公式來看,數據不一致,邏輯一致,最後的業務表現也會不一致。

舉個例子:

全面!一文理解微服務高可用的常用手段

無論是正常情況下的傳輸延時,還是異常情況下的傳輸中斷,都會導致系統的數據在某個時間點出現不一致。

而數據的不一致又會導致業務出現問題,但是如果數據不做冗餘,系統的高可用無法保證。

所以,存儲高可用的難點不在於怎麼備份數據,而在於如何減少或者規避數據不一致對業務造成的影響。

分佈式領域中有一個著名的 CAP 定理,從理論上論證了存儲高可用的複雜度,也就是說,存儲高可用不可能同時滿足“一致性,可用性,分區容錯性”。

最多隻能滿足 2 個,其中分區容錯在分佈式中是必須的,就意味著,我們在做架構設計時必須結合業務對一致性和可用性進行取捨。

存儲高可用方案的本質是將數據複製到多個存儲設備中,通過數據冗餘的方式來實現高可用,其複雜度主要呈現在數據複製的延遲或中斷導致數據的不一致性。

我們在設計存儲架構時必須考慮到以下幾個方面:

  • 數據怎麼進行復制

  • 架構中每個節點的職責是什麼

  • 數據複製出現延遲怎麼處理

  • 當架構中節點出現錯誤怎麼保證高可用

①數據主從複製

主從複製是最常見的也是最簡單的存儲高可用方案,例如 MySQL,Redis 等等。

全面!一文理解微服務高可用的常用手段

其架構的優點就是簡單,主機複製寫和讀,而從機只負責讀操作,在讀併發高時候可用擴張從庫的數量減低壓力,主機出現故障,讀操作也可以保證讀業務的順利進行。

缺點就是客戶端必須感知主從關係的存在,將不同的操作發送給不同的機器進行處理。

而且主從複製中,從機器負責讀操作,可能因為主從複製時延大,出現數據不一致性的問題。

②數據主從切換

剛說了主從切換存在兩個問題:

  • 主機故障寫操作無法進行。

  • 需要人工將其中一臺從機器升級為主機。

為了解決這個兩個問題,我們可以設計一套主從自動切換的方案,其中涉及到對主機的狀態檢測,切換的決策,數據丟失和衝突的問題。

主機狀態檢測:需要多個檢查點來檢測主機的機器是否正常,進程是否存在,是否出現超時,是否寫操作不可執行,是否讀操作不可執行,將其進行彙總,交給切換決策。

切換決策:確定切換的時間決策,什麼情況下從機就應該升級為主機,是進程不存在,是寫操作不可行,連續檢測多少失敗次就進行切換。

應該選擇哪一個從節點升級為主節點,一般來說或應該選同步步驟最大的從節點來進行升級。切換是自動切換還是半自動切換,通過報警方式,讓人工做一次確認。

數據丟失和數據衝突:數據寫到主機,還沒有複製到從機,主機就掛了,這個時候怎麼處理,這個也得考慮業務的方式,是要確保 CP 或 AP。

全面!一文理解微服務高可用的常用手段

還要考慮一個數據衝突的問題,這個問題在 MySQL 中大部分是由自增主鍵引起。

就算不考慮自增主鍵會引起數據衝突的問題,其實自增主鍵還要引起很多的問題,這裡不細說,避免使用自增主鍵。

③數據分片

上述的數據冗餘可以通過數據的複製來進行解決,但是數據的擴張需要通過數據的分片來進行解決(如果在關係型數據庫是分表)。

全面!一文理解微服務高可用的常用手段

何為數據分片(Segment,Fragment, Shard, Partition),就是按照一定的規則,將數據集劃分成相互獨立、正交的數據子集,然後將數據子集分佈到不同的節點上。

HDFS , MongoDB 的 Sharding 模式也基本是基於這種分片的模式去實現。

我們在設計分片主要考慮到的點是:

  • 做數據分片,如何將數據映射到節點。

  • 數據分片的特徵值,即按照數據中的哪一個屬性(字段)來分片。

  • 數據分片的元數據的管理,如何保證元數據服務器的高性能、高可用,如果是一組服務器,如何保證強一致性。

柔性化/異步化

全面!一文理解微服務高可用的常用手段

①異步化

在每一次調用,時間越長存在超時的風險就越大,邏輯越複雜執行的步驟越多,存在失敗的風險也就越大。

如果在業務允許的情況下,用戶調用只給用戶必須要的結果,而不是需要同步的結果可以放在另外的地方異步去操作,這就減少了超時的風險也把複雜業務進行拆分減低複雜度。

當然異步化的好處是非常多,例如削峰解耦等等,這裡只是從可用的角度出發。

異步化大致有這三種的實現方式:

  • 服務端接收到請求後,創建新的線程處理業務邏輯,服務端先回應答給客戶端

全面!一文理解微服務高可用的常用手段
  • 服務端接收到請求後,服務端先回應答給客戶端,再繼續處理業務邏輯。

全面!一文理解微服務高可用的常用手段
  • 服務端接收到請求後,服務端把信息保存在消息隊列或者數據庫,迴應答給客戶端,服務端業務處理進程再從消息隊列或者數據庫上讀取信息處理業務邏輯。

全面!一文理解微服務高可用的常用手段

②柔性化

什麼是柔性化?想象一個場景,我們的系統會給每個下單的用戶增加他們下單金額對應的積分,當一個用戶下單完畢後,我們給他增加積分的服務出現了問題。

這個時候,我們是要取消掉這個訂單還是先讓訂單通過,積分的問題通過重新或者報警來處理呢?

所謂的柔性化,就是在我們業務中允許的情況下,做不到給予用戶百分百可用的,通過降級的手段給到用戶儘可能多的服務,而不是非得每次都交出去要麼 100 分或 0 分的答卷。

怎麼去做柔性化,更多其實是對業務的理解和判斷,柔性化更多是一種思維,需要對業務場景有深入的瞭解。

在電商訂單的場景中,下單,扣庫存,支付是一定要執行的步驟,如果失敗則訂單失敗。

全面!一文理解微服務高可用的常用手段

但是加積分,發貨,售後是可以柔性處理,就算出錯也可以通過日誌報警讓人工去檢查,沒必要為加積分損失整個下單的可用性。

兜底/容錯

全面!一文理解微服務高可用的常用手段

兜底可能是我們經常談論的一種降級的方案,方案是用來實施,但是這裡兜底可能更多是一種思想,更多的是一種預案,每個操作都可以犯錯,我們也可以接受犯錯。

但是每個犯錯我們都必須有一個兜底的預案,這個兜底的預案其實就是我們的容錯或者說最大程度避免更大傷害的措施,實際上也是一個不斷降級的過程。

舉個例子:

全面!一文理解微服務高可用的常用手段

例如我們首頁請求的用戶個性化推薦商品的接口,發現推薦系統出錯,我們不應該去擴大(直接把異常拋給用戶)或保持調用接口的錯誤,而是應該兼容調用接口的錯誤,做到更加柔性化。

這時候可以選擇獲取之前沒有失敗接口的緩存數據,如果沒有則可以獲取通用商品不用個性化推薦,如果也沒有可以讀取一些靜態文字進行展示。

由於我們架構進行了分層,分層 App,網關,業務邏輯層,數據訪問層等等,在組織結構也進行了劃分,與之對應的是前端組,後端業務邏輯組,甚至有中臺組等等。

既然有代碼和人員架構的層級劃分,那麼每一層都必須有這樣的思想:包容下一層的錯誤,為上一層提供儘可能無錯的服務。

舉個例子:

全面!一文理解微服務高可用的常用手段

商品的美元售價假設要用商品人民幣售價/匯率,這個時候錯誤發生在低層的數據層,上一層如果直接進行除,肯定就拋出 java.lang.ArithmeticException: / by zero。

本著我們對任何一層調用服務都不可信的原則,應該對其進行容錯處理,不能讓異常擴散,更要保證我們這一層對上一次儘可能的作出最大努力確定的服務。

負載均衡

全面!一文理解微服務高可用的常用手段

相信負載均衡這個話題基本已經深入每個做微服務開發或設計者的人心,負載均衡的實現有硬件和軟件。

硬件有 F5,A10 等機器;軟件有 LVS,Nginx,HAProxy 等等,負載均衡的算法有 Random,RoundRobin,ConsistentHash 等等。

①Nginx 負載均衡故障轉移

"

高可用並不是一套整體解決方案,而是由諸多環節組成,一環扣一環,鬼知道為了這些串聯起來的環節,我得出多少張牌去應對,才能最終組成一個整個系統的高可用落地方案。

全面!一文理解微服務高可用的常用手段

圖片來自 Pexels

什麼是高可用

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

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

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

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

為什麼需要高可用

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

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

高可用的評價緯度

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

全面!一文理解微服務高可用的常用手段

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

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

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

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

微服務高可用設計手段

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

全面!一文理解微服務高可用的常用手段

這中間將會出現的細節是多種多樣的,所以我們需要對這樣一個微服務高可用方案進行一個頂層的設計,圍繞服務高可用,先檢查下我們手裡有多少張牌。

服務冗餘

全面!一文理解微服務高可用的常用手段

①冗餘策略

每一個訪問可能都會有多個服務組合而成,每個機器每個服務都可能出現問題,所以第一個考慮到的就是每個服務必須不止一份可以是多份。

所謂多份一致的服務就是服務的冗餘,這裡說的服務泛指了機器的服務,容器的服務,還有微服務本身的服務。

在機器服務層面需要考慮,各個機器間的冗餘是否有在物理空間進行隔離冗餘。

例如是否所有機器分別部署在不同機房,如果在同一個機房是否做到了部署在不同的機櫃,如果是 Docker 容器是否部署在分別不同的物理機上面。

採取的策略其實也還是根據服務的業務而定,所以需要對服務進行分級評分,從而採取不同的策略。

不同的策略安全程度不同,伴隨著的成本也是不同,安全等級更高的服務可能還不止考慮不同機房,還需要把各個機房所處的區域考慮進行。

例如,兩個機房不要處在同一個地震帶上等等。

全面!一文理解微服務高可用的常用手段

②無狀態化

服務的冗餘會要求我們可以隨時對服務進行擴容或者縮容,有可能我們會從 2 臺機器變成 3 臺機器。

想要對服務進行隨時隨地的擴縮容,就要求我們的服務是一個無狀態化,所謂無狀態化就是每個服務的服務內容和數據都是一致的。

例如,從我們的微服務架構來看,我們總共分水平劃分了好幾個層,正因為我們每個層都做到了無狀態,所以在這個水平架構的擴張是非常的簡單。

假設,我們需要對網關進行擴容,我們只需要增加服務就可以,而不需要去考慮網關是否存儲了一個額外的數據。

全面!一文理解微服務高可用的常用手段

網關不保存任何的 Session 數據,不提供會造成一致性的服務,將不一致的數據進行幾種存儲,藉助更加擅長數據同步的中間件來完成。

這個是目前主流的方案,服務本身儘可能提供邏輯的服務,將數據的一致性保證集中式處理,這樣就可以把“狀態”抽取出來,讓網關保持一個“無狀態”。

這裡僅僅是舉了網關的例子,在微服務基本所有的服務,都應該按照這種思路去做。

如果服務中有狀態,就應該把狀態抽取出來,讓更加擅長處理數據的組件來處理,而不是在微服務中去兼容有數據的狀態。

數據存儲高可用

全面!一文理解微服務高可用的常用手段

之前上面說的服務冗餘,可以簡單的理解為計算的高可用,計算高可用只需要做到無狀態既可簡單的擴容縮容,但是對於需要存儲數據的系統來說,數據本身就是有狀態。

跟存儲與計算相比,有一個本質的差別:將數據從一臺機器搬到另一臺機器,需要經過線路進行傳輸。

網絡是不穩定的,特別是跨機房的網絡,Ping 的延時可能是幾十幾百毫秒,雖然毫秒對於人來說幾乎沒有什麼感覺,但是對於高可用系統來說,就是本質上的不同,這意味著整個系統在某個時間點上,數據肯定是不一致的。

按照“數據+邏輯=業務”的公式來看,數據不一致,邏輯一致,最後的業務表現也會不一致。

舉個例子:

全面!一文理解微服務高可用的常用手段

無論是正常情況下的傳輸延時,還是異常情況下的傳輸中斷,都會導致系統的數據在某個時間點出現不一致。

而數據的不一致又會導致業務出現問題,但是如果數據不做冗餘,系統的高可用無法保證。

所以,存儲高可用的難點不在於怎麼備份數據,而在於如何減少或者規避數據不一致對業務造成的影響。

分佈式領域中有一個著名的 CAP 定理,從理論上論證了存儲高可用的複雜度,也就是說,存儲高可用不可能同時滿足“一致性,可用性,分區容錯性”。

最多隻能滿足 2 個,其中分區容錯在分佈式中是必須的,就意味著,我們在做架構設計時必須結合業務對一致性和可用性進行取捨。

存儲高可用方案的本質是將數據複製到多個存儲設備中,通過數據冗餘的方式來實現高可用,其複雜度主要呈現在數據複製的延遲或中斷導致數據的不一致性。

我們在設計存儲架構時必須考慮到以下幾個方面:

  • 數據怎麼進行復制

  • 架構中每個節點的職責是什麼

  • 數據複製出現延遲怎麼處理

  • 當架構中節點出現錯誤怎麼保證高可用

①數據主從複製

主從複製是最常見的也是最簡單的存儲高可用方案,例如 MySQL,Redis 等等。

全面!一文理解微服務高可用的常用手段

其架構的優點就是簡單,主機複製寫和讀,而從機只負責讀操作,在讀併發高時候可用擴張從庫的數量減低壓力,主機出現故障,讀操作也可以保證讀業務的順利進行。

缺點就是客戶端必須感知主從關係的存在,將不同的操作發送給不同的機器進行處理。

而且主從複製中,從機器負責讀操作,可能因為主從複製時延大,出現數據不一致性的問題。

②數據主從切換

剛說了主從切換存在兩個問題:

  • 主機故障寫操作無法進行。

  • 需要人工將其中一臺從機器升級為主機。

為了解決這個兩個問題,我們可以設計一套主從自動切換的方案,其中涉及到對主機的狀態檢測,切換的決策,數據丟失和衝突的問題。

主機狀態檢測:需要多個檢查點來檢測主機的機器是否正常,進程是否存在,是否出現超時,是否寫操作不可執行,是否讀操作不可執行,將其進行彙總,交給切換決策。

切換決策:確定切換的時間決策,什麼情況下從機就應該升級為主機,是進程不存在,是寫操作不可行,連續檢測多少失敗次就進行切換。

應該選擇哪一個從節點升級為主節點,一般來說或應該選同步步驟最大的從節點來進行升級。切換是自動切換還是半自動切換,通過報警方式,讓人工做一次確認。

數據丟失和數據衝突:數據寫到主機,還沒有複製到從機,主機就掛了,這個時候怎麼處理,這個也得考慮業務的方式,是要確保 CP 或 AP。

全面!一文理解微服務高可用的常用手段

還要考慮一個數據衝突的問題,這個問題在 MySQL 中大部分是由自增主鍵引起。

就算不考慮自增主鍵會引起數據衝突的問題,其實自增主鍵還要引起很多的問題,這裡不細說,避免使用自增主鍵。

③數據分片

上述的數據冗餘可以通過數據的複製來進行解決,但是數據的擴張需要通過數據的分片來進行解決(如果在關係型數據庫是分表)。

全面!一文理解微服務高可用的常用手段

何為數據分片(Segment,Fragment, Shard, Partition),就是按照一定的規則,將數據集劃分成相互獨立、正交的數據子集,然後將數據子集分佈到不同的節點上。

HDFS , MongoDB 的 Sharding 模式也基本是基於這種分片的模式去實現。

我們在設計分片主要考慮到的點是:

  • 做數據分片,如何將數據映射到節點。

  • 數據分片的特徵值,即按照數據中的哪一個屬性(字段)來分片。

  • 數據分片的元數據的管理,如何保證元數據服務器的高性能、高可用,如果是一組服務器,如何保證強一致性。

柔性化/異步化

全面!一文理解微服務高可用的常用手段

①異步化

在每一次調用,時間越長存在超時的風險就越大,邏輯越複雜執行的步驟越多,存在失敗的風險也就越大。

如果在業務允許的情況下,用戶調用只給用戶必須要的結果,而不是需要同步的結果可以放在另外的地方異步去操作,這就減少了超時的風險也把複雜業務進行拆分減低複雜度。

當然異步化的好處是非常多,例如削峰解耦等等,這裡只是從可用的角度出發。

異步化大致有這三種的實現方式:

  • 服務端接收到請求後,創建新的線程處理業務邏輯,服務端先回應答給客戶端

全面!一文理解微服務高可用的常用手段
  • 服務端接收到請求後,服務端先回應答給客戶端,再繼續處理業務邏輯。

全面!一文理解微服務高可用的常用手段
  • 服務端接收到請求後,服務端把信息保存在消息隊列或者數據庫,迴應答給客戶端,服務端業務處理進程再從消息隊列或者數據庫上讀取信息處理業務邏輯。

全面!一文理解微服務高可用的常用手段

②柔性化

什麼是柔性化?想象一個場景,我們的系統會給每個下單的用戶增加他們下單金額對應的積分,當一個用戶下單完畢後,我們給他增加積分的服務出現了問題。

這個時候,我們是要取消掉這個訂單還是先讓訂單通過,積分的問題通過重新或者報警來處理呢?

所謂的柔性化,就是在我們業務中允許的情況下,做不到給予用戶百分百可用的,通過降級的手段給到用戶儘可能多的服務,而不是非得每次都交出去要麼 100 分或 0 分的答卷。

怎麼去做柔性化,更多其實是對業務的理解和判斷,柔性化更多是一種思維,需要對業務場景有深入的瞭解。

在電商訂單的場景中,下單,扣庫存,支付是一定要執行的步驟,如果失敗則訂單失敗。

全面!一文理解微服務高可用的常用手段

但是加積分,發貨,售後是可以柔性處理,就算出錯也可以通過日誌報警讓人工去檢查,沒必要為加積分損失整個下單的可用性。

兜底/容錯

全面!一文理解微服務高可用的常用手段

兜底可能是我們經常談論的一種降級的方案,方案是用來實施,但是這裡兜底可能更多是一種思想,更多的是一種預案,每個操作都可以犯錯,我們也可以接受犯錯。

但是每個犯錯我們都必須有一個兜底的預案,這個兜底的預案其實就是我們的容錯或者說最大程度避免更大傷害的措施,實際上也是一個不斷降級的過程。

舉個例子:

全面!一文理解微服務高可用的常用手段

例如我們首頁請求的用戶個性化推薦商品的接口,發現推薦系統出錯,我們不應該去擴大(直接把異常拋給用戶)或保持調用接口的錯誤,而是應該兼容調用接口的錯誤,做到更加柔性化。

這時候可以選擇獲取之前沒有失敗接口的緩存數據,如果沒有則可以獲取通用商品不用個性化推薦,如果也沒有可以讀取一些靜態文字進行展示。

由於我們架構進行了分層,分層 App,網關,業務邏輯層,數據訪問層等等,在組織結構也進行了劃分,與之對應的是前端組,後端業務邏輯組,甚至有中臺組等等。

既然有代碼和人員架構的層級劃分,那麼每一層都必須有這樣的思想:包容下一層的錯誤,為上一層提供儘可能無錯的服務。

舉個例子:

全面!一文理解微服務高可用的常用手段

商品的美元售價假設要用商品人民幣售價/匯率,這個時候錯誤發生在低層的數據層,上一層如果直接進行除,肯定就拋出 java.lang.ArithmeticException: / by zero。

本著我們對任何一層調用服務都不可信的原則,應該對其進行容錯處理,不能讓異常擴散,更要保證我們這一層對上一次儘可能的作出最大努力確定的服務。

負載均衡

全面!一文理解微服務高可用的常用手段

相信負載均衡這個話題基本已經深入每個做微服務開發或設計者的人心,負載均衡的實現有硬件和軟件。

硬件有 F5,A10 等機器;軟件有 LVS,Nginx,HAProxy 等等,負載均衡的算法有 Random,RoundRobin,ConsistentHash 等等。

①Nginx 負載均衡故障轉移

全面!一文理解微服務高可用的常用手段

轉移流程:Nginx 根據給定好的負載均衡算法進行調度,當請求到 Tomcat1,Nginx 發現 Tomcat1 出現連接錯誤(節點失效),Nginx 會根據一定的機制將 Tomcat1 從調用的負載列表中清除。

在下一次請求,Nginx 不會分配請求到有問題的 Tomcat1 上面,會將請求轉移到其他的 Tomcat 之上。

節點失效:Nginx 默認判斷節點失效是以 connect refuse 和 timeout 為標準,在對某個節點進行 fails 累加,當 fails 大於 max_fails 時,該節點失效。

節點恢復:當某個節點失敗的次數大於 max_fails 時,但不超過 fail_timeout,Nginx 將不再對該節點進行探測,直到超過失效時間或者所有的節點都失效,Nginx 會對節點進行重新探測。

②ZK 負載均衡故障轉移

"

高可用並不是一套整體解決方案,而是由諸多環節組成,一環扣一環,鬼知道為了這些串聯起來的環節,我得出多少張牌去應對,才能最終組成一個整個系統的高可用落地方案。

全面!一文理解微服務高可用的常用手段

圖片來自 Pexels

什麼是高可用

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

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

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

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

為什麼需要高可用

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

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

高可用的評價緯度

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

全面!一文理解微服務高可用的常用手段

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

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

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

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

微服務高可用設計手段

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

全面!一文理解微服務高可用的常用手段

這中間將會出現的細節是多種多樣的,所以我們需要對這樣一個微服務高可用方案進行一個頂層的設計,圍繞服務高可用,先檢查下我們手裡有多少張牌。

服務冗餘

全面!一文理解微服務高可用的常用手段

①冗餘策略

每一個訪問可能都會有多個服務組合而成,每個機器每個服務都可能出現問題,所以第一個考慮到的就是每個服務必須不止一份可以是多份。

所謂多份一致的服務就是服務的冗餘,這裡說的服務泛指了機器的服務,容器的服務,還有微服務本身的服務。

在機器服務層面需要考慮,各個機器間的冗餘是否有在物理空間進行隔離冗餘。

例如是否所有機器分別部署在不同機房,如果在同一個機房是否做到了部署在不同的機櫃,如果是 Docker 容器是否部署在分別不同的物理機上面。

採取的策略其實也還是根據服務的業務而定,所以需要對服務進行分級評分,從而採取不同的策略。

不同的策略安全程度不同,伴隨著的成本也是不同,安全等級更高的服務可能還不止考慮不同機房,還需要把各個機房所處的區域考慮進行。

例如,兩個機房不要處在同一個地震帶上等等。

全面!一文理解微服務高可用的常用手段

②無狀態化

服務的冗餘會要求我們可以隨時對服務進行擴容或者縮容,有可能我們會從 2 臺機器變成 3 臺機器。

想要對服務進行隨時隨地的擴縮容,就要求我們的服務是一個無狀態化,所謂無狀態化就是每個服務的服務內容和數據都是一致的。

例如,從我們的微服務架構來看,我們總共分水平劃分了好幾個層,正因為我們每個層都做到了無狀態,所以在這個水平架構的擴張是非常的簡單。

假設,我們需要對網關進行擴容,我們只需要增加服務就可以,而不需要去考慮網關是否存儲了一個額外的數據。

全面!一文理解微服務高可用的常用手段

網關不保存任何的 Session 數據,不提供會造成一致性的服務,將不一致的數據進行幾種存儲,藉助更加擅長數據同步的中間件來完成。

這個是目前主流的方案,服務本身儘可能提供邏輯的服務,將數據的一致性保證集中式處理,這樣就可以把“狀態”抽取出來,讓網關保持一個“無狀態”。

這裡僅僅是舉了網關的例子,在微服務基本所有的服務,都應該按照這種思路去做。

如果服務中有狀態,就應該把狀態抽取出來,讓更加擅長處理數據的組件來處理,而不是在微服務中去兼容有數據的狀態。

數據存儲高可用

全面!一文理解微服務高可用的常用手段

之前上面說的服務冗餘,可以簡單的理解為計算的高可用,計算高可用只需要做到無狀態既可簡單的擴容縮容,但是對於需要存儲數據的系統來說,數據本身就是有狀態。

跟存儲與計算相比,有一個本質的差別:將數據從一臺機器搬到另一臺機器,需要經過線路進行傳輸。

網絡是不穩定的,特別是跨機房的網絡,Ping 的延時可能是幾十幾百毫秒,雖然毫秒對於人來說幾乎沒有什麼感覺,但是對於高可用系統來說,就是本質上的不同,這意味著整個系統在某個時間點上,數據肯定是不一致的。

按照“數據+邏輯=業務”的公式來看,數據不一致,邏輯一致,最後的業務表現也會不一致。

舉個例子:

全面!一文理解微服務高可用的常用手段

無論是正常情況下的傳輸延時,還是異常情況下的傳輸中斷,都會導致系統的數據在某個時間點出現不一致。

而數據的不一致又會導致業務出現問題,但是如果數據不做冗餘,系統的高可用無法保證。

所以,存儲高可用的難點不在於怎麼備份數據,而在於如何減少或者規避數據不一致對業務造成的影響。

分佈式領域中有一個著名的 CAP 定理,從理論上論證了存儲高可用的複雜度,也就是說,存儲高可用不可能同時滿足“一致性,可用性,分區容錯性”。

最多隻能滿足 2 個,其中分區容錯在分佈式中是必須的,就意味著,我們在做架構設計時必須結合業務對一致性和可用性進行取捨。

存儲高可用方案的本質是將數據複製到多個存儲設備中,通過數據冗餘的方式來實現高可用,其複雜度主要呈現在數據複製的延遲或中斷導致數據的不一致性。

我們在設計存儲架構時必須考慮到以下幾個方面:

  • 數據怎麼進行復制

  • 架構中每個節點的職責是什麼

  • 數據複製出現延遲怎麼處理

  • 當架構中節點出現錯誤怎麼保證高可用

①數據主從複製

主從複製是最常見的也是最簡單的存儲高可用方案,例如 MySQL,Redis 等等。

全面!一文理解微服務高可用的常用手段

其架構的優點就是簡單,主機複製寫和讀,而從機只負責讀操作,在讀併發高時候可用擴張從庫的數量減低壓力,主機出現故障,讀操作也可以保證讀業務的順利進行。

缺點就是客戶端必須感知主從關係的存在,將不同的操作發送給不同的機器進行處理。

而且主從複製中,從機器負責讀操作,可能因為主從複製時延大,出現數據不一致性的問題。

②數據主從切換

剛說了主從切換存在兩個問題:

  • 主機故障寫操作無法進行。

  • 需要人工將其中一臺從機器升級為主機。

為了解決這個兩個問題,我們可以設計一套主從自動切換的方案,其中涉及到對主機的狀態檢測,切換的決策,數據丟失和衝突的問題。

主機狀態檢測:需要多個檢查點來檢測主機的機器是否正常,進程是否存在,是否出現超時,是否寫操作不可執行,是否讀操作不可執行,將其進行彙總,交給切換決策。

切換決策:確定切換的時間決策,什麼情況下從機就應該升級為主機,是進程不存在,是寫操作不可行,連續檢測多少失敗次就進行切換。

應該選擇哪一個從節點升級為主節點,一般來說或應該選同步步驟最大的從節點來進行升級。切換是自動切換還是半自動切換,通過報警方式,讓人工做一次確認。

數據丟失和數據衝突:數據寫到主機,還沒有複製到從機,主機就掛了,這個時候怎麼處理,這個也得考慮業務的方式,是要確保 CP 或 AP。

全面!一文理解微服務高可用的常用手段

還要考慮一個數據衝突的問題,這個問題在 MySQL 中大部分是由自增主鍵引起。

就算不考慮自增主鍵會引起數據衝突的問題,其實自增主鍵還要引起很多的問題,這裡不細說,避免使用自增主鍵。

③數據分片

上述的數據冗餘可以通過數據的複製來進行解決,但是數據的擴張需要通過數據的分片來進行解決(如果在關係型數據庫是分表)。

全面!一文理解微服務高可用的常用手段

何為數據分片(Segment,Fragment, Shard, Partition),就是按照一定的規則,將數據集劃分成相互獨立、正交的數據子集,然後將數據子集分佈到不同的節點上。

HDFS , MongoDB 的 Sharding 模式也基本是基於這種分片的模式去實現。

我們在設計分片主要考慮到的點是:

  • 做數據分片,如何將數據映射到節點。

  • 數據分片的特徵值,即按照數據中的哪一個屬性(字段)來分片。

  • 數據分片的元數據的管理,如何保證元數據服務器的高性能、高可用,如果是一組服務器,如何保證強一致性。

柔性化/異步化

全面!一文理解微服務高可用的常用手段

①異步化

在每一次調用,時間越長存在超時的風險就越大,邏輯越複雜執行的步驟越多,存在失敗的風險也就越大。

如果在業務允許的情況下,用戶調用只給用戶必須要的結果,而不是需要同步的結果可以放在另外的地方異步去操作,這就減少了超時的風險也把複雜業務進行拆分減低複雜度。

當然異步化的好處是非常多,例如削峰解耦等等,這裡只是從可用的角度出發。

異步化大致有這三種的實現方式:

  • 服務端接收到請求後,創建新的線程處理業務邏輯,服務端先回應答給客戶端

全面!一文理解微服務高可用的常用手段
  • 服務端接收到請求後,服務端先回應答給客戶端,再繼續處理業務邏輯。

全面!一文理解微服務高可用的常用手段
  • 服務端接收到請求後,服務端把信息保存在消息隊列或者數據庫,迴應答給客戶端,服務端業務處理進程再從消息隊列或者數據庫上讀取信息處理業務邏輯。

全面!一文理解微服務高可用的常用手段

②柔性化

什麼是柔性化?想象一個場景,我們的系統會給每個下單的用戶增加他們下單金額對應的積分,當一個用戶下單完畢後,我們給他增加積分的服務出現了問題。

這個時候,我們是要取消掉這個訂單還是先讓訂單通過,積分的問題通過重新或者報警來處理呢?

所謂的柔性化,就是在我們業務中允許的情況下,做不到給予用戶百分百可用的,通過降級的手段給到用戶儘可能多的服務,而不是非得每次都交出去要麼 100 分或 0 分的答卷。

怎麼去做柔性化,更多其實是對業務的理解和判斷,柔性化更多是一種思維,需要對業務場景有深入的瞭解。

在電商訂單的場景中,下單,扣庫存,支付是一定要執行的步驟,如果失敗則訂單失敗。

全面!一文理解微服務高可用的常用手段

但是加積分,發貨,售後是可以柔性處理,就算出錯也可以通過日誌報警讓人工去檢查,沒必要為加積分損失整個下單的可用性。

兜底/容錯

全面!一文理解微服務高可用的常用手段

兜底可能是我們經常談論的一種降級的方案,方案是用來實施,但是這裡兜底可能更多是一種思想,更多的是一種預案,每個操作都可以犯錯,我們也可以接受犯錯。

但是每個犯錯我們都必須有一個兜底的預案,這個兜底的預案其實就是我們的容錯或者說最大程度避免更大傷害的措施,實際上也是一個不斷降級的過程。

舉個例子:

全面!一文理解微服務高可用的常用手段

例如我們首頁請求的用戶個性化推薦商品的接口,發現推薦系統出錯,我們不應該去擴大(直接把異常拋給用戶)或保持調用接口的錯誤,而是應該兼容調用接口的錯誤,做到更加柔性化。

這時候可以選擇獲取之前沒有失敗接口的緩存數據,如果沒有則可以獲取通用商品不用個性化推薦,如果也沒有可以讀取一些靜態文字進行展示。

由於我們架構進行了分層,分層 App,網關,業務邏輯層,數據訪問層等等,在組織結構也進行了劃分,與之對應的是前端組,後端業務邏輯組,甚至有中臺組等等。

既然有代碼和人員架構的層級劃分,那麼每一層都必須有這樣的思想:包容下一層的錯誤,為上一層提供儘可能無錯的服務。

舉個例子:

全面!一文理解微服務高可用的常用手段

商品的美元售價假設要用商品人民幣售價/匯率,這個時候錯誤發生在低層的數據層,上一層如果直接進行除,肯定就拋出 java.lang.ArithmeticException: / by zero。

本著我們對任何一層調用服務都不可信的原則,應該對其進行容錯處理,不能讓異常擴散,更要保證我們這一層對上一次儘可能的作出最大努力確定的服務。

負載均衡

全面!一文理解微服務高可用的常用手段

相信負載均衡這個話題基本已經深入每個做微服務開發或設計者的人心,負載均衡的實現有硬件和軟件。

硬件有 F5,A10 等機器;軟件有 LVS,Nginx,HAProxy 等等,負載均衡的算法有 Random,RoundRobin,ConsistentHash 等等。

①Nginx 負載均衡故障轉移

全面!一文理解微服務高可用的常用手段

轉移流程:Nginx 根據給定好的負載均衡算法進行調度,當請求到 Tomcat1,Nginx 發現 Tomcat1 出現連接錯誤(節點失效),Nginx 會根據一定的機制將 Tomcat1 從調用的負載列表中清除。

在下一次請求,Nginx 不會分配請求到有問題的 Tomcat1 上面,會將請求轉移到其他的 Tomcat 之上。

節點失效:Nginx 默認判斷節點失效是以 connect refuse 和 timeout 為標準,在對某個節點進行 fails 累加,當 fails 大於 max_fails 時,該節點失效。

節點恢復:當某個節點失敗的次數大於 max_fails 時,但不超過 fail_timeout,Nginx 將不再對該節點進行探測,直到超過失效時間或者所有的節點都失效,Nginx 會對節點進行重新探測。

②ZK 負載均衡故障轉移

全面!一文理解微服務高可用的常用手段

在使用 ZK 作為註冊中心時,故障的發現是由 ZK 去進行發現,業務邏輯層通過 Watch 的心跳機制將自己註冊到 ZK 上,網關對 ZK 進行訂閱就可以知道有多少可以調用的列表。

當業務邏輯層在重啟或者被關閉時就會跟 ZK 斷了心跳,ZK 會更新可調用列表。

使用 ZK 作為負載均衡的協調器,最大的問題是 ZK 對於服務是否可用是基於 Pingpong 的方式。

只要服務心跳存在,ZK 就認為服務是處在可用狀態,但是服務如果處在假死的狀態,ZK 是無從得知的。這個時候,業務邏輯服務是否真正可用只能夠由網關知道。

冪等設計:為何會牽出冪等設計的問題,主要是因為負載均衡的 Failover 策略,就是對失敗的服務會進行重試。

一般來說,如果是讀操作的服務,重複執行也不會出問題,但想象一下,如果是一個創建訂單減庫存的操作,第一次調用也 Tomcat1 超時,再重新調用了 Tomcat2。

這個時候我們都不能確認超時調用的 Tomcat1 是否真的被調用,有可能根本就調用不成功,有可能已經調用成功但是因為某些原因返回超時而已。

所以,很大程度這個接口會被調用 2 次。如果我們沒有保證冪等性,就有可能一個訂單導致了減少 2 次的庫存。

所謂的冪等性,就是得保證在同一個業務中,一個接口被調用了多次,其導致的結果都是一樣的。

服務限流降級熔斷

"

高可用並不是一套整體解決方案,而是由諸多環節組成,一環扣一環,鬼知道為了這些串聯起來的環節,我得出多少張牌去應對,才能最終組成一個整個系統的高可用落地方案。

全面!一文理解微服務高可用的常用手段

圖片來自 Pexels

什麼是高可用

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

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

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

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

為什麼需要高可用

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

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

高可用的評價緯度

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

全面!一文理解微服務高可用的常用手段

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

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

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

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

微服務高可用設計手段

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

全面!一文理解微服務高可用的常用手段

這中間將會出現的細節是多種多樣的,所以我們需要對這樣一個微服務高可用方案進行一個頂層的設計,圍繞服務高可用,先檢查下我們手裡有多少張牌。

服務冗餘

全面!一文理解微服務高可用的常用手段

①冗餘策略

每一個訪問可能都會有多個服務組合而成,每個機器每個服務都可能出現問題,所以第一個考慮到的就是每個服務必須不止一份可以是多份。

所謂多份一致的服務就是服務的冗餘,這裡說的服務泛指了機器的服務,容器的服務,還有微服務本身的服務。

在機器服務層面需要考慮,各個機器間的冗餘是否有在物理空間進行隔離冗餘。

例如是否所有機器分別部署在不同機房,如果在同一個機房是否做到了部署在不同的機櫃,如果是 Docker 容器是否部署在分別不同的物理機上面。

採取的策略其實也還是根據服務的業務而定,所以需要對服務進行分級評分,從而採取不同的策略。

不同的策略安全程度不同,伴隨著的成本也是不同,安全等級更高的服務可能還不止考慮不同機房,還需要把各個機房所處的區域考慮進行。

例如,兩個機房不要處在同一個地震帶上等等。

全面!一文理解微服務高可用的常用手段

②無狀態化

服務的冗餘會要求我們可以隨時對服務進行擴容或者縮容,有可能我們會從 2 臺機器變成 3 臺機器。

想要對服務進行隨時隨地的擴縮容,就要求我們的服務是一個無狀態化,所謂無狀態化就是每個服務的服務內容和數據都是一致的。

例如,從我們的微服務架構來看,我們總共分水平劃分了好幾個層,正因為我們每個層都做到了無狀態,所以在這個水平架構的擴張是非常的簡單。

假設,我們需要對網關進行擴容,我們只需要增加服務就可以,而不需要去考慮網關是否存儲了一個額外的數據。

全面!一文理解微服務高可用的常用手段

網關不保存任何的 Session 數據,不提供會造成一致性的服務,將不一致的數據進行幾種存儲,藉助更加擅長數據同步的中間件來完成。

這個是目前主流的方案,服務本身儘可能提供邏輯的服務,將數據的一致性保證集中式處理,這樣就可以把“狀態”抽取出來,讓網關保持一個“無狀態”。

這裡僅僅是舉了網關的例子,在微服務基本所有的服務,都應該按照這種思路去做。

如果服務中有狀態,就應該把狀態抽取出來,讓更加擅長處理數據的組件來處理,而不是在微服務中去兼容有數據的狀態。

數據存儲高可用

全面!一文理解微服務高可用的常用手段

之前上面說的服務冗餘,可以簡單的理解為計算的高可用,計算高可用只需要做到無狀態既可簡單的擴容縮容,但是對於需要存儲數據的系統來說,數據本身就是有狀態。

跟存儲與計算相比,有一個本質的差別:將數據從一臺機器搬到另一臺機器,需要經過線路進行傳輸。

網絡是不穩定的,特別是跨機房的網絡,Ping 的延時可能是幾十幾百毫秒,雖然毫秒對於人來說幾乎沒有什麼感覺,但是對於高可用系統來說,就是本質上的不同,這意味著整個系統在某個時間點上,數據肯定是不一致的。

按照“數據+邏輯=業務”的公式來看,數據不一致,邏輯一致,最後的業務表現也會不一致。

舉個例子:

全面!一文理解微服務高可用的常用手段

無論是正常情況下的傳輸延時,還是異常情況下的傳輸中斷,都會導致系統的數據在某個時間點出現不一致。

而數據的不一致又會導致業務出現問題,但是如果數據不做冗餘,系統的高可用無法保證。

所以,存儲高可用的難點不在於怎麼備份數據,而在於如何減少或者規避數據不一致對業務造成的影響。

分佈式領域中有一個著名的 CAP 定理,從理論上論證了存儲高可用的複雜度,也就是說,存儲高可用不可能同時滿足“一致性,可用性,分區容錯性”。

最多隻能滿足 2 個,其中分區容錯在分佈式中是必須的,就意味著,我們在做架構設計時必須結合業務對一致性和可用性進行取捨。

存儲高可用方案的本質是將數據複製到多個存儲設備中,通過數據冗餘的方式來實現高可用,其複雜度主要呈現在數據複製的延遲或中斷導致數據的不一致性。

我們在設計存儲架構時必須考慮到以下幾個方面:

  • 數據怎麼進行復制

  • 架構中每個節點的職責是什麼

  • 數據複製出現延遲怎麼處理

  • 當架構中節點出現錯誤怎麼保證高可用

①數據主從複製

主從複製是最常見的也是最簡單的存儲高可用方案,例如 MySQL,Redis 等等。

全面!一文理解微服務高可用的常用手段

其架構的優點就是簡單,主機複製寫和讀,而從機只負責讀操作,在讀併發高時候可用擴張從庫的數量減低壓力,主機出現故障,讀操作也可以保證讀業務的順利進行。

缺點就是客戶端必須感知主從關係的存在,將不同的操作發送給不同的機器進行處理。

而且主從複製中,從機器負責讀操作,可能因為主從複製時延大,出現數據不一致性的問題。

②數據主從切換

剛說了主從切換存在兩個問題:

  • 主機故障寫操作無法進行。

  • 需要人工將其中一臺從機器升級為主機。

為了解決這個兩個問題,我們可以設計一套主從自動切換的方案,其中涉及到對主機的狀態檢測,切換的決策,數據丟失和衝突的問題。

主機狀態檢測:需要多個檢查點來檢測主機的機器是否正常,進程是否存在,是否出現超時,是否寫操作不可執行,是否讀操作不可執行,將其進行彙總,交給切換決策。

切換決策:確定切換的時間決策,什麼情況下從機就應該升級為主機,是進程不存在,是寫操作不可行,連續檢測多少失敗次就進行切換。

應該選擇哪一個從節點升級為主節點,一般來說或應該選同步步驟最大的從節點來進行升級。切換是自動切換還是半自動切換,通過報警方式,讓人工做一次確認。

數據丟失和數據衝突:數據寫到主機,還沒有複製到從機,主機就掛了,這個時候怎麼處理,這個也得考慮業務的方式,是要確保 CP 或 AP。

全面!一文理解微服務高可用的常用手段

還要考慮一個數據衝突的問題,這個問題在 MySQL 中大部分是由自增主鍵引起。

就算不考慮自增主鍵會引起數據衝突的問題,其實自增主鍵還要引起很多的問題,這裡不細說,避免使用自增主鍵。

③數據分片

上述的數據冗餘可以通過數據的複製來進行解決,但是數據的擴張需要通過數據的分片來進行解決(如果在關係型數據庫是分表)。

全面!一文理解微服務高可用的常用手段

何為數據分片(Segment,Fragment, Shard, Partition),就是按照一定的規則,將數據集劃分成相互獨立、正交的數據子集,然後將數據子集分佈到不同的節點上。

HDFS , MongoDB 的 Sharding 模式也基本是基於這種分片的模式去實現。

我們在設計分片主要考慮到的點是:

  • 做數據分片,如何將數據映射到節點。

  • 數據分片的特徵值,即按照數據中的哪一個屬性(字段)來分片。

  • 數據分片的元數據的管理,如何保證元數據服務器的高性能、高可用,如果是一組服務器,如何保證強一致性。

柔性化/異步化

全面!一文理解微服務高可用的常用手段

①異步化

在每一次調用,時間越長存在超時的風險就越大,邏輯越複雜執行的步驟越多,存在失敗的風險也就越大。

如果在業務允許的情況下,用戶調用只給用戶必須要的結果,而不是需要同步的結果可以放在另外的地方異步去操作,這就減少了超時的風險也把複雜業務進行拆分減低複雜度。

當然異步化的好處是非常多,例如削峰解耦等等,這裡只是從可用的角度出發。

異步化大致有這三種的實現方式:

  • 服務端接收到請求後,創建新的線程處理業務邏輯,服務端先回應答給客戶端

全面!一文理解微服務高可用的常用手段
  • 服務端接收到請求後,服務端先回應答給客戶端,再繼續處理業務邏輯。

全面!一文理解微服務高可用的常用手段
  • 服務端接收到請求後,服務端把信息保存在消息隊列或者數據庫,迴應答給客戶端,服務端業務處理進程再從消息隊列或者數據庫上讀取信息處理業務邏輯。

全面!一文理解微服務高可用的常用手段

②柔性化

什麼是柔性化?想象一個場景,我們的系統會給每個下單的用戶增加他們下單金額對應的積分,當一個用戶下單完畢後,我們給他增加積分的服務出現了問題。

這個時候,我們是要取消掉這個訂單還是先讓訂單通過,積分的問題通過重新或者報警來處理呢?

所謂的柔性化,就是在我們業務中允許的情況下,做不到給予用戶百分百可用的,通過降級的手段給到用戶儘可能多的服務,而不是非得每次都交出去要麼 100 分或 0 分的答卷。

怎麼去做柔性化,更多其實是對業務的理解和判斷,柔性化更多是一種思維,需要對業務場景有深入的瞭解。

在電商訂單的場景中,下單,扣庫存,支付是一定要執行的步驟,如果失敗則訂單失敗。

全面!一文理解微服務高可用的常用手段

但是加積分,發貨,售後是可以柔性處理,就算出錯也可以通過日誌報警讓人工去檢查,沒必要為加積分損失整個下單的可用性。

兜底/容錯

全面!一文理解微服務高可用的常用手段

兜底可能是我們經常談論的一種降級的方案,方案是用來實施,但是這裡兜底可能更多是一種思想,更多的是一種預案,每個操作都可以犯錯,我們也可以接受犯錯。

但是每個犯錯我們都必須有一個兜底的預案,這個兜底的預案其實就是我們的容錯或者說最大程度避免更大傷害的措施,實際上也是一個不斷降級的過程。

舉個例子:

全面!一文理解微服務高可用的常用手段

例如我們首頁請求的用戶個性化推薦商品的接口,發現推薦系統出錯,我們不應該去擴大(直接把異常拋給用戶)或保持調用接口的錯誤,而是應該兼容調用接口的錯誤,做到更加柔性化。

這時候可以選擇獲取之前沒有失敗接口的緩存數據,如果沒有則可以獲取通用商品不用個性化推薦,如果也沒有可以讀取一些靜態文字進行展示。

由於我們架構進行了分層,分層 App,網關,業務邏輯層,數據訪問層等等,在組織結構也進行了劃分,與之對應的是前端組,後端業務邏輯組,甚至有中臺組等等。

既然有代碼和人員架構的層級劃分,那麼每一層都必須有這樣的思想:包容下一層的錯誤,為上一層提供儘可能無錯的服務。

舉個例子:

全面!一文理解微服務高可用的常用手段

商品的美元售價假設要用商品人民幣售價/匯率,這個時候錯誤發生在低層的數據層,上一層如果直接進行除,肯定就拋出 java.lang.ArithmeticException: / by zero。

本著我們對任何一層調用服務都不可信的原則,應該對其進行容錯處理,不能讓異常擴散,更要保證我們這一層對上一次儘可能的作出最大努力確定的服務。

負載均衡

全面!一文理解微服務高可用的常用手段

相信負載均衡這個話題基本已經深入每個做微服務開發或設計者的人心,負載均衡的實現有硬件和軟件。

硬件有 F5,A10 等機器;軟件有 LVS,Nginx,HAProxy 等等,負載均衡的算法有 Random,RoundRobin,ConsistentHash 等等。

①Nginx 負載均衡故障轉移

全面!一文理解微服務高可用的常用手段

轉移流程:Nginx 根據給定好的負載均衡算法進行調度,當請求到 Tomcat1,Nginx 發現 Tomcat1 出現連接錯誤(節點失效),Nginx 會根據一定的機制將 Tomcat1 從調用的負載列表中清除。

在下一次請求,Nginx 不會分配請求到有問題的 Tomcat1 上面,會將請求轉移到其他的 Tomcat 之上。

節點失效:Nginx 默認判斷節點失效是以 connect refuse 和 timeout 為標準,在對某個節點進行 fails 累加,當 fails 大於 max_fails 時,該節點失效。

節點恢復:當某個節點失敗的次數大於 max_fails 時,但不超過 fail_timeout,Nginx 將不再對該節點進行探測,直到超過失效時間或者所有的節點都失效,Nginx 會對節點進行重新探測。

②ZK 負載均衡故障轉移

全面!一文理解微服務高可用的常用手段

在使用 ZK 作為註冊中心時,故障的發現是由 ZK 去進行發現,業務邏輯層通過 Watch 的心跳機制將自己註冊到 ZK 上,網關對 ZK 進行訂閱就可以知道有多少可以調用的列表。

當業務邏輯層在重啟或者被關閉時就會跟 ZK 斷了心跳,ZK 會更新可調用列表。

使用 ZK 作為負載均衡的協調器,最大的問題是 ZK 對於服務是否可用是基於 Pingpong 的方式。

只要服務心跳存在,ZK 就認為服務是處在可用狀態,但是服務如果處在假死的狀態,ZK 是無從得知的。這個時候,業務邏輯服務是否真正可用只能夠由網關知道。

冪等設計:為何會牽出冪等設計的問題,主要是因為負載均衡的 Failover 策略,就是對失敗的服務會進行重試。

一般來說,如果是讀操作的服務,重複執行也不會出問題,但想象一下,如果是一個創建訂單減庫存的操作,第一次調用也 Tomcat1 超時,再重新調用了 Tomcat2。

這個時候我們都不能確認超時調用的 Tomcat1 是否真的被調用,有可能根本就調用不成功,有可能已經調用成功但是因為某些原因返回超時而已。

所以,很大程度這個接口會被調用 2 次。如果我們沒有保證冪等性,就有可能一個訂單導致了減少 2 次的庫存。

所謂的冪等性,就是得保證在同一個業務中,一個接口被調用了多次,其導致的結果都是一樣的。

服務限流降級熔斷

全面!一文理解微服務高可用的常用手段

先來講講微服務中限流/熔斷的目的是什麼,微服務後,系統分佈式部署,系統之間通過 RPC 框架通信,整個系統發生故障的概率隨著系統規模的增長而增長,一個小的故障經過鏈路的傳遞放大,有可能會造成更大的故障。

限流跟高可用的關係是什麼?假定我們的系統最多隻能承受 500 個人的併發訪問,但某個時候突然增加到 1000 個人進來,一下子就把整個系統給壓垮了。

本來還有 500 個人能享受到我們系統的服務,突然間變成了所有人都無法得到服務。

與其讓 1000 人都無法得到服務,不如就讓 500 個人得到服務,拒絕掉另外 500 個人。限流是對訪問的隔離,是保證了部門系統承受範圍內用戶的可用性。

熔斷跟高可用的關係是什麼?上面說了微服務是一個錯綜複雜的調用鏈關係,假設模塊 A 調用模塊 B,模塊 B 又調用了模塊 C,模塊 C 調用了模塊 D。

這個時候,模塊 D 出了問題出現嚴重的時延,這個時候,整個調用鏈就會被模塊 D 給拖垮。

A 等 B,B 等 C,C 等 D,而且 A B C D 的資源被鎖死得不到釋放,如果流量大的話還容易引起雪崩。

熔斷,主動丟棄模塊 D 的調用,並在功能上作出一些降級才能保證到我們系統的健壯性。熔斷是對模塊的隔離,是保證了最大功能的可用性。

服務治理

"

高可用並不是一套整體解決方案,而是由諸多環節組成,一環扣一環,鬼知道為了這些串聯起來的環節,我得出多少張牌去應對,才能最終組成一個整個系統的高可用落地方案。

全面!一文理解微服務高可用的常用手段

圖片來自 Pexels

什麼是高可用

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

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

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

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

為什麼需要高可用

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

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

高可用的評價緯度

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

全面!一文理解微服務高可用的常用手段

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

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

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

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

微服務高可用設計手段

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

全面!一文理解微服務高可用的常用手段

這中間將會出現的細節是多種多樣的,所以我們需要對這樣一個微服務高可用方案進行一個頂層的設計,圍繞服務高可用,先檢查下我們手裡有多少張牌。

服務冗餘

全面!一文理解微服務高可用的常用手段

①冗餘策略

每一個訪問可能都會有多個服務組合而成,每個機器每個服務都可能出現問題,所以第一個考慮到的就是每個服務必須不止一份可以是多份。

所謂多份一致的服務就是服務的冗餘,這裡說的服務泛指了機器的服務,容器的服務,還有微服務本身的服務。

在機器服務層面需要考慮,各個機器間的冗餘是否有在物理空間進行隔離冗餘。

例如是否所有機器分別部署在不同機房,如果在同一個機房是否做到了部署在不同的機櫃,如果是 Docker 容器是否部署在分別不同的物理機上面。

採取的策略其實也還是根據服務的業務而定,所以需要對服務進行分級評分,從而採取不同的策略。

不同的策略安全程度不同,伴隨著的成本也是不同,安全等級更高的服務可能還不止考慮不同機房,還需要把各個機房所處的區域考慮進行。

例如,兩個機房不要處在同一個地震帶上等等。

全面!一文理解微服務高可用的常用手段

②無狀態化

服務的冗餘會要求我們可以隨時對服務進行擴容或者縮容,有可能我們會從 2 臺機器變成 3 臺機器。

想要對服務進行隨時隨地的擴縮容,就要求我們的服務是一個無狀態化,所謂無狀態化就是每個服務的服務內容和數據都是一致的。

例如,從我們的微服務架構來看,我們總共分水平劃分了好幾個層,正因為我們每個層都做到了無狀態,所以在這個水平架構的擴張是非常的簡單。

假設,我們需要對網關進行擴容,我們只需要增加服務就可以,而不需要去考慮網關是否存儲了一個額外的數據。

全面!一文理解微服務高可用的常用手段

網關不保存任何的 Session 數據,不提供會造成一致性的服務,將不一致的數據進行幾種存儲,藉助更加擅長數據同步的中間件來完成。

這個是目前主流的方案,服務本身儘可能提供邏輯的服務,將數據的一致性保證集中式處理,這樣就可以把“狀態”抽取出來,讓網關保持一個“無狀態”。

這裡僅僅是舉了網關的例子,在微服務基本所有的服務,都應該按照這種思路去做。

如果服務中有狀態,就應該把狀態抽取出來,讓更加擅長處理數據的組件來處理,而不是在微服務中去兼容有數據的狀態。

數據存儲高可用

全面!一文理解微服務高可用的常用手段

之前上面說的服務冗餘,可以簡單的理解為計算的高可用,計算高可用只需要做到無狀態既可簡單的擴容縮容,但是對於需要存儲數據的系統來說,數據本身就是有狀態。

跟存儲與計算相比,有一個本質的差別:將數據從一臺機器搬到另一臺機器,需要經過線路進行傳輸。

網絡是不穩定的,特別是跨機房的網絡,Ping 的延時可能是幾十幾百毫秒,雖然毫秒對於人來說幾乎沒有什麼感覺,但是對於高可用系統來說,就是本質上的不同,這意味著整個系統在某個時間點上,數據肯定是不一致的。

按照“數據+邏輯=業務”的公式來看,數據不一致,邏輯一致,最後的業務表現也會不一致。

舉個例子:

全面!一文理解微服務高可用的常用手段

無論是正常情況下的傳輸延時,還是異常情況下的傳輸中斷,都會導致系統的數據在某個時間點出現不一致。

而數據的不一致又會導致業務出現問題,但是如果數據不做冗餘,系統的高可用無法保證。

所以,存儲高可用的難點不在於怎麼備份數據,而在於如何減少或者規避數據不一致對業務造成的影響。

分佈式領域中有一個著名的 CAP 定理,從理論上論證了存儲高可用的複雜度,也就是說,存儲高可用不可能同時滿足“一致性,可用性,分區容錯性”。

最多隻能滿足 2 個,其中分區容錯在分佈式中是必須的,就意味著,我們在做架構設計時必須結合業務對一致性和可用性進行取捨。

存儲高可用方案的本質是將數據複製到多個存儲設備中,通過數據冗餘的方式來實現高可用,其複雜度主要呈現在數據複製的延遲或中斷導致數據的不一致性。

我們在設計存儲架構時必須考慮到以下幾個方面:

  • 數據怎麼進行復制

  • 架構中每個節點的職責是什麼

  • 數據複製出現延遲怎麼處理

  • 當架構中節點出現錯誤怎麼保證高可用

①數據主從複製

主從複製是最常見的也是最簡單的存儲高可用方案,例如 MySQL,Redis 等等。

全面!一文理解微服務高可用的常用手段

其架構的優點就是簡單,主機複製寫和讀,而從機只負責讀操作,在讀併發高時候可用擴張從庫的數量減低壓力,主機出現故障,讀操作也可以保證讀業務的順利進行。

缺點就是客戶端必須感知主從關係的存在,將不同的操作發送給不同的機器進行處理。

而且主從複製中,從機器負責讀操作,可能因為主從複製時延大,出現數據不一致性的問題。

②數據主從切換

剛說了主從切換存在兩個問題:

  • 主機故障寫操作無法進行。

  • 需要人工將其中一臺從機器升級為主機。

為了解決這個兩個問題,我們可以設計一套主從自動切換的方案,其中涉及到對主機的狀態檢測,切換的決策,數據丟失和衝突的問題。

主機狀態檢測:需要多個檢查點來檢測主機的機器是否正常,進程是否存在,是否出現超時,是否寫操作不可執行,是否讀操作不可執行,將其進行彙總,交給切換決策。

切換決策:確定切換的時間決策,什麼情況下從機就應該升級為主機,是進程不存在,是寫操作不可行,連續檢測多少失敗次就進行切換。

應該選擇哪一個從節點升級為主節點,一般來說或應該選同步步驟最大的從節點來進行升級。切換是自動切換還是半自動切換,通過報警方式,讓人工做一次確認。

數據丟失和數據衝突:數據寫到主機,還沒有複製到從機,主機就掛了,這個時候怎麼處理,這個也得考慮業務的方式,是要確保 CP 或 AP。

全面!一文理解微服務高可用的常用手段

還要考慮一個數據衝突的問題,這個問題在 MySQL 中大部分是由自增主鍵引起。

就算不考慮自增主鍵會引起數據衝突的問題,其實自增主鍵還要引起很多的問題,這裡不細說,避免使用自增主鍵。

③數據分片

上述的數據冗餘可以通過數據的複製來進行解決,但是數據的擴張需要通過數據的分片來進行解決(如果在關係型數據庫是分表)。

全面!一文理解微服務高可用的常用手段

何為數據分片(Segment,Fragment, Shard, Partition),就是按照一定的規則,將數據集劃分成相互獨立、正交的數據子集,然後將數據子集分佈到不同的節點上。

HDFS , MongoDB 的 Sharding 模式也基本是基於這種分片的模式去實現。

我們在設計分片主要考慮到的點是:

  • 做數據分片,如何將數據映射到節點。

  • 數據分片的特徵值,即按照數據中的哪一個屬性(字段)來分片。

  • 數據分片的元數據的管理,如何保證元數據服務器的高性能、高可用,如果是一組服務器,如何保證強一致性。

柔性化/異步化

全面!一文理解微服務高可用的常用手段

①異步化

在每一次調用,時間越長存在超時的風險就越大,邏輯越複雜執行的步驟越多,存在失敗的風險也就越大。

如果在業務允許的情況下,用戶調用只給用戶必須要的結果,而不是需要同步的結果可以放在另外的地方異步去操作,這就減少了超時的風險也把複雜業務進行拆分減低複雜度。

當然異步化的好處是非常多,例如削峰解耦等等,這裡只是從可用的角度出發。

異步化大致有這三種的實現方式:

  • 服務端接收到請求後,創建新的線程處理業務邏輯,服務端先回應答給客戶端

全面!一文理解微服務高可用的常用手段
  • 服務端接收到請求後,服務端先回應答給客戶端,再繼續處理業務邏輯。

全面!一文理解微服務高可用的常用手段
  • 服務端接收到請求後,服務端把信息保存在消息隊列或者數據庫,迴應答給客戶端,服務端業務處理進程再從消息隊列或者數據庫上讀取信息處理業務邏輯。

全面!一文理解微服務高可用的常用手段

②柔性化

什麼是柔性化?想象一個場景,我們的系統會給每個下單的用戶增加他們下單金額對應的積分,當一個用戶下單完畢後,我們給他增加積分的服務出現了問題。

這個時候,我們是要取消掉這個訂單還是先讓訂單通過,積分的問題通過重新或者報警來處理呢?

所謂的柔性化,就是在我們業務中允許的情況下,做不到給予用戶百分百可用的,通過降級的手段給到用戶儘可能多的服務,而不是非得每次都交出去要麼 100 分或 0 分的答卷。

怎麼去做柔性化,更多其實是對業務的理解和判斷,柔性化更多是一種思維,需要對業務場景有深入的瞭解。

在電商訂單的場景中,下單,扣庫存,支付是一定要執行的步驟,如果失敗則訂單失敗。

全面!一文理解微服務高可用的常用手段

但是加積分,發貨,售後是可以柔性處理,就算出錯也可以通過日誌報警讓人工去檢查,沒必要為加積分損失整個下單的可用性。

兜底/容錯

全面!一文理解微服務高可用的常用手段

兜底可能是我們經常談論的一種降級的方案,方案是用來實施,但是這裡兜底可能更多是一種思想,更多的是一種預案,每個操作都可以犯錯,我們也可以接受犯錯。

但是每個犯錯我們都必須有一個兜底的預案,這個兜底的預案其實就是我們的容錯或者說最大程度避免更大傷害的措施,實際上也是一個不斷降級的過程。

舉個例子:

全面!一文理解微服務高可用的常用手段

例如我們首頁請求的用戶個性化推薦商品的接口,發現推薦系統出錯,我們不應該去擴大(直接把異常拋給用戶)或保持調用接口的錯誤,而是應該兼容調用接口的錯誤,做到更加柔性化。

這時候可以選擇獲取之前沒有失敗接口的緩存數據,如果沒有則可以獲取通用商品不用個性化推薦,如果也沒有可以讀取一些靜態文字進行展示。

由於我們架構進行了分層,分層 App,網關,業務邏輯層,數據訪問層等等,在組織結構也進行了劃分,與之對應的是前端組,後端業務邏輯組,甚至有中臺組等等。

既然有代碼和人員架構的層級劃分,那麼每一層都必須有這樣的思想:包容下一層的錯誤,為上一層提供儘可能無錯的服務。

舉個例子:

全面!一文理解微服務高可用的常用手段

商品的美元售價假設要用商品人民幣售價/匯率,這個時候錯誤發生在低層的數據層,上一層如果直接進行除,肯定就拋出 java.lang.ArithmeticException: / by zero。

本著我們對任何一層調用服務都不可信的原則,應該對其進行容錯處理,不能讓異常擴散,更要保證我們這一層對上一次儘可能的作出最大努力確定的服務。

負載均衡

全面!一文理解微服務高可用的常用手段

相信負載均衡這個話題基本已經深入每個做微服務開發或設計者的人心,負載均衡的實現有硬件和軟件。

硬件有 F5,A10 等機器;軟件有 LVS,Nginx,HAProxy 等等,負載均衡的算法有 Random,RoundRobin,ConsistentHash 等等。

①Nginx 負載均衡故障轉移

全面!一文理解微服務高可用的常用手段

轉移流程:Nginx 根據給定好的負載均衡算法進行調度,當請求到 Tomcat1,Nginx 發現 Tomcat1 出現連接錯誤(節點失效),Nginx 會根據一定的機制將 Tomcat1 從調用的負載列表中清除。

在下一次請求,Nginx 不會分配請求到有問題的 Tomcat1 上面,會將請求轉移到其他的 Tomcat 之上。

節點失效:Nginx 默認判斷節點失效是以 connect refuse 和 timeout 為標準,在對某個節點進行 fails 累加,當 fails 大於 max_fails 時,該節點失效。

節點恢復:當某個節點失敗的次數大於 max_fails 時,但不超過 fail_timeout,Nginx 將不再對該節點進行探測,直到超過失效時間或者所有的節點都失效,Nginx 會對節點進行重新探測。

②ZK 負載均衡故障轉移

全面!一文理解微服務高可用的常用手段

在使用 ZK 作為註冊中心時,故障的發現是由 ZK 去進行發現,業務邏輯層通過 Watch 的心跳機制將自己註冊到 ZK 上,網關對 ZK 進行訂閱就可以知道有多少可以調用的列表。

當業務邏輯層在重啟或者被關閉時就會跟 ZK 斷了心跳,ZK 會更新可調用列表。

使用 ZK 作為負載均衡的協調器,最大的問題是 ZK 對於服務是否可用是基於 Pingpong 的方式。

只要服務心跳存在,ZK 就認為服務是處在可用狀態,但是服務如果處在假死的狀態,ZK 是無從得知的。這個時候,業務邏輯服務是否真正可用只能夠由網關知道。

冪等設計:為何會牽出冪等設計的問題,主要是因為負載均衡的 Failover 策略,就是對失敗的服務會進行重試。

一般來說,如果是讀操作的服務,重複執行也不會出問題,但想象一下,如果是一個創建訂單減庫存的操作,第一次調用也 Tomcat1 超時,再重新調用了 Tomcat2。

這個時候我們都不能確認超時調用的 Tomcat1 是否真的被調用,有可能根本就調用不成功,有可能已經調用成功但是因為某些原因返回超時而已。

所以,很大程度這個接口會被調用 2 次。如果我們沒有保證冪等性,就有可能一個訂單導致了減少 2 次的庫存。

所謂的冪等性,就是得保證在同一個業務中,一個接口被調用了多次,其導致的結果都是一樣的。

服務限流降級熔斷

全面!一文理解微服務高可用的常用手段

先來講講微服務中限流/熔斷的目的是什麼,微服務後,系統分佈式部署,系統之間通過 RPC 框架通信,整個系統發生故障的概率隨著系統規模的增長而增長,一個小的故障經過鏈路的傳遞放大,有可能會造成更大的故障。

限流跟高可用的關係是什麼?假定我們的系統最多隻能承受 500 個人的併發訪問,但某個時候突然增加到 1000 個人進來,一下子就把整個系統給壓垮了。

本來還有 500 個人能享受到我們系統的服務,突然間變成了所有人都無法得到服務。

與其讓 1000 人都無法得到服務,不如就讓 500 個人得到服務,拒絕掉另外 500 個人。限流是對訪問的隔離,是保證了部門系統承受範圍內用戶的可用性。

熔斷跟高可用的關係是什麼?上面說了微服務是一個錯綜複雜的調用鏈關係,假設模塊 A 調用模塊 B,模塊 B 又調用了模塊 C,模塊 C 調用了模塊 D。

這個時候,模塊 D 出了問題出現嚴重的時延,這個時候,整個調用鏈就會被模塊 D 給拖垮。

A 等 B,B 等 C,C 等 D,而且 A B C D 的資源被鎖死得不到釋放,如果流量大的話還容易引起雪崩。

熔斷,主動丟棄模塊 D 的調用,並在功能上作出一些降級才能保證到我們系統的健壯性。熔斷是對模塊的隔離,是保證了最大功能的可用性。

服務治理

全面!一文理解微服務高可用的常用手段

①服務模塊劃分

服務模塊與服務模塊之間有著千絲萬縷的關係,但服務模塊在業務中各有權重。

例如訂單模塊可能是一家電商公司的重中之重,如果出問題將會直接影響整個公司的營收。

而一個後臺的查詢服務模塊可能也重要,但它的重要等級絕對是沒有像訂單這麼重要。

所以,在做服務治理時,必須明確各個服務模塊的重要等級,這樣才能更好的做好監控,分配好資源。

這個在各個公司有各個公司的一個標準,例如在電商公司,確定服務的級別可能會更加傾向對用戶請求數和營收相關的作為指標。

"

高可用並不是一套整體解決方案,而是由諸多環節組成,一環扣一環,鬼知道為了這些串聯起來的環節,我得出多少張牌去應對,才能最終組成一個整個系統的高可用落地方案。

全面!一文理解微服務高可用的常用手段

圖片來自 Pexels

什麼是高可用

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

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

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

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

為什麼需要高可用

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

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

高可用的評價緯度

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

全面!一文理解微服務高可用的常用手段

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

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

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

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

微服務高可用設計手段

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

全面!一文理解微服務高可用的常用手段

這中間將會出現的細節是多種多樣的,所以我們需要對這樣一個微服務高可用方案進行一個頂層的設計,圍繞服務高可用,先檢查下我們手裡有多少張牌。

服務冗餘

全面!一文理解微服務高可用的常用手段

①冗餘策略

每一個訪問可能都會有多個服務組合而成,每個機器每個服務都可能出現問題,所以第一個考慮到的就是每個服務必須不止一份可以是多份。

所謂多份一致的服務就是服務的冗餘,這裡說的服務泛指了機器的服務,容器的服務,還有微服務本身的服務。

在機器服務層面需要考慮,各個機器間的冗餘是否有在物理空間進行隔離冗餘。

例如是否所有機器分別部署在不同機房,如果在同一個機房是否做到了部署在不同的機櫃,如果是 Docker 容器是否部署在分別不同的物理機上面。

採取的策略其實也還是根據服務的業務而定,所以需要對服務進行分級評分,從而採取不同的策略。

不同的策略安全程度不同,伴隨著的成本也是不同,安全等級更高的服務可能還不止考慮不同機房,還需要把各個機房所處的區域考慮進行。

例如,兩個機房不要處在同一個地震帶上等等。

全面!一文理解微服務高可用的常用手段

②無狀態化

服務的冗餘會要求我們可以隨時對服務進行擴容或者縮容,有可能我們會從 2 臺機器變成 3 臺機器。

想要對服務進行隨時隨地的擴縮容,就要求我們的服務是一個無狀態化,所謂無狀態化就是每個服務的服務內容和數據都是一致的。

例如,從我們的微服務架構來看,我們總共分水平劃分了好幾個層,正因為我們每個層都做到了無狀態,所以在這個水平架構的擴張是非常的簡單。

假設,我們需要對網關進行擴容,我們只需要增加服務就可以,而不需要去考慮網關是否存儲了一個額外的數據。

全面!一文理解微服務高可用的常用手段

網關不保存任何的 Session 數據,不提供會造成一致性的服務,將不一致的數據進行幾種存儲,藉助更加擅長數據同步的中間件來完成。

這個是目前主流的方案,服務本身儘可能提供邏輯的服務,將數據的一致性保證集中式處理,這樣就可以把“狀態”抽取出來,讓網關保持一個“無狀態”。

這裡僅僅是舉了網關的例子,在微服務基本所有的服務,都應該按照這種思路去做。

如果服務中有狀態,就應該把狀態抽取出來,讓更加擅長處理數據的組件來處理,而不是在微服務中去兼容有數據的狀態。

數據存儲高可用

全面!一文理解微服務高可用的常用手段

之前上面說的服務冗餘,可以簡單的理解為計算的高可用,計算高可用只需要做到無狀態既可簡單的擴容縮容,但是對於需要存儲數據的系統來說,數據本身就是有狀態。

跟存儲與計算相比,有一個本質的差別:將數據從一臺機器搬到另一臺機器,需要經過線路進行傳輸。

網絡是不穩定的,特別是跨機房的網絡,Ping 的延時可能是幾十幾百毫秒,雖然毫秒對於人來說幾乎沒有什麼感覺,但是對於高可用系統來說,就是本質上的不同,這意味著整個系統在某個時間點上,數據肯定是不一致的。

按照“數據+邏輯=業務”的公式來看,數據不一致,邏輯一致,最後的業務表現也會不一致。

舉個例子:

全面!一文理解微服務高可用的常用手段

無論是正常情況下的傳輸延時,還是異常情況下的傳輸中斷,都會導致系統的數據在某個時間點出現不一致。

而數據的不一致又會導致業務出現問題,但是如果數據不做冗餘,系統的高可用無法保證。

所以,存儲高可用的難點不在於怎麼備份數據,而在於如何減少或者規避數據不一致對業務造成的影響。

分佈式領域中有一個著名的 CAP 定理,從理論上論證了存儲高可用的複雜度,也就是說,存儲高可用不可能同時滿足“一致性,可用性,分區容錯性”。

最多隻能滿足 2 個,其中分區容錯在分佈式中是必須的,就意味著,我們在做架構設計時必須結合業務對一致性和可用性進行取捨。

存儲高可用方案的本質是將數據複製到多個存儲設備中,通過數據冗餘的方式來實現高可用,其複雜度主要呈現在數據複製的延遲或中斷導致數據的不一致性。

我們在設計存儲架構時必須考慮到以下幾個方面:

  • 數據怎麼進行復制

  • 架構中每個節點的職責是什麼

  • 數據複製出現延遲怎麼處理

  • 當架構中節點出現錯誤怎麼保證高可用

①數據主從複製

主從複製是最常見的也是最簡單的存儲高可用方案,例如 MySQL,Redis 等等。

全面!一文理解微服務高可用的常用手段

其架構的優點就是簡單,主機複製寫和讀,而從機只負責讀操作,在讀併發高時候可用擴張從庫的數量減低壓力,主機出現故障,讀操作也可以保證讀業務的順利進行。

缺點就是客戶端必須感知主從關係的存在,將不同的操作發送給不同的機器進行處理。

而且主從複製中,從機器負責讀操作,可能因為主從複製時延大,出現數據不一致性的問題。

②數據主從切換

剛說了主從切換存在兩個問題:

  • 主機故障寫操作無法進行。

  • 需要人工將其中一臺從機器升級為主機。

為了解決這個兩個問題,我們可以設計一套主從自動切換的方案,其中涉及到對主機的狀態檢測,切換的決策,數據丟失和衝突的問題。

主機狀態檢測:需要多個檢查點來檢測主機的機器是否正常,進程是否存在,是否出現超時,是否寫操作不可執行,是否讀操作不可執行,將其進行彙總,交給切換決策。

切換決策:確定切換的時間決策,什麼情況下從機就應該升級為主機,是進程不存在,是寫操作不可行,連續檢測多少失敗次就進行切換。

應該選擇哪一個從節點升級為主節點,一般來說或應該選同步步驟最大的從節點來進行升級。切換是自動切換還是半自動切換,通過報警方式,讓人工做一次確認。

數據丟失和數據衝突:數據寫到主機,還沒有複製到從機,主機就掛了,這個時候怎麼處理,這個也得考慮業務的方式,是要確保 CP 或 AP。

全面!一文理解微服務高可用的常用手段

還要考慮一個數據衝突的問題,這個問題在 MySQL 中大部分是由自增主鍵引起。

就算不考慮自增主鍵會引起數據衝突的問題,其實自增主鍵還要引起很多的問題,這裡不細說,避免使用自增主鍵。

③數據分片

上述的數據冗餘可以通過數據的複製來進行解決,但是數據的擴張需要通過數據的分片來進行解決(如果在關係型數據庫是分表)。

全面!一文理解微服務高可用的常用手段

何為數據分片(Segment,Fragment, Shard, Partition),就是按照一定的規則,將數據集劃分成相互獨立、正交的數據子集,然後將數據子集分佈到不同的節點上。

HDFS , MongoDB 的 Sharding 模式也基本是基於這種分片的模式去實現。

我們在設計分片主要考慮到的點是:

  • 做數據分片,如何將數據映射到節點。

  • 數據分片的特徵值,即按照數據中的哪一個屬性(字段)來分片。

  • 數據分片的元數據的管理,如何保證元數據服務器的高性能、高可用,如果是一組服務器,如何保證強一致性。

柔性化/異步化

全面!一文理解微服務高可用的常用手段

①異步化

在每一次調用,時間越長存在超時的風險就越大,邏輯越複雜執行的步驟越多,存在失敗的風險也就越大。

如果在業務允許的情況下,用戶調用只給用戶必須要的結果,而不是需要同步的結果可以放在另外的地方異步去操作,這就減少了超時的風險也把複雜業務進行拆分減低複雜度。

當然異步化的好處是非常多,例如削峰解耦等等,這裡只是從可用的角度出發。

異步化大致有這三種的實現方式:

  • 服務端接收到請求後,創建新的線程處理業務邏輯,服務端先回應答給客戶端

全面!一文理解微服務高可用的常用手段
  • 服務端接收到請求後,服務端先回應答給客戶端,再繼續處理業務邏輯。

全面!一文理解微服務高可用的常用手段
  • 服務端接收到請求後,服務端把信息保存在消息隊列或者數據庫,迴應答給客戶端,服務端業務處理進程再從消息隊列或者數據庫上讀取信息處理業務邏輯。

全面!一文理解微服務高可用的常用手段

②柔性化

什麼是柔性化?想象一個場景,我們的系統會給每個下單的用戶增加他們下單金額對應的積分,當一個用戶下單完畢後,我們給他增加積分的服務出現了問題。

這個時候,我們是要取消掉這個訂單還是先讓訂單通過,積分的問題通過重新或者報警來處理呢?

所謂的柔性化,就是在我們業務中允許的情況下,做不到給予用戶百分百可用的,通過降級的手段給到用戶儘可能多的服務,而不是非得每次都交出去要麼 100 分或 0 分的答卷。

怎麼去做柔性化,更多其實是對業務的理解和判斷,柔性化更多是一種思維,需要對業務場景有深入的瞭解。

在電商訂單的場景中,下單,扣庫存,支付是一定要執行的步驟,如果失敗則訂單失敗。

全面!一文理解微服務高可用的常用手段

但是加積分,發貨,售後是可以柔性處理,就算出錯也可以通過日誌報警讓人工去檢查,沒必要為加積分損失整個下單的可用性。

兜底/容錯

全面!一文理解微服務高可用的常用手段

兜底可能是我們經常談論的一種降級的方案,方案是用來實施,但是這裡兜底可能更多是一種思想,更多的是一種預案,每個操作都可以犯錯,我們也可以接受犯錯。

但是每個犯錯我們都必須有一個兜底的預案,這個兜底的預案其實就是我們的容錯或者說最大程度避免更大傷害的措施,實際上也是一個不斷降級的過程。

舉個例子:

全面!一文理解微服務高可用的常用手段

例如我們首頁請求的用戶個性化推薦商品的接口,發現推薦系統出錯,我們不應該去擴大(直接把異常拋給用戶)或保持調用接口的錯誤,而是應該兼容調用接口的錯誤,做到更加柔性化。

這時候可以選擇獲取之前沒有失敗接口的緩存數據,如果沒有則可以獲取通用商品不用個性化推薦,如果也沒有可以讀取一些靜態文字進行展示。

由於我們架構進行了分層,分層 App,網關,業務邏輯層,數據訪問層等等,在組織結構也進行了劃分,與之對應的是前端組,後端業務邏輯組,甚至有中臺組等等。

既然有代碼和人員架構的層級劃分,那麼每一層都必須有這樣的思想:包容下一層的錯誤,為上一層提供儘可能無錯的服務。

舉個例子:

全面!一文理解微服務高可用的常用手段

商品的美元售價假設要用商品人民幣售價/匯率,這個時候錯誤發生在低層的數據層,上一層如果直接進行除,肯定就拋出 java.lang.ArithmeticException: / by zero。

本著我們對任何一層調用服務都不可信的原則,應該對其進行容錯處理,不能讓異常擴散,更要保證我們這一層對上一次儘可能的作出最大努力確定的服務。

負載均衡

全面!一文理解微服務高可用的常用手段

相信負載均衡這個話題基本已經深入每個做微服務開發或設計者的人心,負載均衡的實現有硬件和軟件。

硬件有 F5,A10 等機器;軟件有 LVS,Nginx,HAProxy 等等,負載均衡的算法有 Random,RoundRobin,ConsistentHash 等等。

①Nginx 負載均衡故障轉移

全面!一文理解微服務高可用的常用手段

轉移流程:Nginx 根據給定好的負載均衡算法進行調度,當請求到 Tomcat1,Nginx 發現 Tomcat1 出現連接錯誤(節點失效),Nginx 會根據一定的機制將 Tomcat1 從調用的負載列表中清除。

在下一次請求,Nginx 不會分配請求到有問題的 Tomcat1 上面,會將請求轉移到其他的 Tomcat 之上。

節點失效:Nginx 默認判斷節點失效是以 connect refuse 和 timeout 為標準,在對某個節點進行 fails 累加,當 fails 大於 max_fails 時,該節點失效。

節點恢復:當某個節點失敗的次數大於 max_fails 時,但不超過 fail_timeout,Nginx 將不再對該節點進行探測,直到超過失效時間或者所有的節點都失效,Nginx 會對節點進行重新探測。

②ZK 負載均衡故障轉移

全面!一文理解微服務高可用的常用手段

在使用 ZK 作為註冊中心時,故障的發現是由 ZK 去進行發現,業務邏輯層通過 Watch 的心跳機制將自己註冊到 ZK 上,網關對 ZK 進行訂閱就可以知道有多少可以調用的列表。

當業務邏輯層在重啟或者被關閉時就會跟 ZK 斷了心跳,ZK 會更新可調用列表。

使用 ZK 作為負載均衡的協調器,最大的問題是 ZK 對於服務是否可用是基於 Pingpong 的方式。

只要服務心跳存在,ZK 就認為服務是處在可用狀態,但是服務如果處在假死的狀態,ZK 是無從得知的。這個時候,業務邏輯服務是否真正可用只能夠由網關知道。

冪等設計:為何會牽出冪等設計的問題,主要是因為負載均衡的 Failover 策略,就是對失敗的服務會進行重試。

一般來說,如果是讀操作的服務,重複執行也不會出問題,但想象一下,如果是一個創建訂單減庫存的操作,第一次調用也 Tomcat1 超時,再重新調用了 Tomcat2。

這個時候我們都不能確認超時調用的 Tomcat1 是否真的被調用,有可能根本就調用不成功,有可能已經調用成功但是因為某些原因返回超時而已。

所以,很大程度這個接口會被調用 2 次。如果我們沒有保證冪等性,就有可能一個訂單導致了減少 2 次的庫存。

所謂的冪等性,就是得保證在同一個業務中,一個接口被調用了多次,其導致的結果都是一樣的。

服務限流降級熔斷

全面!一文理解微服務高可用的常用手段

先來講講微服務中限流/熔斷的目的是什麼,微服務後,系統分佈式部署,系統之間通過 RPC 框架通信,整個系統發生故障的概率隨著系統規模的增長而增長,一個小的故障經過鏈路的傳遞放大,有可能會造成更大的故障。

限流跟高可用的關係是什麼?假定我們的系統最多隻能承受 500 個人的併發訪問,但某個時候突然增加到 1000 個人進來,一下子就把整個系統給壓垮了。

本來還有 500 個人能享受到我們系統的服務,突然間變成了所有人都無法得到服務。

與其讓 1000 人都無法得到服務,不如就讓 500 個人得到服務,拒絕掉另外 500 個人。限流是對訪問的隔離,是保證了部門系統承受範圍內用戶的可用性。

熔斷跟高可用的關係是什麼?上面說了微服務是一個錯綜複雜的調用鏈關係,假設模塊 A 調用模塊 B,模塊 B 又調用了模塊 C,模塊 C 調用了模塊 D。

這個時候,模塊 D 出了問題出現嚴重的時延,這個時候,整個調用鏈就會被模塊 D 給拖垮。

A 等 B,B 等 C,C 等 D,而且 A B C D 的資源被鎖死得不到釋放,如果流量大的話還容易引起雪崩。

熔斷,主動丟棄模塊 D 的調用,並在功能上作出一些降級才能保證到我們系統的健壯性。熔斷是對模塊的隔離,是保證了最大功能的可用性。

服務治理

全面!一文理解微服務高可用的常用手段

①服務模塊劃分

服務模塊與服務模塊之間有著千絲萬縷的關係,但服務模塊在業務中各有權重。

例如訂單模塊可能是一家電商公司的重中之重,如果出問題將會直接影響整個公司的營收。

而一個後臺的查詢服務模塊可能也重要,但它的重要等級絕對是沒有像訂單這麼重要。

所以,在做服務治理時,必須明確各個服務模塊的重要等級,這樣才能更好的做好監控,分配好資源。

這個在各個公司有各個公司的一個標準,例如在電商公司,確定服務的級別可能會更加傾向對用戶請求數和營收相關的作為指標。

全面!一文理解微服務高可用的常用手段

可能真正的劃分要比這個更為複雜,必須根據具體業務去定,這個可以從平時服務模塊的訪問量和流量去預估。

往往更重要的模塊也會提供更多的資源,所以不僅要對技術架構瞭如指掌,還要對公司各種業務形態瞭然於心才可以。

服務分級不僅僅在故障界定起到重要主要,而且決定了服務監控的力度,服務監控在高可用中起到了一個保障的作用。

它不僅可以保留服務崩潰的現場以等待日後覆盤,更重要的是它可以起到一個先知,先行判斷的角色,很多時候可以預先判斷危險,防範於未然。

②服務監控

服務監控是微服務治理的一個重要環節,監控系統的完善程度直接影響到我們微服務質量的好壞。

我們的微服務在線上運行的時候有沒有一套完善的監控體系能去了解到它的健康情況,對整個系統的可靠性和穩定性是非常重要,可靠性和穩定性是高可用的一個前提保證。

服務的監控更多是對於風險的預判,在出現不可用之間就提前的發現問題,如果系統獲取監控報警系統能自我修復則可以將錯誤消滅在無形,如果系統發現報警無法自我修復則可以通知人員提早進行接入。

一個比較完善的微服務監控體系需要涉及到哪些層次?如下圖,大致可以劃分為五個層次的監控:

"

高可用並不是一套整體解決方案,而是由諸多環節組成,一環扣一環,鬼知道為了這些串聯起來的環節,我得出多少張牌去應對,才能最終組成一個整個系統的高可用落地方案。

全面!一文理解微服務高可用的常用手段

圖片來自 Pexels

什麼是高可用

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

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

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

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

為什麼需要高可用

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

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

高可用的評價緯度

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

全面!一文理解微服務高可用的常用手段

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

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

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

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

微服務高可用設計手段

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

全面!一文理解微服務高可用的常用手段

這中間將會出現的細節是多種多樣的,所以我們需要對這樣一個微服務高可用方案進行一個頂層的設計,圍繞服務高可用,先檢查下我們手裡有多少張牌。

服務冗餘

全面!一文理解微服務高可用的常用手段

①冗餘策略

每一個訪問可能都會有多個服務組合而成,每個機器每個服務都可能出現問題,所以第一個考慮到的就是每個服務必須不止一份可以是多份。

所謂多份一致的服務就是服務的冗餘,這裡說的服務泛指了機器的服務,容器的服務,還有微服務本身的服務。

在機器服務層面需要考慮,各個機器間的冗餘是否有在物理空間進行隔離冗餘。

例如是否所有機器分別部署在不同機房,如果在同一個機房是否做到了部署在不同的機櫃,如果是 Docker 容器是否部署在分別不同的物理機上面。

採取的策略其實也還是根據服務的業務而定,所以需要對服務進行分級評分,從而採取不同的策略。

不同的策略安全程度不同,伴隨著的成本也是不同,安全等級更高的服務可能還不止考慮不同機房,還需要把各個機房所處的區域考慮進行。

例如,兩個機房不要處在同一個地震帶上等等。

全面!一文理解微服務高可用的常用手段

②無狀態化

服務的冗餘會要求我們可以隨時對服務進行擴容或者縮容,有可能我們會從 2 臺機器變成 3 臺機器。

想要對服務進行隨時隨地的擴縮容,就要求我們的服務是一個無狀態化,所謂無狀態化就是每個服務的服務內容和數據都是一致的。

例如,從我們的微服務架構來看,我們總共分水平劃分了好幾個層,正因為我們每個層都做到了無狀態,所以在這個水平架構的擴張是非常的簡單。

假設,我們需要對網關進行擴容,我們只需要增加服務就可以,而不需要去考慮網關是否存儲了一個額外的數據。

全面!一文理解微服務高可用的常用手段

網關不保存任何的 Session 數據,不提供會造成一致性的服務,將不一致的數據進行幾種存儲,藉助更加擅長數據同步的中間件來完成。

這個是目前主流的方案,服務本身儘可能提供邏輯的服務,將數據的一致性保證集中式處理,這樣就可以把“狀態”抽取出來,讓網關保持一個“無狀態”。

這裡僅僅是舉了網關的例子,在微服務基本所有的服務,都應該按照這種思路去做。

如果服務中有狀態,就應該把狀態抽取出來,讓更加擅長處理數據的組件來處理,而不是在微服務中去兼容有數據的狀態。

數據存儲高可用

全面!一文理解微服務高可用的常用手段

之前上面說的服務冗餘,可以簡單的理解為計算的高可用,計算高可用只需要做到無狀態既可簡單的擴容縮容,但是對於需要存儲數據的系統來說,數據本身就是有狀態。

跟存儲與計算相比,有一個本質的差別:將數據從一臺機器搬到另一臺機器,需要經過線路進行傳輸。

網絡是不穩定的,特別是跨機房的網絡,Ping 的延時可能是幾十幾百毫秒,雖然毫秒對於人來說幾乎沒有什麼感覺,但是對於高可用系統來說,就是本質上的不同,這意味著整個系統在某個時間點上,數據肯定是不一致的。

按照“數據+邏輯=業務”的公式來看,數據不一致,邏輯一致,最後的業務表現也會不一致。

舉個例子:

全面!一文理解微服務高可用的常用手段

無論是正常情況下的傳輸延時,還是異常情況下的傳輸中斷,都會導致系統的數據在某個時間點出現不一致。

而數據的不一致又會導致業務出現問題,但是如果數據不做冗餘,系統的高可用無法保證。

所以,存儲高可用的難點不在於怎麼備份數據,而在於如何減少或者規避數據不一致對業務造成的影響。

分佈式領域中有一個著名的 CAP 定理,從理論上論證了存儲高可用的複雜度,也就是說,存儲高可用不可能同時滿足“一致性,可用性,分區容錯性”。

最多隻能滿足 2 個,其中分區容錯在分佈式中是必須的,就意味著,我們在做架構設計時必須結合業務對一致性和可用性進行取捨。

存儲高可用方案的本質是將數據複製到多個存儲設備中,通過數據冗餘的方式來實現高可用,其複雜度主要呈現在數據複製的延遲或中斷導致數據的不一致性。

我們在設計存儲架構時必須考慮到以下幾個方面:

  • 數據怎麼進行復制

  • 架構中每個節點的職責是什麼

  • 數據複製出現延遲怎麼處理

  • 當架構中節點出現錯誤怎麼保證高可用

①數據主從複製

主從複製是最常見的也是最簡單的存儲高可用方案,例如 MySQL,Redis 等等。

全面!一文理解微服務高可用的常用手段

其架構的優點就是簡單,主機複製寫和讀,而從機只負責讀操作,在讀併發高時候可用擴張從庫的數量減低壓力,主機出現故障,讀操作也可以保證讀業務的順利進行。

缺點就是客戶端必須感知主從關係的存在,將不同的操作發送給不同的機器進行處理。

而且主從複製中,從機器負責讀操作,可能因為主從複製時延大,出現數據不一致性的問題。

②數據主從切換

剛說了主從切換存在兩個問題:

  • 主機故障寫操作無法進行。

  • 需要人工將其中一臺從機器升級為主機。

為了解決這個兩個問題,我們可以設計一套主從自動切換的方案,其中涉及到對主機的狀態檢測,切換的決策,數據丟失和衝突的問題。

主機狀態檢測:需要多個檢查點來檢測主機的機器是否正常,進程是否存在,是否出現超時,是否寫操作不可執行,是否讀操作不可執行,將其進行彙總,交給切換決策。

切換決策:確定切換的時間決策,什麼情況下從機就應該升級為主機,是進程不存在,是寫操作不可行,連續檢測多少失敗次就進行切換。

應該選擇哪一個從節點升級為主節點,一般來說或應該選同步步驟最大的從節點來進行升級。切換是自動切換還是半自動切換,通過報警方式,讓人工做一次確認。

數據丟失和數據衝突:數據寫到主機,還沒有複製到從機,主機就掛了,這個時候怎麼處理,這個也得考慮業務的方式,是要確保 CP 或 AP。

全面!一文理解微服務高可用的常用手段

還要考慮一個數據衝突的問題,這個問題在 MySQL 中大部分是由自增主鍵引起。

就算不考慮自增主鍵會引起數據衝突的問題,其實自增主鍵還要引起很多的問題,這裡不細說,避免使用自增主鍵。

③數據分片

上述的數據冗餘可以通過數據的複製來進行解決,但是數據的擴張需要通過數據的分片來進行解決(如果在關係型數據庫是分表)。

全面!一文理解微服務高可用的常用手段

何為數據分片(Segment,Fragment, Shard, Partition),就是按照一定的規則,將數據集劃分成相互獨立、正交的數據子集,然後將數據子集分佈到不同的節點上。

HDFS , MongoDB 的 Sharding 模式也基本是基於這種分片的模式去實現。

我們在設計分片主要考慮到的點是:

  • 做數據分片,如何將數據映射到節點。

  • 數據分片的特徵值,即按照數據中的哪一個屬性(字段)來分片。

  • 數據分片的元數據的管理,如何保證元數據服務器的高性能、高可用,如果是一組服務器,如何保證強一致性。

柔性化/異步化

全面!一文理解微服務高可用的常用手段

①異步化

在每一次調用,時間越長存在超時的風險就越大,邏輯越複雜執行的步驟越多,存在失敗的風險也就越大。

如果在業務允許的情況下,用戶調用只給用戶必須要的結果,而不是需要同步的結果可以放在另外的地方異步去操作,這就減少了超時的風險也把複雜業務進行拆分減低複雜度。

當然異步化的好處是非常多,例如削峰解耦等等,這裡只是從可用的角度出發。

異步化大致有這三種的實現方式:

  • 服務端接收到請求後,創建新的線程處理業務邏輯,服務端先回應答給客戶端

全面!一文理解微服務高可用的常用手段
  • 服務端接收到請求後,服務端先回應答給客戶端,再繼續處理業務邏輯。

全面!一文理解微服務高可用的常用手段
  • 服務端接收到請求後,服務端把信息保存在消息隊列或者數據庫,迴應答給客戶端,服務端業務處理進程再從消息隊列或者數據庫上讀取信息處理業務邏輯。

全面!一文理解微服務高可用的常用手段

②柔性化

什麼是柔性化?想象一個場景,我們的系統會給每個下單的用戶增加他們下單金額對應的積分,當一個用戶下單完畢後,我們給他增加積分的服務出現了問題。

這個時候,我們是要取消掉這個訂單還是先讓訂單通過,積分的問題通過重新或者報警來處理呢?

所謂的柔性化,就是在我們業務中允許的情況下,做不到給予用戶百分百可用的,通過降級的手段給到用戶儘可能多的服務,而不是非得每次都交出去要麼 100 分或 0 分的答卷。

怎麼去做柔性化,更多其實是對業務的理解和判斷,柔性化更多是一種思維,需要對業務場景有深入的瞭解。

在電商訂單的場景中,下單,扣庫存,支付是一定要執行的步驟,如果失敗則訂單失敗。

全面!一文理解微服務高可用的常用手段

但是加積分,發貨,售後是可以柔性處理,就算出錯也可以通過日誌報警讓人工去檢查,沒必要為加積分損失整個下單的可用性。

兜底/容錯

全面!一文理解微服務高可用的常用手段

兜底可能是我們經常談論的一種降級的方案,方案是用來實施,但是這裡兜底可能更多是一種思想,更多的是一種預案,每個操作都可以犯錯,我們也可以接受犯錯。

但是每個犯錯我們都必須有一個兜底的預案,這個兜底的預案其實就是我們的容錯或者說最大程度避免更大傷害的措施,實際上也是一個不斷降級的過程。

舉個例子:

全面!一文理解微服務高可用的常用手段

例如我們首頁請求的用戶個性化推薦商品的接口,發現推薦系統出錯,我們不應該去擴大(直接把異常拋給用戶)或保持調用接口的錯誤,而是應該兼容調用接口的錯誤,做到更加柔性化。

這時候可以選擇獲取之前沒有失敗接口的緩存數據,如果沒有則可以獲取通用商品不用個性化推薦,如果也沒有可以讀取一些靜態文字進行展示。

由於我們架構進行了分層,分層 App,網關,業務邏輯層,數據訪問層等等,在組織結構也進行了劃分,與之對應的是前端組,後端業務邏輯組,甚至有中臺組等等。

既然有代碼和人員架構的層級劃分,那麼每一層都必須有這樣的思想:包容下一層的錯誤,為上一層提供儘可能無錯的服務。

舉個例子:

全面!一文理解微服務高可用的常用手段

商品的美元售價假設要用商品人民幣售價/匯率,這個時候錯誤發生在低層的數據層,上一層如果直接進行除,肯定就拋出 java.lang.ArithmeticException: / by zero。

本著我們對任何一層調用服務都不可信的原則,應該對其進行容錯處理,不能讓異常擴散,更要保證我們這一層對上一次儘可能的作出最大努力確定的服務。

負載均衡

全面!一文理解微服務高可用的常用手段

相信負載均衡這個話題基本已經深入每個做微服務開發或設計者的人心,負載均衡的實現有硬件和軟件。

硬件有 F5,A10 等機器;軟件有 LVS,Nginx,HAProxy 等等,負載均衡的算法有 Random,RoundRobin,ConsistentHash 等等。

①Nginx 負載均衡故障轉移

全面!一文理解微服務高可用的常用手段

轉移流程:Nginx 根據給定好的負載均衡算法進行調度,當請求到 Tomcat1,Nginx 發現 Tomcat1 出現連接錯誤(節點失效),Nginx 會根據一定的機制將 Tomcat1 從調用的負載列表中清除。

在下一次請求,Nginx 不會分配請求到有問題的 Tomcat1 上面,會將請求轉移到其他的 Tomcat 之上。

節點失效:Nginx 默認判斷節點失效是以 connect refuse 和 timeout 為標準,在對某個節點進行 fails 累加,當 fails 大於 max_fails 時,該節點失效。

節點恢復:當某個節點失敗的次數大於 max_fails 時,但不超過 fail_timeout,Nginx 將不再對該節點進行探測,直到超過失效時間或者所有的節點都失效,Nginx 會對節點進行重新探測。

②ZK 負載均衡故障轉移

全面!一文理解微服務高可用的常用手段

在使用 ZK 作為註冊中心時,故障的發現是由 ZK 去進行發現,業務邏輯層通過 Watch 的心跳機制將自己註冊到 ZK 上,網關對 ZK 進行訂閱就可以知道有多少可以調用的列表。

當業務邏輯層在重啟或者被關閉時就會跟 ZK 斷了心跳,ZK 會更新可調用列表。

使用 ZK 作為負載均衡的協調器,最大的問題是 ZK 對於服務是否可用是基於 Pingpong 的方式。

只要服務心跳存在,ZK 就認為服務是處在可用狀態,但是服務如果處在假死的狀態,ZK 是無從得知的。這個時候,業務邏輯服務是否真正可用只能夠由網關知道。

冪等設計:為何會牽出冪等設計的問題,主要是因為負載均衡的 Failover 策略,就是對失敗的服務會進行重試。

一般來說,如果是讀操作的服務,重複執行也不會出問題,但想象一下,如果是一個創建訂單減庫存的操作,第一次調用也 Tomcat1 超時,再重新調用了 Tomcat2。

這個時候我們都不能確認超時調用的 Tomcat1 是否真的被調用,有可能根本就調用不成功,有可能已經調用成功但是因為某些原因返回超時而已。

所以,很大程度這個接口會被調用 2 次。如果我們沒有保證冪等性,就有可能一個訂單導致了減少 2 次的庫存。

所謂的冪等性,就是得保證在同一個業務中,一個接口被調用了多次,其導致的結果都是一樣的。

服務限流降級熔斷

全面!一文理解微服務高可用的常用手段

先來講講微服務中限流/熔斷的目的是什麼,微服務後,系統分佈式部署,系統之間通過 RPC 框架通信,整個系統發生故障的概率隨著系統規模的增長而增長,一個小的故障經過鏈路的傳遞放大,有可能會造成更大的故障。

限流跟高可用的關係是什麼?假定我們的系統最多隻能承受 500 個人的併發訪問,但某個時候突然增加到 1000 個人進來,一下子就把整個系統給壓垮了。

本來還有 500 個人能享受到我們系統的服務,突然間變成了所有人都無法得到服務。

與其讓 1000 人都無法得到服務,不如就讓 500 個人得到服務,拒絕掉另外 500 個人。限流是對訪問的隔離,是保證了部門系統承受範圍內用戶的可用性。

熔斷跟高可用的關係是什麼?上面說了微服務是一個錯綜複雜的調用鏈關係,假設模塊 A 調用模塊 B,模塊 B 又調用了模塊 C,模塊 C 調用了模塊 D。

這個時候,模塊 D 出了問題出現嚴重的時延,這個時候,整個調用鏈就會被模塊 D 給拖垮。

A 等 B,B 等 C,C 等 D,而且 A B C D 的資源被鎖死得不到釋放,如果流量大的話還容易引起雪崩。

熔斷,主動丟棄模塊 D 的調用,並在功能上作出一些降級才能保證到我們系統的健壯性。熔斷是對模塊的隔離,是保證了最大功能的可用性。

服務治理

全面!一文理解微服務高可用的常用手段

①服務模塊劃分

服務模塊與服務模塊之間有著千絲萬縷的關係,但服務模塊在業務中各有權重。

例如訂單模塊可能是一家電商公司的重中之重,如果出問題將會直接影響整個公司的營收。

而一個後臺的查詢服務模塊可能也重要,但它的重要等級絕對是沒有像訂單這麼重要。

所以,在做服務治理時,必須明確各個服務模塊的重要等級,這樣才能更好的做好監控,分配好資源。

這個在各個公司有各個公司的一個標準,例如在電商公司,確定服務的級別可能會更加傾向對用戶請求數和營收相關的作為指標。

全面!一文理解微服務高可用的常用手段

可能真正的劃分要比這個更為複雜,必須根據具體業務去定,這個可以從平時服務模塊的訪問量和流量去預估。

往往更重要的模塊也會提供更多的資源,所以不僅要對技術架構瞭如指掌,還要對公司各種業務形態瞭然於心才可以。

服務分級不僅僅在故障界定起到重要主要,而且決定了服務監控的力度,服務監控在高可用中起到了一個保障的作用。

它不僅可以保留服務崩潰的現場以等待日後覆盤,更重要的是它可以起到一個先知,先行判斷的角色,很多時候可以預先判斷危險,防範於未然。

②服務監控

服務監控是微服務治理的一個重要環節,監控系統的完善程度直接影響到我們微服務質量的好壞。

我們的微服務在線上運行的時候有沒有一套完善的監控體系能去了解到它的健康情況,對整個系統的可靠性和穩定性是非常重要,可靠性和穩定性是高可用的一個前提保證。

服務的監控更多是對於風險的預判,在出現不可用之間就提前的發現問題,如果系統獲取監控報警系統能自我修復則可以將錯誤消滅在無形,如果系統發現報警無法自我修復則可以通知人員提早進行接入。

一個比較完善的微服務監控體系需要涉及到哪些層次?如下圖,大致可以劃分為五個層次的監控:

全面!一文理解微服務高可用的常用手段

基礎設施監控:例如網絡,交換機,路由器等低層設備,這些設備的可靠性穩定性就直接影響到上層服務應用的穩定性。

所以需要對網絡的流量,丟包情況,錯包情況,連接數等等這些基礎設施的核心指標進行監控。

系統層監控:涵蓋了物理機,虛擬機,操作系統這些都是屬於系統級別監控的方面,對幾個核心指標監控,如 CPU 使用率,內存佔用率,磁盤 IO 和網絡帶寬情況。

應用層監控:例如對 URL 訪問的性能,訪問的調用數,訪問的延遲,還有對服務提供性能進行監控,服務的錯誤率。

對 SQL 也需要進行監控,查看是否有慢 SQL,對於 Cache 來說,需要監控緩存的命中率和性能,每個服務的響應時間和 QPS 等等。

業務監控:比方說一個電商網站,需要關注它的用戶登錄情況,註冊情況,下單情況,支付情況。

這些直接影響到實際觸發的業務交易情況,這個監控可以提供給運營和公司高管他們需要關注的數據,直接可能對公司戰略產生影響。

端用戶監控:用戶通過瀏覽器,客戶端打開連到到我們的服務,那麼在用戶端用戶的體驗是怎麼樣,用戶端的性能是怎麼樣,有沒有產生錯誤,這些信息也是需要進行監控並記錄下來。

如果沒有監控,有可能用戶因為某些原因出錯或者性能問題造成體驗非常的差,而我們並沒有感知。

這裡麵包括了,監控用戶端的使用性能,返回碼,在哪些城市地區他們的使用情況是怎麼樣,還有運營商的情況,包括電信,聯通用戶的連接情況。

我們需要進一步去知道是否有哪些渠道哪些用戶接入的時候存在著問題,包括我們還需要知道客戶端使用的操作系統瀏覽器的版本。

總結

"

高可用並不是一套整體解決方案,而是由諸多環節組成,一環扣一環,鬼知道為了這些串聯起來的環節,我得出多少張牌去應對,才能最終組成一個整個系統的高可用落地方案。

全面!一文理解微服務高可用的常用手段

圖片來自 Pexels

什麼是高可用

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

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

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

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

為什麼需要高可用

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

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

高可用的評價緯度

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

全面!一文理解微服務高可用的常用手段

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

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

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

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

微服務高可用設計手段

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

全面!一文理解微服務高可用的常用手段

這中間將會出現的細節是多種多樣的,所以我們需要對這樣一個微服務高可用方案進行一個頂層的設計,圍繞服務高可用,先檢查下我們手裡有多少張牌。

服務冗餘

全面!一文理解微服務高可用的常用手段

①冗餘策略

每一個訪問可能都會有多個服務組合而成,每個機器每個服務都可能出現問題,所以第一個考慮到的就是每個服務必須不止一份可以是多份。

所謂多份一致的服務就是服務的冗餘,這裡說的服務泛指了機器的服務,容器的服務,還有微服務本身的服務。

在機器服務層面需要考慮,各個機器間的冗餘是否有在物理空間進行隔離冗餘。

例如是否所有機器分別部署在不同機房,如果在同一個機房是否做到了部署在不同的機櫃,如果是 Docker 容器是否部署在分別不同的物理機上面。

採取的策略其實也還是根據服務的業務而定,所以需要對服務進行分級評分,從而採取不同的策略。

不同的策略安全程度不同,伴隨著的成本也是不同,安全等級更高的服務可能還不止考慮不同機房,還需要把各個機房所處的區域考慮進行。

例如,兩個機房不要處在同一個地震帶上等等。

全面!一文理解微服務高可用的常用手段

②無狀態化

服務的冗餘會要求我們可以隨時對服務進行擴容或者縮容,有可能我們會從 2 臺機器變成 3 臺機器。

想要對服務進行隨時隨地的擴縮容,就要求我們的服務是一個無狀態化,所謂無狀態化就是每個服務的服務內容和數據都是一致的。

例如,從我們的微服務架構來看,我們總共分水平劃分了好幾個層,正因為我們每個層都做到了無狀態,所以在這個水平架構的擴張是非常的簡單。

假設,我們需要對網關進行擴容,我們只需要增加服務就可以,而不需要去考慮網關是否存儲了一個額外的數據。

全面!一文理解微服務高可用的常用手段

網關不保存任何的 Session 數據,不提供會造成一致性的服務,將不一致的數據進行幾種存儲,藉助更加擅長數據同步的中間件來完成。

這個是目前主流的方案,服務本身儘可能提供邏輯的服務,將數據的一致性保證集中式處理,這樣就可以把“狀態”抽取出來,讓網關保持一個“無狀態”。

這裡僅僅是舉了網關的例子,在微服務基本所有的服務,都應該按照這種思路去做。

如果服務中有狀態,就應該把狀態抽取出來,讓更加擅長處理數據的組件來處理,而不是在微服務中去兼容有數據的狀態。

數據存儲高可用

全面!一文理解微服務高可用的常用手段

之前上面說的服務冗餘,可以簡單的理解為計算的高可用,計算高可用只需要做到無狀態既可簡單的擴容縮容,但是對於需要存儲數據的系統來說,數據本身就是有狀態。

跟存儲與計算相比,有一個本質的差別:將數據從一臺機器搬到另一臺機器,需要經過線路進行傳輸。

網絡是不穩定的,特別是跨機房的網絡,Ping 的延時可能是幾十幾百毫秒,雖然毫秒對於人來說幾乎沒有什麼感覺,但是對於高可用系統來說,就是本質上的不同,這意味著整個系統在某個時間點上,數據肯定是不一致的。

按照“數據+邏輯=業務”的公式來看,數據不一致,邏輯一致,最後的業務表現也會不一致。

舉個例子:

全面!一文理解微服務高可用的常用手段

無論是正常情況下的傳輸延時,還是異常情況下的傳輸中斷,都會導致系統的數據在某個時間點出現不一致。

而數據的不一致又會導致業務出現問題,但是如果數據不做冗餘,系統的高可用無法保證。

所以,存儲高可用的難點不在於怎麼備份數據,而在於如何減少或者規避數據不一致對業務造成的影響。

分佈式領域中有一個著名的 CAP 定理,從理論上論證了存儲高可用的複雜度,也就是說,存儲高可用不可能同時滿足“一致性,可用性,分區容錯性”。

最多隻能滿足 2 個,其中分區容錯在分佈式中是必須的,就意味著,我們在做架構設計時必須結合業務對一致性和可用性進行取捨。

存儲高可用方案的本質是將數據複製到多個存儲設備中,通過數據冗餘的方式來實現高可用,其複雜度主要呈現在數據複製的延遲或中斷導致數據的不一致性。

我們在設計存儲架構時必須考慮到以下幾個方面:

  • 數據怎麼進行復制

  • 架構中每個節點的職責是什麼

  • 數據複製出現延遲怎麼處理

  • 當架構中節點出現錯誤怎麼保證高可用

①數據主從複製

主從複製是最常見的也是最簡單的存儲高可用方案,例如 MySQL,Redis 等等。

全面!一文理解微服務高可用的常用手段

其架構的優點就是簡單,主機複製寫和讀,而從機只負責讀操作,在讀併發高時候可用擴張從庫的數量減低壓力,主機出現故障,讀操作也可以保證讀業務的順利進行。

缺點就是客戶端必須感知主從關係的存在,將不同的操作發送給不同的機器進行處理。

而且主從複製中,從機器負責讀操作,可能因為主從複製時延大,出現數據不一致性的問題。

②數據主從切換

剛說了主從切換存在兩個問題:

  • 主機故障寫操作無法進行。

  • 需要人工將其中一臺從機器升級為主機。

為了解決這個兩個問題,我們可以設計一套主從自動切換的方案,其中涉及到對主機的狀態檢測,切換的決策,數據丟失和衝突的問題。

主機狀態檢測:需要多個檢查點來檢測主機的機器是否正常,進程是否存在,是否出現超時,是否寫操作不可執行,是否讀操作不可執行,將其進行彙總,交給切換決策。

切換決策:確定切換的時間決策,什麼情況下從機就應該升級為主機,是進程不存在,是寫操作不可行,連續檢測多少失敗次就進行切換。

應該選擇哪一個從節點升級為主節點,一般來說或應該選同步步驟最大的從節點來進行升級。切換是自動切換還是半自動切換,通過報警方式,讓人工做一次確認。

數據丟失和數據衝突:數據寫到主機,還沒有複製到從機,主機就掛了,這個時候怎麼處理,這個也得考慮業務的方式,是要確保 CP 或 AP。

全面!一文理解微服務高可用的常用手段

還要考慮一個數據衝突的問題,這個問題在 MySQL 中大部分是由自增主鍵引起。

就算不考慮自增主鍵會引起數據衝突的問題,其實自增主鍵還要引起很多的問題,這裡不細說,避免使用自增主鍵。

③數據分片

上述的數據冗餘可以通過數據的複製來進行解決,但是數據的擴張需要通過數據的分片來進行解決(如果在關係型數據庫是分表)。

全面!一文理解微服務高可用的常用手段

何為數據分片(Segment,Fragment, Shard, Partition),就是按照一定的規則,將數據集劃分成相互獨立、正交的數據子集,然後將數據子集分佈到不同的節點上。

HDFS , MongoDB 的 Sharding 模式也基本是基於這種分片的模式去實現。

我們在設計分片主要考慮到的點是:

  • 做數據分片,如何將數據映射到節點。

  • 數據分片的特徵值,即按照數據中的哪一個屬性(字段)來分片。

  • 數據分片的元數據的管理,如何保證元數據服務器的高性能、高可用,如果是一組服務器,如何保證強一致性。

柔性化/異步化

全面!一文理解微服務高可用的常用手段

①異步化

在每一次調用,時間越長存在超時的風險就越大,邏輯越複雜執行的步驟越多,存在失敗的風險也就越大。

如果在業務允許的情況下,用戶調用只給用戶必須要的結果,而不是需要同步的結果可以放在另外的地方異步去操作,這就減少了超時的風險也把複雜業務進行拆分減低複雜度。

當然異步化的好處是非常多,例如削峰解耦等等,這裡只是從可用的角度出發。

異步化大致有這三種的實現方式:

  • 服務端接收到請求後,創建新的線程處理業務邏輯,服務端先回應答給客戶端

全面!一文理解微服務高可用的常用手段
  • 服務端接收到請求後,服務端先回應答給客戶端,再繼續處理業務邏輯。

全面!一文理解微服務高可用的常用手段
  • 服務端接收到請求後,服務端把信息保存在消息隊列或者數據庫,迴應答給客戶端,服務端業務處理進程再從消息隊列或者數據庫上讀取信息處理業務邏輯。

全面!一文理解微服務高可用的常用手段

②柔性化

什麼是柔性化?想象一個場景,我們的系統會給每個下單的用戶增加他們下單金額對應的積分,當一個用戶下單完畢後,我們給他增加積分的服務出現了問題。

這個時候,我們是要取消掉這個訂單還是先讓訂單通過,積分的問題通過重新或者報警來處理呢?

所謂的柔性化,就是在我們業務中允許的情況下,做不到給予用戶百分百可用的,通過降級的手段給到用戶儘可能多的服務,而不是非得每次都交出去要麼 100 分或 0 分的答卷。

怎麼去做柔性化,更多其實是對業務的理解和判斷,柔性化更多是一種思維,需要對業務場景有深入的瞭解。

在電商訂單的場景中,下單,扣庫存,支付是一定要執行的步驟,如果失敗則訂單失敗。

全面!一文理解微服務高可用的常用手段

但是加積分,發貨,售後是可以柔性處理,就算出錯也可以通過日誌報警讓人工去檢查,沒必要為加積分損失整個下單的可用性。

兜底/容錯

全面!一文理解微服務高可用的常用手段

兜底可能是我們經常談論的一種降級的方案,方案是用來實施,但是這裡兜底可能更多是一種思想,更多的是一種預案,每個操作都可以犯錯,我們也可以接受犯錯。

但是每個犯錯我們都必須有一個兜底的預案,這個兜底的預案其實就是我們的容錯或者說最大程度避免更大傷害的措施,實際上也是一個不斷降級的過程。

舉個例子:

全面!一文理解微服務高可用的常用手段

例如我們首頁請求的用戶個性化推薦商品的接口,發現推薦系統出錯,我們不應該去擴大(直接把異常拋給用戶)或保持調用接口的錯誤,而是應該兼容調用接口的錯誤,做到更加柔性化。

這時候可以選擇獲取之前沒有失敗接口的緩存數據,如果沒有則可以獲取通用商品不用個性化推薦,如果也沒有可以讀取一些靜態文字進行展示。

由於我們架構進行了分層,分層 App,網關,業務邏輯層,數據訪問層等等,在組織結構也進行了劃分,與之對應的是前端組,後端業務邏輯組,甚至有中臺組等等。

既然有代碼和人員架構的層級劃分,那麼每一層都必須有這樣的思想:包容下一層的錯誤,為上一層提供儘可能無錯的服務。

舉個例子:

全面!一文理解微服務高可用的常用手段

商品的美元售價假設要用商品人民幣售價/匯率,這個時候錯誤發生在低層的數據層,上一層如果直接進行除,肯定就拋出 java.lang.ArithmeticException: / by zero。

本著我們對任何一層調用服務都不可信的原則,應該對其進行容錯處理,不能讓異常擴散,更要保證我們這一層對上一次儘可能的作出最大努力確定的服務。

負載均衡

全面!一文理解微服務高可用的常用手段

相信負載均衡這個話題基本已經深入每個做微服務開發或設計者的人心,負載均衡的實現有硬件和軟件。

硬件有 F5,A10 等機器;軟件有 LVS,Nginx,HAProxy 等等,負載均衡的算法有 Random,RoundRobin,ConsistentHash 等等。

①Nginx 負載均衡故障轉移

全面!一文理解微服務高可用的常用手段

轉移流程:Nginx 根據給定好的負載均衡算法進行調度,當請求到 Tomcat1,Nginx 發現 Tomcat1 出現連接錯誤(節點失效),Nginx 會根據一定的機制將 Tomcat1 從調用的負載列表中清除。

在下一次請求,Nginx 不會分配請求到有問題的 Tomcat1 上面,會將請求轉移到其他的 Tomcat 之上。

節點失效:Nginx 默認判斷節點失效是以 connect refuse 和 timeout 為標準,在對某個節點進行 fails 累加,當 fails 大於 max_fails 時,該節點失效。

節點恢復:當某個節點失敗的次數大於 max_fails 時,但不超過 fail_timeout,Nginx 將不再對該節點進行探測,直到超過失效時間或者所有的節點都失效,Nginx 會對節點進行重新探測。

②ZK 負載均衡故障轉移

全面!一文理解微服務高可用的常用手段

在使用 ZK 作為註冊中心時,故障的發現是由 ZK 去進行發現,業務邏輯層通過 Watch 的心跳機制將自己註冊到 ZK 上,網關對 ZK 進行訂閱就可以知道有多少可以調用的列表。

當業務邏輯層在重啟或者被關閉時就會跟 ZK 斷了心跳,ZK 會更新可調用列表。

使用 ZK 作為負載均衡的協調器,最大的問題是 ZK 對於服務是否可用是基於 Pingpong 的方式。

只要服務心跳存在,ZK 就認為服務是處在可用狀態,但是服務如果處在假死的狀態,ZK 是無從得知的。這個時候,業務邏輯服務是否真正可用只能夠由網關知道。

冪等設計:為何會牽出冪等設計的問題,主要是因為負載均衡的 Failover 策略,就是對失敗的服務會進行重試。

一般來說,如果是讀操作的服務,重複執行也不會出問題,但想象一下,如果是一個創建訂單減庫存的操作,第一次調用也 Tomcat1 超時,再重新調用了 Tomcat2。

這個時候我們都不能確認超時調用的 Tomcat1 是否真的被調用,有可能根本就調用不成功,有可能已經調用成功但是因為某些原因返回超時而已。

所以,很大程度這個接口會被調用 2 次。如果我們沒有保證冪等性,就有可能一個訂單導致了減少 2 次的庫存。

所謂的冪等性,就是得保證在同一個業務中,一個接口被調用了多次,其導致的結果都是一樣的。

服務限流降級熔斷

全面!一文理解微服務高可用的常用手段

先來講講微服務中限流/熔斷的目的是什麼,微服務後,系統分佈式部署,系統之間通過 RPC 框架通信,整個系統發生故障的概率隨著系統規模的增長而增長,一個小的故障經過鏈路的傳遞放大,有可能會造成更大的故障。

限流跟高可用的關係是什麼?假定我們的系統最多隻能承受 500 個人的併發訪問,但某個時候突然增加到 1000 個人進來,一下子就把整個系統給壓垮了。

本來還有 500 個人能享受到我們系統的服務,突然間變成了所有人都無法得到服務。

與其讓 1000 人都無法得到服務,不如就讓 500 個人得到服務,拒絕掉另外 500 個人。限流是對訪問的隔離,是保證了部門系統承受範圍內用戶的可用性。

熔斷跟高可用的關係是什麼?上面說了微服務是一個錯綜複雜的調用鏈關係,假設模塊 A 調用模塊 B,模塊 B 又調用了模塊 C,模塊 C 調用了模塊 D。

這個時候,模塊 D 出了問題出現嚴重的時延,這個時候,整個調用鏈就會被模塊 D 給拖垮。

A 等 B,B 等 C,C 等 D,而且 A B C D 的資源被鎖死得不到釋放,如果流量大的話還容易引起雪崩。

熔斷,主動丟棄模塊 D 的調用,並在功能上作出一些降級才能保證到我們系統的健壯性。熔斷是對模塊的隔離,是保證了最大功能的可用性。

服務治理

全面!一文理解微服務高可用的常用手段

①服務模塊劃分

服務模塊與服務模塊之間有著千絲萬縷的關係,但服務模塊在業務中各有權重。

例如訂單模塊可能是一家電商公司的重中之重,如果出問題將會直接影響整個公司的營收。

而一個後臺的查詢服務模塊可能也重要,但它的重要等級絕對是沒有像訂單這麼重要。

所以,在做服務治理時,必須明確各個服務模塊的重要等級,這樣才能更好的做好監控,分配好資源。

這個在各個公司有各個公司的一個標準,例如在電商公司,確定服務的級別可能會更加傾向對用戶請求數和營收相關的作為指標。

全面!一文理解微服務高可用的常用手段

可能真正的劃分要比這個更為複雜,必須根據具體業務去定,這個可以從平時服務模塊的訪問量和流量去預估。

往往更重要的模塊也會提供更多的資源,所以不僅要對技術架構瞭如指掌,還要對公司各種業務形態瞭然於心才可以。

服務分級不僅僅在故障界定起到重要主要,而且決定了服務監控的力度,服務監控在高可用中起到了一個保障的作用。

它不僅可以保留服務崩潰的現場以等待日後覆盤,更重要的是它可以起到一個先知,先行判斷的角色,很多時候可以預先判斷危險,防範於未然。

②服務監控

服務監控是微服務治理的一個重要環節,監控系統的完善程度直接影響到我們微服務質量的好壞。

我們的微服務在線上運行的時候有沒有一套完善的監控體系能去了解到它的健康情況,對整個系統的可靠性和穩定性是非常重要,可靠性和穩定性是高可用的一個前提保證。

服務的監控更多是對於風險的預判,在出現不可用之間就提前的發現問題,如果系統獲取監控報警系統能自我修復則可以將錯誤消滅在無形,如果系統發現報警無法自我修復則可以通知人員提早進行接入。

一個比較完善的微服務監控體系需要涉及到哪些層次?如下圖,大致可以劃分為五個層次的監控:

全面!一文理解微服務高可用的常用手段

基礎設施監控:例如網絡,交換機,路由器等低層設備,這些設備的可靠性穩定性就直接影響到上層服務應用的穩定性。

所以需要對網絡的流量,丟包情況,錯包情況,連接數等等這些基礎設施的核心指標進行監控。

系統層監控:涵蓋了物理機,虛擬機,操作系統這些都是屬於系統級別監控的方面,對幾個核心指標監控,如 CPU 使用率,內存佔用率,磁盤 IO 和網絡帶寬情況。

應用層監控:例如對 URL 訪問的性能,訪問的調用數,訪問的延遲,還有對服務提供性能進行監控,服務的錯誤率。

對 SQL 也需要進行監控,查看是否有慢 SQL,對於 Cache 來說,需要監控緩存的命中率和性能,每個服務的響應時間和 QPS 等等。

業務監控:比方說一個電商網站,需要關注它的用戶登錄情況,註冊情況,下單情況,支付情況。

這些直接影響到實際觸發的業務交易情況,這個監控可以提供給運營和公司高管他們需要關注的數據,直接可能對公司戰略產生影響。

端用戶監控:用戶通過瀏覽器,客戶端打開連到到我們的服務,那麼在用戶端用戶的體驗是怎麼樣,用戶端的性能是怎麼樣,有沒有產生錯誤,這些信息也是需要進行監控並記錄下來。

如果沒有監控,有可能用戶因為某些原因出錯或者性能問題造成體驗非常的差,而我們並沒有感知。

這裡麵包括了,監控用戶端的使用性能,返回碼,在哪些城市地區他們的使用情況是怎麼樣,還有運營商的情況,包括電信,聯通用戶的連接情況。

我們需要進一步去知道是否有哪些渠道哪些用戶接入的時候存在著問題,包括我們還需要知道客戶端使用的操作系統瀏覽器的版本。

總結

全面!一文理解微服務高可用的常用手段

出了那麼多張牌,出牌只是術,真正的道還是得靜下心來看看整個服務高可用的本質是什麼。

隨著微服務架構的相互調用越來越複雜,環節只會越來越多,只有建立清晰的架構和層次才能理清楚每個環節高可用的保障,保持簡單。

從手段看高可用

主要使用的技術手段是服務和數據的冗餘備份和失效轉移,一組服務或一組數據都能在多節點上,之間相互備份。

當一臺機器宕機或出現問題的時候,可以從當前的服務切換到其他可用的服務,不影響系統的可用性,也不會導致數據丟失。

從架構看高可用

保持簡單的架構,目前多數網站採用的是比較經典的分層架構,應用層,服務層,數據層。

應用層是處理一些業務邏輯,服務層提供一些數據和業務緊密相關服務,數據層負責對數據進行讀寫。

簡單的架構可以使應用層,服務層可以保持無狀態化進行水平擴展,這個屬於計算高可用。

相比計算高可用,在數據層思考的高可用則屬於數據高可用,數據高可用相比計算高可用需要考慮到數據的一致性問題會更加的複雜。

這個時候 CAP 理論在裡面會發揮關鍵的作用,究竟是選擇 AP 或 CP,這個得根據業務去選擇模型。

從硬件看高可用

首先得確認硬件總是可能壞的,網絡總是不穩定的。解決它的方法也是一個服務器不夠就來多幾個,一個機櫃不夠就來幾個,一個機房不夠就來幾個。

從軟件看高可用

軟件的開發不嚴謹,發佈不規範也是導致各種不可用出現,通過控制軟件開發過程質量監控,通過測試,預發佈,灰度發佈等手段也是減少不可用的措施。

從治理看高可用

一個系統在線上跑的好好的,但我們也不能確保它在下一秒會不會出現不可用狀態。

將服務規範化,事前做好服務分割,做好服務監控,預判不可用的出現,在不可用出現之前發現問題,解決問題。

【注:文章部分內容參考 李雲華《從 0 開始學架構》楊波老師《微服務》】

作者:陳於喆

簡介:十餘年的開發和架構經驗,國內較早一批微服務開發實施者。曾任職國內互聯網公司網易和唯品會高級研發工程師,後在創業公司擔任技術總監/架構師,目前在洋蔥集團任職技術研發副總監。

高可用架構

改變互聯網的構建方式

"

相關推薦

推薦中...