(譯)xDS REST and gRPC protocol
xDS REST and gRPC protocol
原文地址:xDS REST and gRPC protocol.
envoy可通過文件系統、一個或多個管理服務器來發現各種動態資源.這些服務發現和他們相對應的API統稱為xDS.通過定閱方式獲取資源,如監控指定的文件路徑、gRPC流或輪詢REST-JSON URL.後兩種使用DiscoveryRequest來發送請求消息.所有的資源包含在DiscoveryResponse響應消息中.下面,我們將討論每種訂閱類型.
文件訂閱
動態配置最簡單的方法是將配置寫入一個文件,文件路徑通過ConfigSource配置.Envoy會使用inotify
(Mac OS X上用kqueue
DiscoveryResponse
進行解析.DiscoveryResponse
支持的格式包括: 二進制protobuf,JSON,YAML和協議文本.
文件訂閱支持統計數據和日誌,不支持ACK/NACK的更新方式.如果配置更新被拒絕,xDS API將使用最近一次的有效配置.
gRPC流訂閱
單資源類型發現
gRPC ApiConfigSource對於xDS API都可單獨配置,指向對應的上遊管理服務器的集群地址.每種xDS資源類型都會各自啟動一個雙向的gRPC流,來對應可能會向不同的管理服務器發起.API的交付方式是最終一致性的.明確控制的順序可看下面的ADS.
URL類型
每個xDS API都與特定的資源類型相關.xDS API和資源類型之間是1:1的.對應關系如下:
- LDS: envoy.api.v2.Listener
- RDS: envoy.api.v2.RouteConfiguration
- CDS: envoy.api.v2.Cluster
- EDS: envoy.api.v2.ClusterLoadAssignment
- SDS: envoy.api.v2.Auth.Secret
URL類型的概念如下所示,其采用type.googleapis.com/<resource type>
形式,例如: CDS對應於type.googleapis.com/envoy.api.v2.Cluster
ACK/NACK和版本控制
每個Enovy以流DiscoveryRequest
開始,包括指定訂閱資源列表,訂閱資源對應的URL類型,結點標誌和空version_info
.EDS的請求例子如下:
version_info:
node: { id: envoy }
resource_names:
- foo
- bar
type_url: type.googleapis.com/envoy.api.v2.ClusterLoadAssignment
response_nonce:
管理服務器會立即或者等待請求可用時以DiscoveryResponse
作為應答.應答例子如下:
version_info: X
resources:
- foo ClusterLoadAssignment proto encoding
- bar ClusterLoadAssignment proto encoding
type_url: type.googleapis.com/envoy.api.v2.ClusterLoadAssignment
nonce: A
處理完DiscoveryResponse
應答之後,將通過流發送一個新請求,請求包括應用成功的最後一個版本號和管理服務器提供的nonce.如果這次更新成功應用,version_info
將被設置為X,時序圖如下:
在此序列圖及後續中,將統一使用以下縮寫格式:
DiscoveryRequest
: (V=version_info
,R=version_info
,N=response_nonce
,T=type_url
)DiscoveryResponse
: (v=version_info
,R=resources
,N=nonce
,T=type_url
)
版本為Envoy和管理服務器提供了共享當前應用配置的概念以及通過ACK/NACK來進行配置更新.如果Envoy拒絕配置更新X,它將返回error_detail和上一個版本號,在當前情況下為空的初始版本號.error_detail
包含了更多的錯誤詳細信息:
後續,API可能會在版本Y上更新成功:
每個流都有自己的版本,跨資源類型沒有共享版本.當不使用ADS時,甚至每個資源類型都可能有不同的版本,因為Envoy API允許不同的EDS/RDS資源配置對應不同的ConfigSource
.
何時發送更新
管理服務器僅在DiscoveryResponse
更改資源時才向Envoy客戶端發送更新.Envoy會根據接受和拒絕的情況,會立即回復包含ACK/NACK的請求.如果管理服務器每次發送相同的資源集而不是等到有改變時再發送,這會導致Envoy和管理服務器的效率大打折扣.
對於同個流,新的DiscoveryRequest
將取代之前具有相同的資源類型請求.這意味著管理服務器只響應最新DiscoveryRequest
的請求,在相同的資源請求下.
資源提示
DiscoveryRequest
中resource_names
作為資源提示出現.一些資源類型,例如:cluster
和listener
將使用一個空的resource_names
列表.因為Envoy需要獲取管理服務器對應於節點標識的所有Cluster
s(CDS)和Listener
s(LDS).對於其它的資源類型,例如:RouteConfiguration
s(RDS)和ClusterLoadAssignment
s(EDS),遵循早期的CDS/LDS更新,Envoy能夠明確地列舉這些資源.
LDS和CDS資源信息始終為空,並且期望管理服務器將在每個響應中提供LDS / CDS資源的完整狀態.缺席的Listener
或Cluster
將被刪除.resource_names
只是一個提示.
對於EDS/RDS,管理服務器不需要提供每個資源的請求,也可能提供額外的未請求資源.Envoy會忽略多余的資源信息.當一個RDS或EDS的更新缺少請求資源時,Envoy將會保留對應資源最後的有效值.管理服務器可能能夠從node標識中推斷出所有所需的EDS/ RDS資源DiscoveryRequest
,在這種情況下,提示信息可能會被丟棄.從特定角度看,一個空的EDS/RDS DiscoveryResponse
響應說明Envoy是一個空的資源.
當Listener
或Cluster
被刪除,Envoy上相應EDS和RDS資源也會被刪除.為了讓Envoy知道或跟蹤EDS資源,必須存在應用過的Cluster
定義(例如:通過CDS獲得).RDS和Listeners
之間也存在相似的關系(通過LDS獲得).
對於EDS/RDS,Envoy可以為每個給定類型的資源生成不同的流(如每個ConfigSource
都有自己的上遊管理服務集群)或當指定資源類型的請求發送到同一個管理服務器的時候,允許將多個資源請求組合在一起發送.雖然可以單個實現,但管理服務器應該能夠為resource_names
每個請求中的給定資源類型處理一個或多個.下面的兩個時序圖都可用於獲取兩個EDS資源{foo, bar}
:
資源更新
如上所述,Envoy可能會更新resource_names
列表在每個DiscoveryRequest
,其中DiscoveryResponse
是用來ACK/NACK管理服務器的特定的.此外,Envoy 後續可能會發送額外的DiscoveryRequest
,用於在特定version_info
上使用新的資源提示來更新管理服務器.舉個例子: 如果Envoy在EDS版本X時僅知道集群foo
,但隨後收到一個CDS更新時額外獲取了集群bar
,它可能會為版本X發出額外的DiscoveryRequest
請求,並將{foo,bar}
作為請求的resource_names
.
這裏可能會出現競爭情況;如果Envoy在版本X上發布了資源提示更新請求,但在管理服務器處理該請求之前發送了新的版本號為Y的響應,對於version_info
為X的版本,資源提示更新可能會被解釋為拒絕Y.為了避免這種情況,管理服務器提供nonce
,Envoy可以用來保證DiscoveryResponse
對應每個DiscoveryRequest
.
管理服務器不應發送DiscoveryResponse
響應給任何過期DiscoveryRequest
請求.Envoy在DiscoveryResponse
響應中包含了新的nonce
,而舊的nonce
將過期做廢.在新的版本就緒前,管理服務器不需要發送更新.同版本的早期請求也會過期.在新版本就緒時,管理服務器可能會處理同版本的多個DiscoveryRequests
請求.
上述資源更新時序圖表明Envoy 並不能期待其發出的每個DiscoveryRequest
請求都能得到DiscoveryResponse
響應.
最終一致性考慮
由於Envoy xDS API采用最終一致性,在更新期會導致流量丟失.舉個例子: 如果通過CDS/EDS僅獲取到了集群X,而且RouteConfiguration
引用了集群X,在CDS/EDS更新集群Y配置之前,如果將集群調整為Y,那麽流量將被丟棄,直到集群Y被Envoy實例獲取.
對某些應用程序,暫時的流量丟失是可接受的,客戶端重試或其它的Envoy sidecar會掩蓋這這些丟失.對於對流量丟失不能容忍的場景,可以通過以下方式避免流量丟失.CDS/EDS更新同時攜帶X和Y,然後發送RDS更新從X切換到Y,最後發送丟棄X的CDS/EDS更新.
通常情況下,為了避免流量丟失,更新的順序應該遵循make before break
模型,其中
- 必須始終先推送CDS更新(如果有).
- EDS更新(如果有)必須在相應群集的CDS更新後到達.
- LDS更新必須在相應的CDS/EDS更新後到達.
- 與新添加的監聽器相關的RDS更新必須最終到達.
- 刪除過期的CDS群集和相關的EDS端點(不再被引用的端點).
如果沒有新的集群/路由/監聽器或者允許更新時臨時流量丟失的情況下,可以單獨推送xDS更新.請註意,在LDS更新的情況下,監聽器須在接收流量之前被預熱,例如: 如果配置了依賴的路由,則需先從RDS獲取規則.添加/刪除/更新集群信息時,集群也要進行預熱.另一方面,路由可以不用預熱,例如: 管理平面確保在更新路由時,集群中的路由已經就緒.
聚合服務發現(ADS)
當管理服務器進行分發時,通過上述保證交互順序的方式來避免流量丟失是一項很有挑戰的工作.ADS允許單一管理服務器,通過gRPC流的方式來分發所有的API更新.配合仔細規劃的更新順序,ADS可規避更新過程中流量丟失.使用ADS,在單個流上可通過URL類型來進行復用多個獨立的DiscoveryRequest
/DiscoveryResponse
序列.對於任何給定類型的URL,以上的DiscoveryRequest
和DiscoveryResponse
消息序列都適合.一個更新的時序圖如下:
對於每個Envoy實例,ADS流都是可用的.
最小化ADS配置的bootstrap.yaml
片段示例如下:
node:
id: <node identifier>
dynamic_resources:
cds_config: {ads: {}}
lds_config: {ads: {}}
ads_config:
api_type: GRPC
grpc_services:
envoy_grpc:
cluster_name: ads_cluster
static_resources:
clusters:
- name: ads_cluster
connect_timeout: { seconds: 5 }
type: STATIC
hosts:
- socket_address:
address: <ADS management server IP address>
port_value: <ADS management server port>
lb_policy: ROUND_ROBIN
http2_protocol_options: {}
admin:
...
增量xDS
增量xDS是可用於允許的ADS、CDS和RDS的單獨xDS端點:
- xDS客戶端對跟蹤資源列表進行增量更新.這支持Envoy按需/惰性地請求額外資源.舉個例子: 當與未知集群相對應的請求到達時,這是有可能發生的.
- xDS服務端可以增量更新客戶端上的資源.這支持xDS資源可伸縮性的目標.管理服務器只需發送給更改的單個集群,而不是在修改單個集群時發送給所有100k集群.
xDS增量會話始終位於gRPC雙向流的上下文中.這允許xDS服務器能夠跟蹤到連接的xDS客戶端的狀態.xDS REST版本不支持增量.
在增量xDS中,nonce字段是必須的,用於匹配IncrementalDiscoveryResponse與IncrementalDiscoveryRequest關聯的ACK或NACK.可選地,響應級別的消息system_version_info僅用來調試.
IncrementalDiscoveryRequest
在以下3種情況發送:
- 在一個雙向gRPC流初始化消息.
- 作為對先前的
IncrementalDiscoveryResponse
的ACK或NACK響應.這種情況下,response_nonce
將在響應中被設為nonce值.ACK或NACK存不存在由error_detail確定. - 由客戶自發.可以動態地添加或刪除被跟蹤
resource_names
集.在這種情況下,response_nonce
必須被忽略.
在第一個示例中,客戶端連接並接收它的第一個更新並ACK,第二次更新失敗,客戶發送NACK拒絕更新,然後xDS客戶端會自發的請求"wc"資源.
在重新連接時,增量的xDS客戶端可能會告訴服務器其已有資源從而避免通過網絡重新發送它們.
輪詢REST-JSOM URL訂閱
通過REST端點進行同步(長)輪詢,也可用於xDS單例API.和上面的消息序列類似,除了在管理服務器沒有保持一個永久的流.在任何時間點只有一個未完成的請求,因此響應現時在REST-JSON中是可選的.proto3的Json編碼規範用於編碼DiscoveryRequest
和DiscoveryResponse
消息.ADS不適用REST-JSON輪詢.
當輪詢周期設置為較小的值時,為了進行長輪詢,則還需要避免發送DiscoveryResponse
,除非對底層資源進行了更改.
(譯)xDS REST and gRPC protocol