【问题标题】:Best practice for defining gRPC metadata about a stream定义有关流的 gRPC 元数据的最佳实践
【发布时间】:2020-10-28 22:41:05
【问题描述】:

我必须向 gRPC 服务器发送消息流,但我还必须发送大量关于流的元数据。有没有办法定义元数据消息并使其成为客户端和服务器之间接口契约的一部分?据我所知,将另一条消息编组到元数据中似乎完全超出了我的 .proto 文件中的接口定义。

真的,我希望 gRPC 允许流式调用具有两个参数,例如:

service DataServer {
    rpc AddData(DataScope, stream MyData) returns (Reply) {}
}

是否有正确的方法,或者至少是一种普遍接受的方法来解决这个问题?

【问题讨论】:

标签: stream metadata grpc rpc grpc-go


【解决方案1】:

这不可能如你所愿(如你所知),但它在功能上等同于:

service DataServer {
    rpc AddStream(AddStreamRequest) returns (AddStreamResponse) {}
    rpc AddData(stream MyData) returns (Reply) {}
}

其中AddStreamResponse 包括在MyData 中引用的唯一(流)标识符。

【讨论】:

  • 感谢您发布此 Daz。我喜欢这个解决方案。我们没有朝这个方向发展的唯一原因是它创建了一些额外的服务器端管理,因为服务器需要跟踪等待未来 AddData 的 AddStream 键/标头。如果客户端搞砸了,服务器可能无法获得匹配的 AddData 并且服务器将开始累积密钥/标头。
【解决方案2】:

很遗憾,这是不可能的。但这里有一个等价物:

您可以使用 oneof 关键字来指定请求应包含配置(范围)或数据。您的客户将很容易理解,其 AddDataRequest 流中的第一个对象必须包含范围,并且以下对象必须包含数据。您的服务器实现必须断言此行为。

service DataServer {
    rpc AddData(stream AddDataRequest) returns (AddDataReply) {}
}

message AddDataRequest {
    oneof request {
        AddDataConfiguration configuration = 1;
        Data data = 2;
    }
}

【讨论】:

  • 我不确定这是否比嵌入在流块中的可选标头消息更好。对于原本只需要一条流消息的短数据,这将始终至少需要两条消息。
【解决方案3】:

我们决定在 MyData 流消息中嵌入一个可选的流定义“标头”消息。我们只在流的第一个 MyData 消息中填充该标头消息。

message StreamBlock {
    DataScope header = 1;
    MyData    data   = 2;
}

当数据足够短以适合单个 MyData protobuf 消息时,它允许我们在单个 gRPC 往返调用中发送标头和数据。当数据较长,拆分成几条MyData消息时,后续消息中未使用的头域不占用空间,因此不会产生额外开销。

【讨论】:

  • 您应该通过 oneof 键定义此行为。看看我的回答
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-09
  • 1970-01-01
相关资源
最近更新 更多