Putting gRPC multi-language support to the test
Mete Atamel
Cloud Developer Advocate
gRPC is an RPC framework developed and open-sourced by Google. There are many benefits to gRPC, such as efficient connectivity with HTTP/2, efficient data serialization with Protobuf, bi-directional streaming and more, but one of the biggest benefits is often overlooked: multi-language support.
Out of the box, gRPC supports multiple programming languages : C#, Java, Go, Node.js, Python, PHP, Ruby and more. In the new microservices world, the multi-language support provides the flexibility you need to implement services in whatever language and framework you like and let gRPC handle the low-level connectivity and data transfer between microservices in an efficient and consistent way.
This all sounds nice in theory but does it work in reality? As a long-time Java and C# developer, I wanted to see how well gRPC delivered on its multi-language promise. The plan was to run a couple of Java gRPC samples to see how gRPC worked in Java. Then, I wanted to see how easy it would be to port those samples into C#. Finally, I wanted to mix and match Java and C# clients/servers and see how well they worked together.
gRPC Java support
First, I wanted to figure out how well gRPC supports individual languages. Getting started with Java is pretty straightforward —just add the Maven or Gradle dependencies and plugins. Ray Tsang, a colleague and Java expert, has written and published some gRPC samples in Java in his GitHub repository, so I started exploring those.
I tried a simple gRPC client and a simple gRPC server written in Java. These are "Hello World"-type samples, where a client sends a request to the server and the server echoes it back. The samples are Maven projects, so I used my favorite Java editor (Eclipse) to import the projects into a new workspace. First, I started the server:
Then, I started the client. As expected, the client sent a request and received a response from the server:
Ray also has a more interesting sample that uses a bi-directional streaming feature. He built a chat server and a chat client based on JavaFX to talk to that server. I was able to get the two chat clients talking to each other through the chat server with little effort.
Two JavaFX clients talking to each other via Java server
gRPC C# support
So far so good. Next, I wanted to see how easy it was to rewrite the same samples in C#. With a little help from the gRPC documentation samples, I was able to create a GreeterClient and a GreeterServer for the Hello World sample. The code is very similar to Java but it looks a little nicer. (Ok, I'm biased in favor of C# :-) )One minor difference: with Java, you can use Maven or Gradle plugins to generate gRPC stub classes automatically. In the case of C#, you need to bring in the gRPC Tools NuGet package and generate the stub classes with it. Take a look at generate_protos.bat to see how I did that. The good news is that you can rely on the same service definition file to generate Java and C# stub clients, which makes it easy to write client and server apps in different languages.
I also implemented the bi-directional streaming chat example with ChatServer and ChatWindowsClient but instead of JavaFX, I used Windows Forms. As before, the code is quite similar to the Java version but gRPC takes advantage of the language to make sure developers are not missing out on language specific features.
For example, ChatServerImpl.java
creates and returns a StreamObserver
as a handler for client messages. This works but felt a little unintuitive. On the other hand, ChatServerImpl.cs
uses the async/await pattern of C# and writes to the response stream asynchronously, which yields a cleaner implementation.
gRPC multi-language test
The real test for multi-language support is how well Java and C# implementations work together. To test that, I started the Java chat server. Then, I started a Java chat client and a C# chat client both talking to the same Java chat server. It was nice to see the two clients talking to each other through the chat server with no special configuration or effort on my part.
Conclusion
Designing a framework is hard. Designing a framework that works across different languages while maintaining the unique benefits of each language is even harder. Whether I worked with gRPC in Java or C#, it never felt alien. It's obvious that a lot of thought and effort went into making sure that gRPC was idiomatic for each language. That's great to see from a framework trying to cover a wide range of languages. If you want to run the samples yourself, take a look at Ray's Java gRPC samples and my C# gRPC samples. You can also watch a recording of Ray’s talk on Java gRPC.
Happy gRPCing! :-)