gRPC which is short for Google RPC is an application based communication based on protocol buffers. These buffers can communicate language-anonymous (so ruby to python or C++ to Java for example).
gRPC is written in a serialization format. The base use in this tutorial with be protobuf which comes default with the gRPC in the download section below and use the .proto extension. Any serialization language can be used however.
gRPC vs REST
The advantage of gRPC over REST is several. First and foremost gRPC is much quicker than REST because encoding / decoding happens over the users local CPU. Secondly the amount of code one needs to write is less than that of most REST implementations and general type conversion is easier.
How To Install
[sudo] apt-get install build-essential autoconf libtool pkg-configgit clone -b $(curl -L https://grpc.io/release) https://github.com/grpc/grpccd grpcgit submodule update — initcd grpc/third_party/protobufsudo make install
Install Visual Studio 2015 or 2017 (Visual C++ compiler will be used).
Install Git.Install CMake.Install Active State Perl (choco install activeperl)Install Go (choco install golang)Install yasm and add it to PATH (choco install yasm)powershell git clone — recursive -b ((New-Object System.Net.WebClient).DownloadString(\”https://grpc.io/release\").Trim()) https://github.com/grpc/grpccd grpcgit submodule update — init
[sudo] xcode-select — install(optional) brew install autoconf automake libtool shtoolgit clone -b $(curl -L https://grpc.io/release) https://github.com/grpc/grpccd grpcgit submodule update — initcd grpc/third_party/protobufsudo make install
Writing a simple request
For this example we will be creating a client that sends a request of two numbers to the server, the server will multiply these two numbers and return the result to the client.
There are 4 parts to writing a protoc buffer request in C++. The Makefile, the client, the server, and the proto file.
First create these 4 files in any editor.
The make file when called with make will build both the client and server. gRPC is dependent on several buffer files that will be built with proto in the background as specified in the last 2 build commands before clean.
You should not worry much about what these extra files do, they are simply generated and used by the program however the user never has to interact with them.
Also as a note for users not familiar with more deep Makefile knowledge the $@ takes the name of the command, so in the 2nd and 3rd build commands it would be client and server respectively. The % symbol is a catch all symbol looking for any match. Finally, the $^ symbol uses every file after the build command one at a time, so mathtest.pb.o then mathtest.grpc.pb.o, and finally client.o if looking at the second client build for example.
The next file to write is the .proto file. The top line specifies what proto we are using which is proto3. The next line is additional configuration. The name of the package is mathtest in this case which will be the import name later.
The service is what creates the linked between proto and C++ which will later be invoked in our C++ code. This function name is sendRequest that accepts a MathRequest and returns a MathReply.
The messages: MathRequest and MathReply specify the types as well as content of the messages. The numbers in these requests do not specify their values only labeling for the proto file generation. We will set these messages using generated code stub in our C++ code later.
Now we come to putting all the code together.
First import some headers.
The second and third lines import gRPC headers as well as our .proto file respectively. The next commands set namespaces that will be used for the server as well as our request logic.
Next is the main.
Not much to say here.
Lets look at the Run() command.
The run command creates a port on localhost 5000 as well as instantiates a class called MathServiceImplementation which we will create in a second. This contains our gRPC logic. We then instantiate a server called builderand bind our service as well as the port to this server. Since we are not using SSL we use insecure credentials. After that we start the server with a smart pointer and wait to hear from the client.
Lets look at MathServiceImplementation finally.
This class extends our .protoc file MathTest Service and will contain our logic. From our .proto file we had a sendRequest function which we will be adding logic to here. The sendRequest returns a status such as 200, 404, 500 ect… We are overriding this function in order to add our arithmatic logic. The request from the .proto file takes 2 values, a and b which we pull out in the overrid body. Then we set the value of result in MathReply using the generate function stub set_result(value) which we set value to be a * b. There are several generated function stubs that the protoc compiler will create, this is just one of them. Finally we return Status::OK to signal the message has been creates and send by the gRPC protocol.
Putting it all together one should get a file that looks like this.
Lets start off with the headers in main again.
The only difference between the server is that we use different grpc namespaces this time.
For the Run function.
Here we connect to port localhost port 5000 which is what the server is running on as well as instantiate a class called MathTestClient. From there we declare variables and call function sendRequest (not the same function used in our proto file) passing the two numbers a and b which will be sent to the server. Finally we print the result from the server.
Looking at the MathTestClient class
Here we do not need to override the request since we are simply sending and receiving the results request, adding no new logic like the server does. In the sendRequest function we set a and b with protoc generated c++ function set_* stubs. Afterwards we create the reply and use our MathTest proto stub to invoke sendRequest (this one is generated from our proto file) to the server.
Once the status returns we check if status is successful and return the result of our reply which is the multiplication of a and b.
The result of all the steps above will be a file looking like the one below
After creating all the files one only has to run
On one terminal run
On another terminal run
On the client terminal you should see
Answer received: 5 * 10 = 50
Below is a table of total time in seconds to complete x specified requests from the same program above written in both gRPC and REST. You can determine if gRPC from this perspective is worth the speedup it provides.
gRPC seems to be 4 times faster here, but different server logic and data size amounts could vary this value.
While gRPC can be a little difficult to setup at first once the user gets going they can be simpler in the long run to write over REST requests especially for C++. while most rest services are quicker to get up and running if speed is a requirement the extra time to prepare gRPC can be worth it. Also, since more content is being driven over the web year over year being able to support http2 can be worth it for the asynchronous gains used in these requests. One more note is in this article the group did not look at asynchronous requests. So the above Benchmark table could potentially show even more gains in performance if that was explored as well.