1. 程式人生 > >Netflix如何在上萬臺機器中管理微服務?

Netflix如何在上萬臺機器中管理微服務?

任何一個普通的服務,放到 Netflix 的大規模叢集(上萬臺機器)裡執行,如果不做特別處理,會發生各種各樣的問題,以實現一個電影推薦的服務為例,傳統方案:

Netflix

在傳統的方案裡,你會使用固定 DNS 域名解析服務,將一組固定的 IP 放在負載均衡的列表裡。服務註冊和發現都是寫在配置檔案裡,一旦服務掛掉了,依賴於這個服務的其他服務都會受到影響,傳統的辦法只能新起一臺伺服器,然後去改變其他機器的配置檔案,並重啟關聯的服務。

在小的叢集裡這種方式或許可以忍受,但在上萬臺伺服器的叢集裡,管理500多種服務的時候,情況將變得非常複雜,Netflix 通過多年的實踐,貢獻出了很多開源專案,例如:Eureka, Hystrix, Feign,Ribbon 等等, 來解決大規模叢集裡服務管理的問題。

使用 Eureka 作為服務發現工具

 Eureka

Eureka 是什麼?

Eureka 是 Netflix 貢獻出來的開源中間層負載均衡和服務發現的工具。Eureka 基於 Java 實現,可以非常方便的在 Spring 應用程式裡宣告 Server 和 Client 進行服務註冊。

Eureka 解決的問題

Eureka

Eureka 伺服器是服務的註冊中心,它能提高大規模叢集環境裡服務發現的容錯性和可用性。並且可以解決跨資料中心之間的服務註冊和發現的問題。

Netflix 推薦在每個 Region 搭建一個 Eureka 叢集,每個 Region 裡的可用區至少有一個 Eureka Server,這樣可以保證任意一個可用區的服務註冊資訊都會被複制到各個可用區,實現服務資訊的高可用。在任意可用區的客戶端都可以訪問到服務的註冊資訊。客戶端在訪問伺服器之後會在本地快取服務的資訊,並且定期(30秒)重新整理服務的狀態。

如果在叢集內有大面積的網路故障時(例如由於交換機故障導致子網之間無法通訊),Eureka 會進入自我保護模式,每個Eureka節點會持續的對外提供服務(注:ZooKeeper不會):接收新的服務註冊同時將它們提供給下游的服務發現請求。這樣就可以實現在同一個子網中(Same side of partition),新發布的服務仍然可以被發現與訪問。

在 Eureka V1.0的版本里,Eureka 之間的資料同步是全量同步,每個客戶端都有 Eureka 叢集裡所有服務的資訊,在 V2.0的版本里,將支援客戶端偏好的服務資訊同步。同時也會增強 Eureka 的讀寫分離和高可用性。

有了 Eureka,Netflix 如何做紅黑髮布?

Netflix 釋出的方式是紅黑髮布。如果監控到線上部署的服務有問題,按傳統方式回滾一個服務需要5-15分鐘。而 Netflix 使用 Eureka 能夠動態的下線/上線一個服務。

服務分兩種:REST 服務和非 REST 服務。如果下線的服務是 REST 服務,那麼情況比較簡單,通過 Eureka 可以實時的實現服務的下線和上線。

如果服務是非 REST 服務,例如執行 Batching 任務或者快服務的 Transaction 等等,就不能簡單的標記服務下線,藉助於 Spring 提供的 EventListener (事件監聽器),Eureka 可以傳遞
EurekaStatusChangeEvent 事件,幫助開發者在這個事件監聽器裡去做對應的服務下線處理。

Netflix 在實現紅黑髮布的時候,會先將一部分的服務動態下線,如果這些服務有一些 Batching 任務,則通過事件監聽器停掉這些任務。

為什麼 Netflix 沒有選擇使用 ZooKeeper 做服務發現?

因為當 ZooKeeper 在處理上千個節點時,由於故障發生次數不高,可能可以應對,但是達到上萬節點之後,ZooKeeper 的表現不如 Eureka,因為在這種體量的叢集裡,叢集故障是時刻都在發生的,如果每次都重新進行選舉的代價太大,而 Eureka 會根據 CAP 理論中的 AP 策略,採用了最終一致的方案。

其次,Eureka 提供了 REST endpoint 支援服務的註冊,這樣解決能 Non-Java 服務的註冊問題。

Hystrix 做服務降級

Hystrix 是 Netflix 開源的元件,它能夠幫助服務之間呼叫超時,報錯時,阻止問題的擴散,避免雪崩。在使用者無感知的情況下對服務進行降級處理。

Hystrix

舉例:當你試圖為你的使用者進行電影推薦時,出於某種原因服務呼叫一直沒有返回(可能依賴的 User 服務掛了),Hystrix 可以定義多種策略來判斷服務是否健康。例如:為 Hystrix 預設一個 timeout 時間,如果服務呼叫的返回結果超過這個時間,Hystrix 會決定觸發熔斷機制,暫定該服務的呼叫,並返回一個通用的電影列表作為推薦,而不是讓使用者無休止的等下去,從而提高使用者體驗。

當然,超時時間只是 Hystrix 做熔斷決策的一個條件,你可以為 Hystrix 設定多個條件來讓判斷某個服務呼叫是否正常,比如服務的 corePoolSize, maximumPoolSize and keepAliveTime 都可以作為 Hystrix 熔斷的策略。

Hystrix 提供了 Circuit Break 來檢測服務的健康狀態,Circuit Break 解決了以下問題:

1. 檢查服務的狀態。
2. 支援執行緒和資源訪問的隔離。當服務的併發訪問特別大時(每秒上百個連線),Circuit Break 會對執行緒進行隔離,或者對資源訪問做限制,保證服務的可用性。

下圖是 Circuit Break Open/Close 的決策流程:

流程

1. 如果服務呼叫的錯誤率高於預先設定的錯誤率。
2. Circuit-breaker 的狀態會從 CLOSED 變成 OPEN(熔斷狀態)。
3. 當 Circuit-breaker 狀態為 OPEN 時,所有進來的請求會被阻止。
4. 過一段時間,會讓一些單個的請求進來(Half-Open),如果服務呼叫仍然失敗,Circuit-breaker 會再次進入 OPEN 狀態,如果請求成功,Circuit-breaker 狀態變為 CLOSED 並且重新進入第一步。

目前,Hystrix 正在對跨服務事務(Transaction)處理進行優化中。

Ribbon 作為負載均衡

Ribbon 是 Netflix OSS 貢獻的處理 RPC 呼叫的軟負載均衡。除了傳統負載均衡的能力之外,它還能解決以下問題:
1. 當監控到叢集內有9臺伺服器提供同一個服務,其中有三臺的響應明顯有問題,Ribbon 可以臨時將這三臺伺服器從負載均衡中剔除,直到這三臺機器恢復正常的響應。

2. 可以對響應最快的伺服器進行加權,將更多的流量帶到響應最快的節點。

3. 支援將多種負載均衡的策略同時啟用,將負載均衡的效果除錯到最好。

4. 自定義設定重試機制。
雖然 Ribbon 專案處於維護狀態,但是它的實現思路仍然值得大家借鑑。

總結

本文主要介紹了 Netflix OSS 貢獻的 Eureka,Hystrix 和 Ribbon,由於篇幅限制,其他的元件將在後續的文章中介紹, 這些開源元件和 Spring Boot/Spring Cloud 都有良好的整合,通過註解的方式配合 Properties 檔案,能夠解決管理大規模服務時遇到的通用問題。

本文的目的是希望通過解讀 Netflix 在實現大規模擴容時遇到的問題,分析他們的解決辦法,為將來自己碰到問題時提供一些思路,思路和視野有時候比工具本身更重要。

參考資料:

https://github.com/Netflix/eureka/wiki
https://github.com/Netflix/Hystrix