Mor*_*eat 7 c# compression grpc
使用 C# 时是否可以控制 gRPC 中的响应消息压缩?
这个问题收到了评论,但没有答案。该评论指向gRPC 问题 #10902,其中说:
功能在那里,但您需要通过设置适当的通道选项或在您的 RPC 中设置元数据条目来[启用?]。
链接到那里的测试类显示了几种可能性:
new WriteOptions(WriteFlags.NoCompress)
Run Code Online (Sandbox Code Playgroud)
但这对我没有影响:无论此设置如何,WAN 上的呼叫都需要相同的时间。
var compressionMetadata = new Metadata
{
{ new Metadata.Entry(Metadata.CompressionRequestAlgorithmMetadataKey, "gzip") }
};
Run Code Online (Sandbox Code Playgroud)
同样,测试显示更改此设置时呼叫时间没有变化。(CompressionRequestAlgorithmMetadataKey
常量是内部的,我反编译得到字符串值)。
C# github repo 中有一个诱人的CompressionLevel
枚举,但我找不到它的任何用法。
gRPC 问题 #4170(在 C# 中实现压缩支持)已关闭,但表示
它可以在 C# 中完成,但它绝对不是用户友好的
有没有人能帮我举个例子来说明如何做到这一点?如果它不是用户友好的,我不介意,我只是希望能够做到!我正在通过网络发送一些大的(~8Mb)响应,我想对它们进行一些控制。虽然我可以在发送之前压缩数据,但允许客户端对使用的方法/压缩级别进行一些控制会很好。
(我会发布一些代码,但我只是使用带有大型硬编码字符串的C# 示例代码中的测试代码)
tl;dr 我不知道如何使用 C# gRPC 控制压缩设置。所有看起来可能的设置都不会影响通过线路发送响应所花费的时间。
编辑
在 Jon Skeet 关于查看有线流量的评论之后,我运行了一个新测试,其中响应是The quick brown fox jumps over the lazy dog
重复 5000 次的字符串。我通过以下方式打开了 gRPC 跟踪
Environment.SetEnvironmentVariable("GRPC_TRACE", "compression");
Environment.SetEnvironmentVariable("GRPC_VERBOSITY", "DEBUG");
GrpcEnvironment.SetLogger(new ConsoleLogger());
Run Code Online (Sandbox Code Playgroud)
...在客户端和服务器上。我使用 Wireshark 捕获网络流量,解码我的 gRPC 服务器端口上的 HTTP2 流量。
测试 #1:没有特定的代码来控制压缩
测试 #2:服务器关闭压缩
context.WriteOptions = new WriteOptions(WriteFlags.NoCompress);
在返回响应之前在服务器端设置。 测试 #3:服务器启用压缩
context.ResponseTrailers.Add(new Metadata.Entry("grpc-internal-encoding-request", "gzip"));
在返回响应之前在服务器端设置。 测试 #4:客户端启用压缩
var headers = new Metadata {{new Metadata.Entry("grpc-internal-encoding-request", "gzip")}};
D0228 16:53:21.566026 0 C:\jenkins\workspace\gRPC_build_artifacts\platform\windows\workspace_csharp_ext_windows_x64\src\core\ext\filters\http\message_compress\message_compress_filter.cc:262:算法未启用但已决定压缩. 输入大小:0
编辑#2
Jan Tattermusch 得到了它。在我的服务器端方法中添加此代码
var headers = new Metadata{new Metadata.Entry("grpc-internal-encoding-request", "gzip")};
await context.WriteResponseHeadersAsync(headers);
Run Code Online (Sandbox Code Playgroud)
……成功了!Wireshark 显示响应被压缩并显示 gRPC 日志
压缩 [gzip] 225002 字节与 742 字节(节省 99.67%)
杰出的!可悲的是,它导致了我的下一个问题:压缩的开销导致此方法调用比未压缩的数据慢!
更多的谷歌搜索让我找到了更好的选择:创建Server
对象时,您可以传递ChannelOption
s的集合。我设置如下:
var options = new[] {new ChannelOption("grpc.default_compression_level", (int) CompressionLevel.Low)};
Run Code Online (Sandbox Code Playgroud)
这将压缩设置为更好的级别(对于我在此处发送的数据),并且具有启用 gzip 压缩作为所有调用的默认值的副作用。现在每个方法都必须明确关闭压缩(通过WriteOptions
我的测试 #2 中的)。
有趣的是,尝试通过 覆盖默认压缩grpc-internal-encoding-request
现在非常慢,我猜是由于引发了异常:
src\core\lib\surface\call.cc:1018: prepare_application_metadata: {"created":"@1520008670.738000000","description":"不允许重复的元数据","file":"C:\jenkins\workspace\gRPC_build_artifacts\平台\windows\workspace_csharp_ext_windows_x64\src\core\lib\transport\metadata_batch.cc","file_line":111,"key":"grpc-internal-encoding-request","value":"gzip"}
这意味着我不能在每次调用的基础上修改和更改压缩算法或级别,但考虑到打开压缩后的性能优势,我是一个快乐的人。
测试 #1 和测试 #2 似乎表现符合预期。
测试#3:
测试#4: