gRPC Connectivity Semantics and API
原文:https://github.com/grpc/grpc/blob/master/doc/connectivity-semantics-and-api.md
本文主要描述 gRPC 通道的連接語義以及對 RPC 的相應影響纪铺,然后再探討下 API芦倒。
States of Connectivity
gRPC Channels 提供了一種 clients 與 servers 交互的抽象猾骡〕ι客戶端的 channel 對象可以通過使用一個 DNS 名字多一點的信息就可以構(gòu)建出來土辩。Channels 封裝了一系列功能遭赂,包括:名稱解析、建立TCP連接(包括 retries 和 backoff)和 TLS 握手臭增。
Channels 還可以處理已建立連接上的錯誤并重新連接懂酱,或者在 HTTP/2 GO_AWAY 的情況下,重新解析名稱并重新連接誊抛。
為了對使用 gRPC API的用戶(即應用程序代碼)隱藏所有此活動的詳細信息列牺,同時暴露有關 channel 狀態(tài)的有意義信息,我們使用了如下定義的五個狀態(tài)表述的狀態(tài)機:
CONNECTING:
標識該 channel 正在嘗試建立連接拗窃,并且正在等待在 名稱解析瞎领、TCP 連接建立 或 TLS 握手 中涉及的其中一個步驟上取得進展。它可以被用作創(chuàng)建 channel 時的初始狀態(tài)随夸。
READY:
標識該 channel 已經(jīng)通過 TLS握手(或等效)和協(xié)議級(HTTP/2等)握手 成功建立了連接九默,并且所有后續(xù)的通信嘗試都已成功(或者在沒有任何已知故障的情況下等待)。
TRANSIENT_FAILURE:
標識該 channel 出現(xiàn)了一些瞬時故障(例如宾毒,TCP 3次握手超時 或 套接字錯誤)驼修。處于此狀態(tài)的 channel 最終將切換到 CONNECTING 狀態(tài)并嘗試再次建立連接。
由于重試是通過指數(shù)退避(exponential backoff)完成的,因此乙各,連接失敗的 channel 在剛開始時在此狀態(tài)下花費很少的時間墨礁,但是隨著重復嘗試并失敗的次數(shù)增加,channel 將在此狀態(tài)下花費越來越多的時間耳峦。對于許多非致命故障(例如恩静,由于服務器尚不可用而導致 TCP 連接嘗試超時),channel 可能在該狀態(tài)下花費越來越多的大量時間妇萄。
IDLE:
這個狀態(tài)標識由于缺少新的(new)或未決(pending)的RPC蜕企,channel 甚至沒有嘗試創(chuàng)建連接咬荷。新的 RPC 可能會在這個狀態(tài)被創(chuàng)建冠句。任何在 channel 上啟動 RPC 的嘗試都會將通道從此狀態(tài)推送到 CONNECTING 狀態(tài)。
如果 channel 上已經(jīng)在指定的 IDLE_TIMEOUT 時間內(nèi)沒有 RPC 活動幸乒,即在此期間沒有新的(new)或掛起(pending)的(或活躍的) RPC懦底,則 READY 或 CONNECTING 狀態(tài)的 channel 將轉(zhuǎn)換到 IDLE 狀態(tài)。通常情況下罕扎,IDLE_TIMEOUT 的默認值是 300秒聚唐。
此外,已經(jīng)接收到 GOAWAY 的 channel 在沒有活躍(active)或掛起(pending)的 RPCs 時腔召,也應當轉(zhuǎn)換到 IDLE 狀態(tài)杆查,以避免嘗試斷開連接的服務器上的連接過載。
SHUTDOWN:
標識該 channel 已經(jīng)開始關閉臀蛛。任何新的 RPCs 都應該立即失敗亲桦。待處理(pending)的 RPCs 可能會繼續(xù)運行,直到應用程序取消它們浊仆。channel 可能會因為應用程序顯式請求關閉客峭,或者在嘗試連接通信期間發(fā)生了不可恢復的錯誤而進入此狀態(tài)。(截至2015年12月6日抡柿,沒有已知的錯誤(連接或通信時)被歸類為不可恢復的錯誤舔琅。)
一旦 channel 進入 SHUTDOWN 狀態(tài),就絕不會再離開洲劣。也就是說备蚓,SHUTDOWN 是狀態(tài)機的結(jié)束。
狀態(tài)轉(zhuǎn)換表
下表列出了合法的狀態(tài)轉(zhuǎn)換和相關原因囱稽〗汲ⅲ空的單元表示不允許對應的狀態(tài)轉(zhuǎn)換。
From/To | CONNECTING | READY | TRANSIENT_FAILURE | IDLE | SHUTDOWN |
---|---|---|---|---|---|
CONNECTING | Incremental progress during connection establishment | All steps needed to establish a connection succeeded | Any failure in any of the steps needed to establish connection | No RPC activity on channel for IDLE_TIMEOUT | Shutdown triggered by application. |
READY | Incremental successful communication on established channel. | Any failure encountered while expecting successful communication on established channel. | No RPC activity on channel for IDLE_TIMEOUT OR upon receiving a GOAWAY while there are no pending RPCs. | Shutdown triggered by application. | |
TRANSIENT_FAILURE | Wait time required to implement (exponential) backoff is over. | Shutdown triggered by application. | |||
IDLE | Any new RPC activity on the channel | Shutdown triggered by application. | |||
SHUTDOWN |
Channel State API
所有的 gRPC 庫都應該暴露一個 channel-level 的 API 方法以輪詢 channel 的當前狀態(tài)粗悯。
在 C++ 中, 這個方法叫 GetState虚循,它會返回一個標識五個合法狀態(tài)中一個的枚舉值。如果 channel 當前處于 IDLE 狀態(tài),它還接受布爾值 try_to_connect 以轉(zhuǎn)換為 CONNECTING横缔。The boolean should act as if an RPC occurred, so it should also reset IDLE_TIMEOUT.
grpc_connectivity_state GetState(bool try_to_connect);
所有的 gRPC 庫還應該暴露一個 API 以在當 channel 狀態(tài)發(fā)生變化時铺遂,應用程序(使用 gRPC API 的用戶)可以得到通知。由于狀態(tài)更改可以快速并且與任何此類通知競爭茎刚,因此通知應該僅通知用戶已經(jīng)發(fā)生了一些狀態(tài)改變襟锐,將其留給用戶以輪詢該通道以獲得當前狀態(tài)。異步版本的這個 API如下:
bool WaitForStateChange(grpc_connectivity_state source_state, gpr_timespec deadline);
當狀態(tài)不是 source_state 時返回 true膛锭,如果截止時間到期則返回 false粮坞。Asynchronous- and futures-based 的API應該有一個相應的方法,允許在通道狀態(tài)發(fā)生變化時通知應用程序初狰。
請注意莫杈,每當從任何狀態(tài)轉(zhuǎn)換到任何其他狀態(tài)時,都會發(fā)送通知奢入。
也就是說筝闹,合法狀態(tài)轉(zhuǎn)換的規(guī)則要求從 CONNECTING 轉(zhuǎn)換到 TRANSIENT_FAILURE 并返回到每個可恢復故障的 CONNECTING,即使相應的指數(shù)退避在重試之前不需要等待腥光。綜合效果是應用程序可能會收到看似虛假的狀態(tài)更改通知关顷。例如,在 CONNECTING 狀態(tài)的 channel 上等待狀態(tài)變更的應用程序武福,可能會在收到狀態(tài)更改通知议双,但在輪詢當前狀態(tài)時發(fā)現(xiàn)其依然處于 CONNECTING 狀態(tài),因為該 channel 可能在 TRANSIENT_FAILURE 狀態(tài)下花費了極少的時間捉片。