---
description: gRPC Connectivity Semantics and API
---

# gRPC 客户端连接语义与API

> 原文：[https://github.com/grpc/grpc/blob/master/doc/connectivity-semantics-and-api.md](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 名字多一点的信息就可以构建出来。Channels 封装了一系列功能，包括：名称解析、建立TCP连接(包括 retries 和 backoff)和 TLS 握手。 Channels 还可以处理已建立连接上的错误并重新连接，或者在 HTTP/2 GO\_AWAY 的情况下，重新解析名称并重新连接。

为了对使用 gRPC API的用户(即应用程序代码)隐藏所有此活动的详细信息，同时暴露有关 channel 状态的有意义信息，我们使用了如下定义的五个状态表述的状态机：

### CONNECTING:

标识该 channel 正在尝试建立连接，并且正在等待在 名称解析、TCP 连接建立 或 TLS 握手 中涉及的其中一个步骤上取得进展。它可以被用作创建 channel 时的初始状态。

### READY:

标识该 channel 已经通过 TLS握手(或等效)和协议级(HTTP/2等)握手 成功建立了连接，并且所有后续的通信尝试都已成功(或者在没有任何已知故障的情况下等待)。

### TRANSIENT\_FAILURE:

标识该 channel 出现了一些瞬时故障(例如，TCP 3次握手超时 或 套接字错误)。处于此状态的 channel 最终将切换到 CONNECTING 状态并尝试再次建立连接。

由于重试是通过指数退避(exponential backoff)完成的，因此，连接失败的 channel 在刚开始时在此状态下花费很少的时间，但是随着重复尝试并失败的次数增加，channel 将在此状态下花费越来越多的时间。对于许多非致命故障(例如，由于服务器尚不可用而导致 TCP 连接尝试超时)，channel 可能在该状态下花费越来越多的大量时间。

### IDLE:

这个状态标识由于缺少新的(new)或未决(pending)的RPC，channel 甚至没有尝试创建连接。新的 RPC **可能**会在这个状态被创建。任何在 channel 上启动 RPC 的尝试都会将通道从此状态推送到 CONNECTING 状态。

如果 channel 上已经在指定的 IDLE\_TIMEOUT 时间内没有 RPC 活动，即在此期间没有新的(new)或挂起(pending)的(或活跃的) RPC，则 READY 或 CONNECTING 状态的 channel 将转换到 IDLE 状态。通常情况下，IDLE\_TIMEOUT 的默认值是 300秒。

此外，已经接收到 GOAWAY 的 channel 在没有活跃(active)或挂起(pending)的 RPCs 时，也应当转换到 IDLE 状态，以避免尝试断开连接的服务器上的连接过载。

### SHUTDOWN:

标识该 channel 已经开始关闭。任何新的 RPCs 都应该立即失败。待处理(pending)的 RPCs 可能会继续运行，直到应用程序取消它们。channel 可能会因为应用程序显式请求关闭，或者在尝试连接通信期间发生了不可恢复的错误而进入此状态。(截至2015年12月6日，没有已知的错误(连接或通信时)被归类为不可恢复的错误。)

一旦 channel 进入 SHUTDOWN 状态，就绝不会再离开。也就是说，SHUTDOWN 是状态机的结束。

## 状态转换表

下表列出了合法的状态转换和相关原因。空的单元表示不允许对应的状态转换。

|         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 的当前状态。

在 C++ 中, 这个方法叫 GetState，它会返回一个标识五个合法状态中一个的枚举值。如果 channel 当前处于 IDLE 状态，它还接受布尔值 try\_to\_connect 以转换为 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 状态发生变化时，应用程序(使用 gRPC API 的用户)可以得到通知。由于状态更改可以快速并且与任何此类通知竞争，因此通知应该仅通知用户已经发生了一些状态改变，将其留给用户以轮询该通道以获得当前状态。异步版本的这个 API如下： `bool WaitForStateChange(grpc_connectivity_state source_state, gpr_timespec deadline);`

当状态不是 source\_state 时返回 true，如果截止时间到期则返回 false。Asynchronous- and futures-based 的API应该有一个相应的方法，允许在通道状态发生变化时通知应用程序。

请注意，每当从任何状态转换到任何其他状态时，都会发送通知。

也就是说，合法状态转换的规则要求从 CONNECTING 转换到 TRANSIENT\_FAILURE 并返回到每个可恢复故障的 CONNECTING，即使相应的指数退避在重试之前不需要等待。综合效果是应用程序可能会收到看似虚假的状态更改通知。例如，在 CONNECTING 状态的 channel 上等待状态变更的应用程序，可能会在收到状态更改通知，但在轮询当前状态时发现其依然处于 CONNECTING 状态，因为该 channel 可能在 TRANSIENT\_FAILURE 状态下花费了极少的时间。
