原文地址:gRPC proxy
gRPC代理是在gRPC層(L7)運行的無狀態etcd反向代理。代理旨在減小核心etcd羣集上的總處理負載。對於水平可伸縮性,它合併了監視和租約API請求。 爲了保護集羣免受濫用客戶端的侵害,它會緩存關鍵範圍請求。
gRPC代理支持多個etcd服務器端點。 代理啓動時,它會隨機選擇一個etcd服務器端點來使用.該端點將處理全部請求,直到代理檢測到端點故障爲止。 若是gRPC代理檢測到端點故障,它將切換到其餘端點(若是有)以向其客戶端隱藏故障。 未來可能會支持其餘重試策略,例如加權輪詢。git
gRPC代理將同一鍵或範圍上的多個客戶端監視程序(c-watcher)合併爲鏈接到etcd服務器的單個監視程序(s-watcher)。 代理將全部事件從S-watcher廣播到其c-watcher。
假設N個客戶端監視相同的密鑰,則一個gRPC代理能夠將etcd服務器上的監視負載從N減小到1。用戶能夠部署多個gRPC代理來進一步分配服務器負載。
在如下示例中,三個客戶端監視鍵A。gRPC代理將三個監視程序合併,從而建立一個附加到etcd服務器的監視程序。github
+-------------+ | etcd 服務器 | +------+------+ ^ 監視 key A (s-watcher) | +-------+-----+ | gRPC 代理 | <-------+ | | | ++-----+------+ |監視 key A (c-watcher) 監視 key A ^ ^ 監視 key A | (c-watcher) | | (c-watcher) | +-------+-+ ++--------+ +----+----+ | 客戶端 | | 客戶端 | | 客戶端 | | | | | | | +---------+ +---------+ +---------+
爲了有效地將多個客戶端監視程序合併爲一個監視程序,gRPC代理在可能的狀況下將新的c-watcher合併爲現有的s-watcher。 因爲網絡延遲或緩衝的未傳遞事件,此合併的s-watcher可能與etcd服務器不一樣步。 若是未指定監視版本,則gRPC代理將不能保證c-watcher從最近的存儲修訂版本開始監視。 例如,若是客戶端從具備修訂版1000的etcd服務器監視,則該監視程序將從修訂版1000開始。若是客戶端從gRPC代理監視,則能夠從修訂版990開始監視。
相似的限制也適用於取消。 取消觀察者後,etcd服務器的修訂版可能大於取消響應修訂版。
對於大多數用例,這兩個限制不該引發問題。 未來,可能會有其餘選項強制觀察者繞過gRPC代理以得到更準確的修訂響應。api
爲了保持其租約有效,客戶端必須至少向一個etcd服務器創建一個gRPC流,以發送按期的心跳信號。 若是etcd工做負載涉及大量租約活動分佈在許多客戶端上,則這些流可能會致使CPU使用率太高。 爲了減小核心羣集上的流總數,該代理支持租約流合併。
假設N個客戶端正在更新租約,則單個gRPC代理將etcd服務器上的流負載從N減小到1。部署中可能具備其餘gRPC代理,以進一步在多個代理之間分配流。
在如下示例中,三個客戶端更新了三個獨立的租約(L1,L2和L3)。 gRPC代理將三個客戶端租約流(c-stream)合併爲鏈接到etcd服務器的單個租約保持活動流(s-stream)。 代理將客戶端租用心跳從c流轉發到s流,而後將響應返回到相應的c流。緩存
+-------------+ | etcd 服務器 | +------+------+ ^ | 心跳 L1, L2, L3 | (s-stream) v +-------+-----+ | gRPC 代理 +<-----------+ +---+------+--+ | 心跳 L3 ^ ^ | (c-stream) 心跳 L1 | | 心跳 L2 | (c-stream) v v (c-stream) v +------+-+ +-+------+ +-----+--+ | 客戶端 | | 客戶端 | | 客戶端 | +--------+ +--------+ +--------+
gRPC代理在不違反一致性要求時會緩存請求的響應。 這能夠保護etcd服務器免遭嚴密for循環中濫用客戶端的侵害。安全
考慮一個etcd集羣包括如下幾個靜態端點:服務器
名字 | 地址 | 主機名 |
---|---|---|
infra0 | 10.0.1.10 | infra0.example.com |
infra1 | 10.0.1.11 | infra1.example.com |
infra2 | 10.0.1.12 | infra2.example.com |
經過如下命令使用靜態節點啓動gRPC代理:網絡
$ etcd grpc-proxy start --endpoints=infra0.example.com,infra1.example.com,infra2.example.com --listen-addr=127.0.0.1:2379
etcd gRPC啓動並監聽端口2379.它將客戶端請求轉發到上面提供的三個端點之一。
經過代理髮送請求:curl
$ ETCDCTL_API=3 etcdctl --endpoints=127.0.0.1:2379 put foo bar OK $ ETCDCTL_API=3 etcdctl --endpoints=127.0.0.1:2379 get foo foo bar
代理支持經過寫入用戶定義的端點來註冊其端點以進行發現。 這有兩個目的。 首先,它容許客戶端將其端點與一組代理端點同步,以實現高可用性。 其次,它是etcd gRPC命名的端點提供程序。
經過提供用戶定義的前綴來註冊代理:ide
$ etcd grpc-proxy start --endpoints=localhost:2379 \ --listen-addr=127.0.0.1:23790 \ --advertise-client-url=127.0.0.1:23790 \ --resolver-prefix="___grpc_proxy_endpoint" \ --resolver-ttl=60 $ etcd grpc-proxy start --endpoints=localhost:2379 \ --listen-addr=127.0.0.1:23791 \ --advertise-client-url=127.0.0.1:23791 \ --resolver-prefix="___grpc_proxy_endpoint" \ --resolver-ttl=60
代理將會列出成員列表中的全部成員:測試
ETCDCTL_API=3 etcdctl --endpoints=http://localhost:23790 member list --write-out table +----+---------+--------------------------------+------------+-----------------+ | ID | STATUS | NAME | PEER ADDRS | CLIENT ADDRS | +----+---------+--------------------------------+------------+-----------------+ | 0 | started | Gyu-Hos-MBP.sfo.coreos.systems | | 127.0.0.1:23791 | | 0 | started | Gyu-Hos-MBP.sfo.coreos.systems | | 127.0.0.1:23790 | +----+---------+--------------------------------+------------+-----------------+
這使客戶端能夠經過Sync自動發現代理端點:
cli, err := clientv3.New(clientv3.Config{ Endpoints: []string{"http://localhost:23790"}, }) if err != nil { log.Fatal(err) } defer cli.Close() // fetch registered grpc-proxy endpoints if err := cli.Sync(context.Background()); err != nil { log.Fatal(err) }
注意,若是配置的代理沒有解析程序前綴,
$ etcd grpc-proxy start --endpoints=localhost:2379 \ --listen-addr=127.0.0.1:23792 \ --advertise-client-url=127.0.0.1:23792
grpc-proxy的成員列表API返回其本身的advertise-client-url
:
ETCDCTL_API=3 etcdctl --endpoints=http://localhost:23792 member list --write-out table +----+---------+--------------------------------+------------+-----------------+ | ID | STATUS | NAME | PEER ADDRS | CLIENT ADDRS | +----+---------+--------------------------------+------------+-----------------+ | 0 | started | Gyu-Hos-MBP.sfo.coreos.systems | | 127.0.0.1:23792 | +----+---------+--------------------------------+------------+-----------------+
假設一個應用程序指望對整個鍵空間有徹底控制,可是etcd集羣與其餘應用程序共享。 爲了使全部應用程序都不會相互干擾地運行,代理能夠對etcd鍵空間進行分區,以便客戶端能夠訪問完整的鍵空間。 當給代理提供標誌--namespace
時,全部進入代理的客戶端請求都將轉換爲在鍵上具備用戶定義的前綴。 對etcd集羣的訪問將在前綴下,而來自代理的響應將刪除該前綴;對於客戶端,顯然根本沒有前綴。
要爲代理命名空間,請經過--namespace
啓動:
$ etcd grpc-proxy start --endpoints=localhost:2379 \ --listen-addr=127.0.0.1:23790 \ --namespace=my-prefix/
如今,對代理的訪問在etcd集羣上透明地加上前綴:
$ ETCDCTL_API=3 etcdctl --endpoints=localhost:23790 put my-key abc # OK $ ETCDCTL_API=3 etcdctl --endpoints=localhost:23790 get my-key # my-key # abc $ ETCDCTL_API=3 etcdctl --endpoints=localhost:2379 get my-prefix/my-key # my-prefix/my-key # abc
使用來自安全etcd羣集的TLS的gRPC代理終端爲未加密的本地端點提供服務.
使用客戶端https啓動單個成員etcd集羣嘗試:
$ etcd --listen-client-urls https://localhost:2379 --advertise-client-urls https://localhost:2379 --cert-file=peer.crt --key-file=peer.key --trusted-ca-file=ca.crt --client-cert-auth
確認客戶端端口正在提供https:
# fails $ ETCDCTL_API=3 etcdctl --endpoints=http://localhost:2379 endpoint status # works $ ETCDCTL_API=3 etcdctl --endpoints=https://localhost:2379 --cert=client.crt --key=client.key --cacert=ca.crt endpoint status
接下來,經過使用客戶端證書鏈接到etcd端點https://localhost2379
在localhost:12379
上啓動gRPC代理:
$ etcd grpc-proxy start --endpoints=https://localhost:2379 --listen-addr localhost:12379 --cert client.crt --key client.key --cacert=ca.crt --insecure-skip-tls-verify &
最後,經過在http上將密鑰放入代理來測試TLS終端:
$ ETCDCTL_API=3 etcdctl --endpoints=http://localhost:12379 put abc def # OK
gRPC代理爲--endpoints
定義的etcd成員公開了/health
和Prometheus/metrics
端點。 另外一種方法是定義一個附加URL,該URL將使用--metrics-addr
參數來響應/metrics
和/health
端點。
$ etcd grpc-proxy start \ --endpoints https://localhost:2379 \ --metrics-addr https://0.0.0.0:4443 \ --listen-addr 127.0.0.1:23790 \ --key client.key \ --key-file proxy-server.key \ --cert client.crt \ --cert-file proxy-server.crt \ --cacert ca.pem \ --trusted-ca-file proxy-ca.pem
代理的主接口同時服務於HTTP2和HTTP/1.1。若是如上例所示,使用TLS設置了代理,則在監聽接口上使用諸如cURL之類的客戶端時,將要求在返回/metrics
或/health
的請求上將協議顯式設置爲HTTP/1.1。經過使用--metrics-addr
參數,輔助接口將沒有此要求。
$ curl --cacert proxy-ca.pem --key proxy-client.key --cert proxy-client.crt https://127.0.0.1:23790/metrics --http1.1