服務發現
當在設定中定義上游叢集時,Envoy 需要知道如何解析叢集的成員。這稱為服務發現。
支援的服務發現類型
靜態 (Static)
靜態是最簡單的服務發現類型。設定會明確指定每個上游主機的已解析網路名稱 (IP 位址/埠號、Unix 網域套接字等)。
嚴格 DNS (Strict DNS)
使用嚴格 DNS 服務發現時,Envoy 會持續且非同步地解析指定的 DNS 目標。DNS 結果中傳回的每個 IP 位址都會被視為上游叢集中的明確主機。這表示如果查詢傳回三個 IP 位址,Envoy 會假設叢集有三個主機,並且應該對所有三個主機進行負載平衡。如果從結果中移除主機,Envoy 會假設它不再存在,並會從任何現有的連線池中排空流量。因此,如果成功的 DNS 解析傳回 0 個主機,Envoy 會假設叢集沒有任何主機。請注意,Envoy 永遠不會在轉送路徑中同步解析 DNS。以最終一致性為代價,永遠不用擔心會被長時間執行的 DNS 查詢阻塞。
如果單個 DNS 名稱多次解析為相同的 IP,這些 IP 將會被去重複。
如果多個 DNS 名稱解析為相同的 IP,則健康檢查將不會共享。這表示如果在使用解析為相同 IP 的 DNS 名稱時使用主動健康檢查,應多加注意:如果 IP 在 DNS 名稱之間重複多次,可能會對上游主機造成不必要的負載。
如果啟用respect_dns_ttl,則 DNS 記錄 TTL 和 dns_refresh_rate 用於控制 DNS 重新整理速率。對於嚴格 DNS 叢集,如果所有記錄 TTL 的最小值為 0,則 dns_refresh_rate 將用作叢集的 DNS 重新整理速率。dns_refresh_rate 如果未指定,則預設為 5000 毫秒。dns_failure_refresh_rate 控制失敗期間的重新整理頻率,如果未設定,則將使用 DNS 重新整理速率。
DNS 解析會發出叢集統計資訊欄位 update_attempt、update_success 和 update_failure。
邏輯 DNS (Logical DNS)
邏輯 DNS 使用與嚴格 DNS 相似的非同步解析機制。但是,邏輯 DNS 叢集不是嚴格採用 DNS 查詢的結果並假設它們構成整個上游叢集,而是僅在需要啟動新連線時使用傳回的第一個 IP 位址。因此,單個邏輯連線池可能包含與各種不同上游主機的實體連線。連線永遠不會排空,包括在成功傳回 0 個主機的 DNS 解析上。
這種服務發現類型對於必須透過 DNS 存取的大型網路服務來說是最佳的。此類服務通常使用循環 DNS 來傳回許多不同的 IP 位址。通常,每次查詢都會傳回不同的結果。如果在此情況下使用嚴格 DNS,Envoy 會假設叢集的成員在每次解析間隔期間都在變更,這會導致排空連線池、連線循環等。相反地,使用邏輯 DNS 時,連線會保持活動狀態,直到它們被循環為止。在與大型網路服務互動時,這是所有可能情況中的最佳選擇:非同步/最終一致的 DNS 解析、長期連線以及轉送路徑中的零阻塞。
如果啟用respect_dns_ttl,則 DNS 記錄 TTL 和 dns_refresh_rate 用於控制 DNS 重新整理速率。對於邏輯 DNS 叢集,如果第一個記錄的 TTL 為 0,則 dns_refresh_rate 將用作叢集的 DNS 重新整理速率。dns_refresh_rate 如果未指定,則預設為 5000 毫秒。dns_failure_refresh_rate 控制失敗期間的重新整理頻率,如果未設定,則將使用 DNS 重新整理速率。
DNS 解析會發出叢集統計資訊欄位 update_attempt、update_success 和 update_failure。
原始目的地 (Original destination)
當傳入連線透過 iptables REDIRECT 或 TPROXY 目標或使用 Proxy Protocol 重新導向至 Envoy 時,可以使用原始目的地叢集。在這些情況下,路由至原始目的地叢集的請求會轉送至重新導向中繼資料所定址的上游主機,而無需任何明確的主機設定或上游主機探索。與上游主機的連線會被放入池中,並且未使用的主機在任何連線池未使用時間超過 cleanup_interval 時會被清除,該值預設為 5000 毫秒。如果原始目的地位址不可用,則不會開啟任何上游連線。Envoy 也可以從 HTTP 標頭 中擷取原始目的地。原始目的地服務發現必須與原始目的地負載平衡器一起使用。當使用原始目的地叢集進行 HTTP 上游時,請將 idle_timeout 設定為 5 分鐘,以限制上游 HTTP 連線的持續時間。
端點探索服務 (EDS) (Endpoint discovery service (EDS))
端點探索服務是 Envoy 用來擷取叢集成員的基於 gRPC 或 REST-JSON API 伺服器的 xDS 管理伺服器。在 Envoy 術語中,叢集成員稱為「端點」。對於每個叢集,Envoy 都會從探索服務擷取端點。EDS 是首選的服務發現機制,原因如下:
Envoy 具有每個上游主機的明確知識 (相對於透過 DNS 解析的負載平衡器進行路由),並且可以做出更智慧的負載平衡決策。
探索 API 回應中針對每個主機攜帶的額外屬性會通知 Envoy 主機的負載平衡權重、 Canary 狀態、區域等。這些額外的屬性會在全球 Envoy 網格中於負載平衡、統計資料收集等期間使用。
自訂叢集 (Custom cluster)
Envoy 也支援自訂叢集探索機制。自訂叢集是使用叢集設定上的 cluster_type 欄位 來指定的。
一般而言,主動健康檢查會與最終一致的服務發現服務資料結合使用,以做出負載平衡和路由決策。這將在以下章節中進一步討論。
關於最終一致的服務發現
許多現有的 RPC 系統都將服務發現視為完全一致的程序。為此,它們使用完全一致的領導者選舉後端儲存,例如 Zookeeper、etcd、Consul 等。我們的經驗是,大規模運作這些後端儲存是痛苦的。
Envoy 從一開始就設計了服務發現不需要完全一致的概念。相反地,Envoy 假設主機會以最終一致的方式在網格中來來去去。我們建議將服務部署至服務 Envoy 網格設定的方式是使用最終一致的服務發現以及主動健康檢查 (Envoy 明確檢查上游叢集成員的健康狀況) 來判斷叢集健康狀況。此範例具有許多好處:
所有健康狀況決策都是完全分散的。因此,網路分割會被順利處理 (應用程式是否順利處理分割是另一回事)。
當為上游叢集設定健康檢查時,Envoy 會使用 2x2 矩陣來判斷是否路由到主機
探索狀態 (Discovery Status) |
健康檢查正常 (Health Check OK) |
健康檢查失敗 (Health Check Failed) |
---|---|---|
已探索 (Discovered) |
路由 (Route) |
不路由 (Don’t Route) |
不存在 (Absent) |
路由 (Route) |
不路由/刪除 (Don’t Route / Delete) |
- 已探索的主機/健康檢查正常 (Host discovered / health check OK)
Envoy 將路由至目標主機。
- 主機不存在/健康檢查正常 (Host absent / health check OK)
Envoy 將會路由至目標主機。這點非常重要,因為設計上假設探索服務隨時可能失效。如果主機即使在探索資料中不存在後仍持續通過健康檢查,Envoy 仍然會進行路由。儘管在這種情況下無法新增主機,但現有的主機將會繼續正常運作。當探索服務再次正常運作時,資料最終會重新收斂。
- 已探索到的主機 / 健康檢查失敗
Envoy 將不會路由至目標主機。健康檢查資料被認為比探索資料更準確。
- 主機不存在 / 健康檢查失敗
Envoy 將不會路由並且會刪除目標主機。這是 Envoy 會清除主機資料的唯一狀態。