使用C#时,是否可以在gRPC中控制响应消息压缩?
This question收到了评论,但没有回答。该评论指向gRPC issue #10902,其中说:
功能就在那里,但是您需要通过设置适当的通道选项或在RPC中设置元数据条目来[启用?]。
那里连接的test class显示了一些可能性:
new WriteOptions(WriteFlags.NoCompress)
但这对我没有影响:无论此设置如何,通过WAN进行的呼叫都需要相同的时间。
var compressionMetadata = new Metadata
{
{ new Metadata.Entry(Metadata.CompressionRequestAlgorithmMetadataKey, "gzip") }
};
同样,测试显示此设置更改时呼叫时间没有变化。 (CompressionRequestAlgorithmMetadataKey
常量是内部的,我反编译得到字符串值)。
有一个诱人的CompressionLevel
枚举in the C# github repo但我找不到任何使用它。
gRPC issue #4170(在C#中实现压缩支持)已经关闭但是说
它可以在C#中完成,但它绝对不是用户友好的
有人能够帮我提供一个关于如何做到这一点的例子吗?我不介意它不是用户友好的,我只是想能够做到!我正在通过线路发送一些大的(~8Mb)响应,我想对它们有一些控制权。虽然我可以在发送之前压缩数据,但允许客户端对所使用的方法/压缩级别进行一些控制会很好。
(我会发布一些代码,但我只是使用C# sample code中带有大型硬编码字符串的测试代码)
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());
...在客户端和服务器上。我使用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:算法'gzip'已启用但决定不压缩。输入大小:0
编辑#2 Jan Tattermusch明白了。在我的服务器端方法中添加此代码
var headers = new Metadata{new Metadata.Entry("grpc-internal-encoding-request", "gzip")};
await context.WriteResponseHeadersAsync(headers);
......做了伎俩! Wireshark显示响应被压缩并显示gRPC日志
压缩[gzip] 225002字节与742字节(节省99.67%)
辉煌!遗憾的是它导致了我的下一个问题:压缩的开销导致此方法调用比未压缩的数据慢!
更多谷歌搜索引导我找到更好的选择:当创建Server
对象时,您可以传递ChannelOption
s的集合。我将其设置如下:
var options = new[] {new ChannelOption("grpc.default_compression_level", (int) CompressionLevel.Low)};
这将压缩设置为更好的级别(对于我在此处发送的数据),并且具有启用gzip压缩作为所有调用的默认值的副作用。现在每个方法必须明确地关闭压缩(通过我的测试#2中的WriteOptions
)。
有趣的是,尝试通过grpc-internal-encoding-request
覆盖默认压缩现在非常慢,我猜是由于异常被提出:
src \ core \ lib \ surface \ call.cc:1018:prepare_application_metadata:{“created”:“@ 1520008670.738000000”,“description”:“不允许重复的元数据”,“文件”:“C:\ jenkins \ workspace \ gRPC_build_artifacts \平台\ Windows \ workspace_csharp_ext_windows_x64 \ SRC \芯\ lib中\传输\ metadata_batch.cc”, “file_line”:111, “密钥”: “GRPC编码内部请求”, “值”: “gzip的”}
这意味着我无法在每个呼叫的基础上切换和更改压缩算法或级别,但考虑到打开压缩后的性能优势,我是一个快乐的人。
测试#1和测试#2似乎表现得如预期。
测试#3:
测试#4: