简体   繁体   English

gRPC (cpp) - 如何检查 RPC 通道是否连接成功?

[英]gRPC (cpp) - How can I check if the RPC channel connected successfully?

How can I check if the RPC client actually made a successfull connection to the RPC server when I create the channel and stub?当我创建通道和存根时,如何检查 RPC 客户端是否真的成功连接到 RPC 服务器?

I want to be able to throw an exception or signal if the connection failed.如果连接失败,我希望能够抛出异常或信号。 I am not sure what method qualifies as an "operation" to try here.我不确定什么方法有资格在这里尝试“操作”。 I don't want to make any of the RPC calls that we defined, as they all have effects that will occur....unless the only option is to go implement some "Hi I am here" RPC method, but that seems silly, no?我不想进行我们定义的任何 RPC 调用,因为它们都会产生影响......除非唯一的选择是实现一些“嗨,我在这里”的 RPC 方法,但这似乎很愚蠢, 不?

void ChatSyncClient::connect(QUrl const& endpoint)
{
    disconnect();

    // TODO - How do we tell if this fails?
    //        The comments say a lame channel will be returned, where all operations fail
    //        How are we suppose to check right here rather than later?
    auto channel = ::grpc::CreateChannel(endpoint.toString().toStdString(), ::grpc::InsecureChannelCredentials());
    m_stub = std::make_unique<chat_sync::Chat::Stub>(channel);

    emit signalOnConnected();
}

Before I directly answer your question, let me provide some background.在我直接回答你的问题之前,让我提供一些背景。

A gRPC channel is not actually the same as a connection. gRPC 通道实际上与连接不同。 In fact, a channel may have more than one underlying connection active in parallel, depending on what load balancing policy the channel is using.事实上,一个通道可能有多个并行活动的底层连接,这取决于该通道使用的负载平衡策略。 The intent of the channel API is that it abstracts away the details of individual connections from the application;通道 API 的目的是从应用程序中抽象出各个连接的细节; the idea is that the application should think of a channel as a generic interface on which RPCs are sent, and the channel will internally handle the details of connection management automatically, so the application doesn't have to worry about them.这个想法是应用程序应该将通道视为发送 RPC 的通用接口,并且通道将在内部自动处理连接管理的细节,因此应用程序不必担心它们。

So at a high level, I think that your application should not need to know or care whether the channel is connected.所以在高层次上,我认为您的应用程序应该不需要知道或关心通道是否已连接。 If you think it does need to know that, then I would actually consider that an indication that you need to step back and rethink how you are architecting the application.如果您认为它确实需要知道这一点,那么我实际上会认为这表明您需要退后一步并重新考虑如何构建应用程序。

In particular, I'm not sure exactly what you mean by "I don't want to make any of the RPC calls that we defined, as they all have effects that will occur", but that sounds a little strange to me.特别是,我不确定您所说的“我不想进行我们定义的任何 RPC 调用,因为它们都会产生影响”是什么意思,但这对我来说听起来有点奇怪。 I assume that you mean that there could be effects on the server's state, which implies that the RPC is not idempotent.我假设您的意思是可能会对服务器的状态产生影响,这意味着 RPC 不是幂等的。 You may want to consider changing it to be idempotent somehow, since that is safer (I'll come back to why in a minute).您可能需要考虑以某种方式将其更改为幂等的,因为这样更安全(稍后我会回到为什么)。 But even if you are dealing with a non-idempotent RPC, I don't see how knowing the state of the underlying connection would help you avoid that problem.但即使您正在处理非幂等 RPC,我也看不出知道底层连接的状态将如何帮助您避免该问题。 Even if the channel was connected at the moment the client initiates the RPC, there is never a guarantee that the server will see it, because the connection could fail right after the application tells gRPC to send it but before it goes out on the wire.即使在客户端发起 RPC 的那一刻通道已连接,也永远无法保证服务器会看到它,因为在应用程序告诉 gRPC 发送它之后但在它出去之前,连接可能会失败。 Or the network itself could fail to deliver it to the server after gRPC puts it on the wire.或者,在 gRPC 将其连接到网络后,网络本身可能无法将其传送到服务器。 Or, worse, the server could see it but the network could fail before the server's response gets back to the client.或者,更糟糕的是,服务器可以看到它,但网络可能会在服务器的响应返回给客户端之前出现故障。 There's really no guarantee that an RPC will be atomic, nor is there any guarantee that the client and server will have the same view of whether or not the RPC succeeded.真的不能保证 RPC 是原子的,也不能保证客户端和服务器对 RPC 是否成功有相同的看法。 All the client knows in any of these cases is that the RPC failed, but it cannot infer from that whether or not the server actually saw the RPC.在任何这些情况下,客户端都知道 RPC 失败,但它无法从中推断出服务器是否真的看到了 RPC。

This is why designing your RPCs to be idempotent generally makes more sense.这就是为什么将 RPC 设计为幂等的通常更有意义。 Instead of focusing on whether or not the channel is connecteed, you can focus on whether or not individual RPCs succeed.您可以关注单个 RPC 是否成功,而不是关注通道是否已连接。 Any time the client sees that an RPC has failed, it can retry it.每当客户端发现 RPC 失败时,它都可以重试。 And if the server happens to see the same RPC twice, that won't break things (eg, if you replay a delete operation, it will notice that the data has already been deleted, so it will be a no-op).如果服务器碰巧看到相同的 RPC 两次,这不会破坏事情(例如,如果您重放删除操作,它会注意到数据已经被删除,因此它将是空操作)。

So, my high-level answer is, your client code should react to individual RPC failures, not to connection failures.所以,我的高级回答是,您的客户端代码应该对单个 RPC 失败做出反应,而不是对连接失败做出反应。

All of that having been said, if you do actually want to monitor the channel's connectivity state, you can do so using the connectivity state API .综上所述,如果您确实想要监视通道的连接状态,则可以使用连接状态 API 来实现 Note that a gRPC channel does not actually initiate a connection immediately when you create it.请注意,当您创建 gRPC 通道时,它实际上并不会立即启动连接。 Initially, it is in state IDLE.最初,它处于空闲状态。 It will attempt to connect (and transition to state CONNECTING) when either (a) you send the first RPC on the channel or (b) you call channel->GetState(true) to explicitly ask it to connect.当 (a) 您在通道上发送第一个 RPC 或 (b) 您调用channel->GetState(true)以明确要求它连接时,它将尝试连接(并转换到状态 CONNECTING)。 If the connection attempt fails, the channel will transition to state TRANSIENT_FAILURE, and it will retry periodically.如果连接尝试失败,通道将转换到状态 TRANSIENT_FAILURE,并会定期重试。 When it has established a connection, it will transition to state READY.当它建立了连接时,它将转换到状态 READY。

Any RPC sent on a channel in state TRANSIENT_FAILURE will fail immediately, unless it is wait_for_ready .在状态为 TRANSIENT_FAILURE 的通道上发送的任何 RPC 将立即失败,除非它是wait_for_ready The same is true for an RPC that is still pending when the channel transitions into state TRANSIENT_FAILURE (eg, if the channel was initially in state IDLE and started to connect as a result of the RPC being sent, but then the initial connection attempt failed).对于在通道转换到状态 TRANSIENT_FAILURE 时仍处于挂起状态的 RPC 也是如此(例如,如果通道最初处于 IDLE 状态并由于 RPC 发送而开始连接,但随后初始连接尝试失败) .

With regard to lame channels, note that that only happens in the rare case where you try to create a channel using a malformed target URI that gRPC does not know how to parse.关于蹩脚的通道,请注意,只有在您尝试使用 gRPC 不知道如何解析的格式错误的目标 URI 创建通道的情况下,才会发生这种情况。 If gRPC knows that it will never be able to resolve the name you specified, it will return a lame channel, which is basically a channel that is permanently in state TRANSIENT_FAILURE.如果 gRPC 知道它永远无法解析您指定的名称,它将返回一个蹩脚的通道,它基本上是一个永久处于 TRANSIENT_FAILURE 状态的通道。

I hope this information is helpful.我希望这些信息对你有用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM