使用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次。我通过
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:Algorithm' gzip&# 39;启用但决定不压缩。输入大小: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
的集合。我将其设置如下:
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":& #34;不允许重复的元数据","文件":" C:\ jenkins \ workspace \ gRPC_build_artifacts \ platform \ windows \ workspace_csharp_ext_windows_x64 \ src \ core \ lib \ transport \ metadata_batch.cc&# 34;," file_line":111,"键":" GRPC内部编码请求""值":&#34 ; gzip的"}
这意味着我无法在每个呼叫的基础上切换和更改压缩算法或级别,但考虑到打开压缩后的性能优势,我是一个快乐的人。
答案 0 :(得分:1)
测试#1和测试#2似乎表现得如预期。
测试#3:
测试#4: