微服務實踐:服務治理
在微服務的演進過程中,為了最大化利用微服務的優勢,保障系統的高可用性,需要通過一些類的服務支撐組件來協助服務間有效的協作,這便是服務治理的范疇。
注冊發現
為什么需要服務注冊發現
在微服務系統中,服務的消費者需要知道服務提供者的網絡地址,才能與之通信。比較簡單的實現方式是直接在消費者端或者負載均衡器上進行注冊,在發生變化時手動更新。隨着服務數量的增多,這種方式會面領如下挑戰:
- 手動注冊實例地址的成本高
- 無法識別服務重啟后的網絡地址的變化
服務注冊發現——客戶端發現
當服務發現的邏輯位於服務消費者端時,稱為客戶端發現。服務發現簡單來說,服務注冊發現的過程(客戶端發現),共分為以下3個步驟:
1、 服務提供者將實例信息注冊到注冊中心。
2、服務調用者根據服務標識,從注冊中心查詢服務,獲取包含網絡地址的服務實例列表。
3、與服務實現通信。
客戶端發現的缺點是實現起來較為復雜,因為在各個服務消費者中需要完成以下功能:首先需要維護服務提供者的列表,並且需要不斷與注冊中心同步以獲取服務最新信息;其次,如果服務部署多實例,服務消費者需要實現路由邏輯,即實現負載均衡器。
服務注冊發現——服務端發現
1、 服務提供者實例向注冊中心注冊地址信息。
2、調用者向服務發送請求,請求被送到負載均衡器。
3、負載均衡器從服務注冊中心查找服務體用這注冊的信息。
4、負載均衡器將請求轉發給具體的服務提供者實例。
服務端發現的好處是服務消費者的實現復雜度會降低。服務消費者只需要發送請求,不需要關心如何與注冊中心交互。缺點是由於多個請求多了一次網絡跳轉,整體性能會有所損失,需要保證它的高可用性。
負載均衡
什么是負載均衡
為了提高可用性、降低延遲,同一個服務可能會部署多個實例,負載均衡就是為了在服務的多個實例之間進行分配負載,已達到優化資源使用、最大化吞吐率,同時避免過載。
服務端負載均衡
優點是負載均衡對於服務消費者來說是透明的,服務消費者完全感知不到負載均衡的存在,也不需要關心具體被轉發至哪個實例。但是當服務數量或調用了增大時,一旦負載均衡器發生故障就導致整個系統不可用。常見的復雜均衡器有如下:
還有一些商用的負載均衡器,如F5、NetScaler、Array、AWD的ELB、華為雲的ELB等。
客戶端負載均衡
將負載均衡的功能以庫的形式集成到服務消費中。服務消費者需要訪問某服務時,需要通過內置的負載均衡組件向服務注冊中心查詢,得到可用的服務提供者列表,然后按照某種負載均衡策略選擇一個目標服務地址,最后向目標服務發起請求。
服務端負載均衡將負載均衡能力實現在服務內部,因此服務消費者與提供者之間是直接調動,沒有額外開銷,性能較好。目前客戶端負載均衡在很多開源框架中都有實現,如Spring Cloud、Dubbo、ServiceComb等。
負載均衡策略
- 隨機策略
- 輪詢策略
- 權重策略
- 響應事件策略
配置管理
服務在運行過程中,需要和其他服務協作,同時他也會依賴基礎設施或其他服務完成某項業務功能。在這個過程中,就需要多樣化的配置信息。
- 基礎設施的連接信息
- 協作服務的地址信息
- 業務行為的配置參數
- 與特性相關的信息
源碼中硬編碼配置信息,雖然實現成本低,但是這種方式不僅缺乏靈活性,而且容易造成信息泄露。因此,較好的方式是將配置與代碼分離。采用獨立於代碼的外部機制存儲配置信息。
微服務的配置管理策略
下圖為集中化的配置管理示意圖:
其配置變更流程如下:
多實例的配置信息變更
對於服務多實例的場景,可以引入輕量級的消息代理,通過廣播事件或者消息的方式通知各個實例更新配置。
容錯機制
生產環境中的每個微服務並不是具有百分百的可靠性。一方面,線性系統的可靠性等於其所包含的每個組件的可靠性之乘積,而各個微服務之間存在錯綜復雜的關系,讓它比線性系統更復雜。另一方面,服務之間跨網絡調用,增加了調用失敗的可能性。因此,如何保證微服務系統的可靠性,也變得更為復雜和困難。所以,微服務系統在設計之初就需要考慮容錯機制,當系統負載過高時,可以確保核心業務不被破壞,以及當某個服務出錯時,把影響范圍降低到最小,避免整個系統不可用。下面介紹一下常見的容錯模式。
限流
服務的流量可能是動態的,如果流量增加,超過服務承載范圍,就會影響用戶掩。通過限制服務能使用的資源,當監控到流量超過設定的閾值時,服務拒絕處理新的用戶請求。當系統壓力過大時,對系統的非核心業務進行限流,避免因壓力過大導致整個系統奔潰。
超時和重試
超時時指當前消費者依賴的服務出現響應延遲時,消費者不用無限等待,而是根據事先設計的超時時間中斷調用,及時釋放Web容器、數據庫等的連接資源。重試通常與超時結合起來,當出現超時時重新發起調用,常用於因網絡抖動等導致服務調用出現超時的場景。
服務雪崩現象如下:
服務提供者不可用——>重試加大流量——>服務消費者不可用
對於服務提供者來說,可通過自動擴容和限流來應對。對於服務消費者來說需要引入服務降級來避免服務雪崩,具體措施包括隔離、熔斷和回退。
服務隔離
微服務架構下系統會包含多個服務,每個服務擁有一個或多個消費者,服務負載過多或故障將影響所有消費者。消費者可以同時向多個服務發送請求,每個請求都消耗資源。當消費者向錯誤配置或未響應的服務發送請求時,客戶端請求使用的資源可能無法及時釋放,繼續對服務請求會耗盡資源,如耗盡客戶端的連接池,導致消費者對其他服務的請求也受到影響,進而不能再向其他服務發送請求。
在軟件行業中,可以考慮通過資源隔離來防止有限的資源被耗盡:
服務A依賴於服務B、C、D,假設運行服務A的容器有120個線程,當服務B不可用時,服務A重試或外部流量增加,服務A的120個線程會因為服務B的不可用而耗盡。
如果采用線程隔離的機制,對於服務B、C、D的調用使用不同的連接池,每個服務各分配40個線程。當服務B不可用時,為服務B分配的線程會被耗盡,而為服務C、D分配的80個線程不受影響,服務A仍然可用。
使用隔離機制的好處在於:
- 防止引發服務級聯故障
- 在發生服務故障的時保留一些功能,系統的其他服務和功能將繼續運行。
熔斷和回退
當電路發生短路時,斷路器能夠主動熔斷電路,以避免災難發生。借用斷路器的原理,引入熔斷機制,在服務出現非臨時性的故障時,先通過回退機制(直接返回錯誤、返回空值/缺省值、返回緩存/備份數據)防止重復嘗試執行可能失敗的操作,同時檢測故障是否持續,是否已解決。如果問題已經修復,則重新發起請求。
熔斷機制可以通過「代理 → 斷路器」統計最近發生的故障數,來決定是否繼續操作或者返回異常。如圖 3-40 所示,斷路器的狀態包括關閉狀態、打開狀態和半開狀態。
● 關閉狀態:在默認情況下,斷路器處於關閉狀態,如果調用持續出錯,失敗計數器在給定時間段內超過了閾值,斷路器進入打開狀態。
● 打開狀態:在指定時間段內,不再向服務提供者發送請求,而是直接回退到失敗的結果,此時斷路器進入打開狀態,並且啟動超時計時器。
● 半開狀態:計時器超時后,斷路器進入半開狀態,即允許發送少量請求進行嘗試,並且通過成功計數器計算成功的請求數。如果調用仍然失敗,則返回到打開狀態,如果成功計數器超過閾值,則斷路器回到關閉狀態。
熔斷機制提供穩定性,讓服務從故障中恢復,並最大限度地減少性能的影響。這種機制可定制性較強,可以根據故障類型進行調整。例如,可以將超時計時器的超時時間逐步增加。最初可以將斷路器置於打開狀態幾秒鍾,然后如果故障沒有解決,將超時時間增加到幾分鍾。