Hug*_*ugo 5 streaming bidirectional go grpc
我如何知道另一端已收到我通过 gRPC 流发送的消息?
是否有一种构建方法可以在 gRPC 双向流式传输中执行此操作,或者我是否需要仅使用流式传输,然后发回响应?
原型文件:
service SimpleService {
rpc SimpleRPC (stream SimpleData) returns (stream SimpleData) {}
}
message SimpleData {
string msg = 1;
}
Run Code Online (Sandbox Code Playgroud)
去代码:
client := pb.NewSimpleServiceClient(conn)
stream, err := client.SimpleRPC(context.Background())
waitc := make(chan struct{})
msg := &pb.SimpleData{"sup"}
go func() {
for {
stream.Send(msg)
}
}()
<-waitc
stream.CloseSend()
Run Code Online (Sandbox Code Playgroud)
不幸的是,gRPC 不能很好地处理这种情况。它也不处理单向流,甚至不处理单个 RPC 请求。失败模式(没有流的简单情况)是这样的:
TT-1sec2sec,将其放在T+1sec(超过超时期限)T,并看到错误最好的解决方案是找出一种方法来避免这样做,从服务器的角度来看,使协议无状态——换句话说,如果客户端看到失败,让他们重试。或者,您可以反转连接的方向,以便“服务器”将 RPC 发送到客户端,然后客户端以 ack 进行响应。
困难的地方是服务器存储的内容取决于客户端的状态。例如,假设服务器有一个有序的数据队列,它试图将其发送到客户端,并且它需要知道客户端在从队列中删除项目之前看到的最后一件事是什么。这里的选项是:
ClientRequest内部为对象的oneof对象ClientActualRequest或一个空ClientSuccess对象,表明客户端看到了该消息。然后,在客户端的实现中,让它先发送一个ClientRequest { ClientActualRequest {...} },在接收处理来自服务器的响应后,让它发送一个ClientRequest { ClientSuccess {} },然后终止流。(当然,服务器也必须知道如何处理。)last_known_sequence_number作为协议的一部分发送到服务器,而不是使用 ack 消息,并且服务器只能安全地删除直到该序列号的项目;但是,如果您这样做,则没有简单的方法可以传回更复杂的状态,因为它只是一个序列号。ClientSuccess对象需要对您正在确认的序列号进行编码,以便服务器知道它可以删除哪些内容。这基本上是 TCP 内部所做的事情,但当然只是在从服务器到客户端的方向上进行确认……显然,如果您将解决方案与 TCP 进行比较,我们正在谈论一些非常复杂的东西。请记住,在所有这些情况下,同样,即使 RPC 成功,也不能保证客户端会看到服务器的 ack,在我们的新协议中,服务器也不能保证客户端会看到客户端的 ack。因此,您的客户端需要能够在连接重置时处理查看重复的请求(最多可达您一次允许的任何数量的正在进行的请求)。除非你实现“ack of an ack”,那就是:-P。