Add compression to Tonic
https://github.com/BurntSushi/rust-snappy
We use gzip (default) in our Go GRPC services. Would like to normalize this across all services. There are other compression options such as snappy. I noticed burntsushi has a nice snappy implementation in rust.
Add some level of compression for larger payloads.
Id be more then happy to help with the implementation of this. Been wanting to get my hands dirty on some more open source projects. I don't know if any ideas have been floated or not about this, or if it belongs here or in tower.
@ericmcbride yeah, compression is something we should 100% add. I am curious what type of compression you are using with grpc-go? Is it at the connection level or is it per message?
I'd love to support this though I am not 100% sure on how to do this yet, so happy to chat about it! Feel free to ping me on discord as well and we can chat if this is something you are interested in contributing :)
Yeah we just use gzip and enable it as an option. I haven't really went deep into the rabbit hole. At first glance
// callInfo contains all related configuration and information about an RPC.
type callInfo struct {
compressorType string
failFast bool
stream ClientStream
maxReceiveMessageSize *int
maxSendMessageSize *int
creds credentials.PerRPCCredentials
contentSubtype string
codec baseCodec
maxRetryRPCBufferSize int
}
// CallOption configures a Call before it starts or extracts information from
// a Call after it completes.
type CallOption interface {
// before is called before the call is sent to any server. If before
// returns a non-nil error, the RPC fails with that error.
before(*callInfo) error
// after is called after the call has completed. after cannot return an
// error, so any failures should be reported via output parameters.
after(*callInfo)
}
Makes me thing its per message but this is a quick assumption. Ill dive deeper into the code this weekend and look and id be more then happy to jump on!
I think if compression is in connection-level, need to check peer support compression or not, but it makes developers can focus on the real job, instead of 'how to set the framework correctly'.
And if we could choose which rpc call enable compression, which one disable, it's very good, because when we just send some little bytes, compress them doesn't reduce time, sometimes even make data bigger. However, if we need to send a lot of data, like sending a photo, compress it may reduce a lot of transport time
I assume we will want to change our generated clients to be more like a builder api that can allow users to set compression per service.
In my tonic-based client-server app there is a need in compression of grpc stream data.
Given that gRPC specs explicitly tell that compression is message-level, I think that the better option is to provide a stream compression layer on top of tonic api, not extend the api itself.
In case anyone needs to (de)compress streams of prost! messages (which tonic streams are), I created a crate just for that purpose.
Here's a link to the gRPC c++ compression documentation
They outline test cases that exemplify the behaviour of compression
Test cases
- When a compression level is not specified for either the channel or the message, the default channel level none is considered: data MUST NOT be compressed.
- When per-RPC compression configuration isn't present for a message, the channel compression configuration MUST be used.
- When a compression method (including no compression) is specified for an outgoing message, the message MUST be compressed accordingly.
- A message compressed by a client in a way not supported by its server MUST fail with status UNIMPLEMENTED, its associated description indicating the unsupported condition as well as the supported ones. The returned grpc-accept-encoding header MUST NOT contain the compression method (encoding) used.
- A message compressed by a server in a way not supported by its client MUST fail with status INTERNAL, its associated description indicating the unsupported condition as well as the supported ones. The returned grpc-accept-encoding header MUST NOT contain the compression method (encoding) used.
- An ill-constructed message with its Compressed-Flag bit set but lacking a grpc-encoding entry different from identity in its metadata MUST fail with INTERNAL status, its associated description indicating the invalid Compressed-Flag condition.