ETCD:gRPC代理


原文地址:gRPC proxy
gRPC代理是在gRPC層(L7)運行的無狀態etcd反向代理。代理旨在減少核心etcd群集上的總處理負載。對於水平可伸縮性,它合並了監視和租約API請求。 為了保護集群免受濫用客戶端的侵害,它會緩存關鍵范圍請求。
gRPC代理支持多個etcd服務器端點。 代理啟動時,它會隨機選擇一個etcd服務器端點來使用.該端點將處理所有請求,直到代理檢測到端點故障為止。 如果gRPC代理檢測到端點故障,它將切換到其他端點(如果有)以向其客戶端隱藏故障。 將來可能會支持其他重試策略,例如加權輪詢。

可擴展的監視 API


gRPC代理將同一鍵或范圍上的多個客戶端監視程序(c-watcher)合並為連接到etcd服務器的單個監視程序(s-watcher)。 代理將所有事件從S-watcher廣播到其c-watcher。
假設N個客戶端監視相同的密鑰,則一個gRPC代理可以將etcd服務器上的監視負載從N減少到1。用戶可以部署多個gRPC代理來進一步分配服務器負載。
在以下示例中,三個客戶端監視鍵A。gRPC代理將三個監視程序合並,從而創建一個附加到etcd服務器的監視程序。

            +-------------+
            | 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 gRPC代理


考慮一個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.它將客戶端請求轉發到上面提供的三個端點之一。
通過代理發送請求:

$ 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命名的端點提供程序。
通過提供用戶定義的前綴來注冊代理:

$ 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

TLS終端


使用來自安全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://localhost2379localhost: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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM