Avoiding deserialization

902 views
Skip to first unread message

ccl...@dieselpoint.com

unread,
Dec 21, 2016, 5:30:33 PM12/21/16
to grpc.io
In our app we need to accept a (large) Grpc message, extract a field, and then based on the value of that field forward the message on to another server.

I'm trying to avoid the overhead of completely deserializing the message before passing it on.

One way to do this in a microservices environment would be to send the field as a separate query or header parameter, but Grpc doesn't support them.

Another way would be to extract just the field of interest from the payload, but Protobuf doesn't support partial or selective deserialization.

How else can I do this?



Makarand Dharmapurikar

unread,
Dec 22, 2016, 3:58:38 PM12/22/16
to ccl...@dieselpoint.com, grpc.io
"One way to do this in a microservices environment would be to send the field as a separate query or header parameter, but Grpc doesn't support them." - gRPC does support custom headers.

--
You received this message because you are subscribed to the Google Groups "grpc.io" group.
To unsubscribe from this group and stop receiving emails from it, send an email to grpc-io+unsubscribe@googlegroups.com.
To post to this group, send email to grp...@googlegroups.com.
Visit this group at https://groups.google.com/group/grpc-io.
To view this discussion on the web visit https://groups.google.com/d/msgid/grpc-io/4181d2cf-2bda-4f9d-8b08-abb177855323%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Nathaniel Manista

unread,
Dec 22, 2016, 4:37:56 PM12/22/16
to ccl...@dieselpoint.com, grpc.io
On Wed, Dec 21, 2016 at 2:30 PM, <ccl...@dieselpoint.com> wrote:
In what programming language(s) are you working with gRPC?
-Nathaniel

Chris Cleveland

unread,
Dec 22, 2016, 5:50:39 PM12/22/16
to grpc.io
I'm using Java. A bit of searching suggests that I have to implement client and server interceptors to send and receive custom headers. Is that correct?

Also, can I avoid deserialization on the server side and simply forward the request based on the value of a custom header?
--
Chris Cleveland
Dieselpoint, Inc.

Kun Zhang

unread,
Dec 27, 2016, 2:38:26 PM12/27/16
to grpc.io
Yes you need to implement interceptors to get access custom headers.

The generated server interface always uses the default Protobuf Marshaller which will always deserialize.
If you want to avoid deserialization, you can't use the generated server interface.

Here is a recipe that may work for you:

1. A custom Marshaller<InputStream> that just passes the InputStream through.
2. Custom MethodDescriptor<InputStream, InputStream> that use the Marshaller above. Let's say they are MD1, MD2, ...
3. Define a Context.Key<Boolean>, say PASS_THROUGH. In your server interceptor, if you find your custom header says pass-through, set this context value in the context before calling next.newCall(). This is necessary because the service impl only has access to the Context, but not headers.
4. Write the service impl in the following pattern:

class FooImpl implements BindableService {
  @Override
  public ServerServiceDefinition bindService() {
    return ServerServiceDefinition.builder("FooService")
        .addMethod(MD1,
            ServerCalls.asyncUnaryCall(      // suppose MD1 is unary
                new ServerCalls.UnaryMethod<InputStream, InputStream>() {
                    @Override
                    public void invoke(
                        InputStream request, StreamObserver<InputStream> responseObserver) {
                          if (PASS_THROUGH.get() != null) {
                            // send request out
                            // You won't be able to use the generated stub here.
                            // Instead, you will need call newCall() on an out-going Channel with MD1.
                          } else {
                            // parse request and handle it locally
                          }
                    }
                }))
        .addMethod(MD2,
          ....
        )
        ...
       .build();
  }
}

5. Register this server impl (add the interceptor too) to the gRPC Server builder.

William Thurston

unread,
Dec 27, 2016, 4:04:51 PM12/27/16
to Kun Zhang, grpc.io
Also, if you're okay doing the call to a different server in the interceptor itself, you might take a look here https://github.com/grpc/grpc-java/blob/master/core/src/main/java/io/grpc/ServerInterceptors.java#L154 .  I contributed this and it's used to have an interceptor hook in before the messages are marshalled into real types.  We use it to inspect headers and return raw bytes from caches both in process and out of process(memcached) before parsing the messages.

-Will

--
You received this message because you are subscribed to the Google Groups "grpc.io" group.
To unsubscribe from this group and stop receiving emails from it, send an email to grpc-io+unsubscribe@googlegroups.com.
To post to this group, send email to grp...@googlegroups.com.
Visit this group at https://groups.google.com/group/grpc-io.

daniel...@datadoghq.com

unread,
Jul 24, 2018, 11:40:15 AM7/24/18
to grpc.io
Reviving an old thread. Is there a way to do something similar in Golang? Preferably without needing to run a separate server.

Thanks,
Daniel
To unsubscribe from this group and stop receiving emails from it, send an email to grpc-io+u...@googlegroups.com.

To post to this group, send email to grp...@googlegroups.com.
Visit this group at https://groups.google.com/group/grpc-io.

Jorg Heymans

unread,
Jul 24, 2018, 2:46:49 PM7/24/18
to grpc.io
Depending how much control you have over the message definitions, another approach could be to have an 'envelope message' containing the fields you need to calculate the route from together with the payload as Any. That way you can deserialize the envelope message very cheaply (the Any will not be deserialized), then decide on the payload route.

message Envelope {
   string myroutingfield = 1;
   Any largePayload = 2;
}

Jorg
Reply all
Reply to author
Forward
0 new messages