Performance Benchmarking: gRPC+Protobuf vs. HTTP+JSON
A fair benchmark with Go examples to compare Protocol Buffers over gRPC vs. JSON over HTTP/1 and HTTP/2.
While human-readable JSON over HTTP remains a popular choice for service communication due to its simplicity and familiarity, in Microservices architectures gRPC is emerging as a popular choice for communication.
It is mainly because in the case of internal services, the structured formats, such as Protocol Buffers, are a better choice than JSON for encoding data.
So we wanted to experiment with performance benchmarking of 2 types of communication in Go. It's important to note that results might vary across languages due to implementation specifics.
Comparing Apples to Apples
To isolate the performance impact of data transport and serialization protocols, we designed both the gRPC and HTTP endpoints to avoid any extraneous operations like database calls or memory-intensive computations. By minimizing the function's footprint, we ensure that the benchmark primarily reflects the performance differences between Protobuf over gRPC and JSON over HTTP.
It’s important to note that this benchmark was conducted on my local machine, providing a relative comparison of gRPC and HTTP performance. Real-world performance may vary depending on hardware, network conditions, and specific workloads.
Also this benchmark is a starting point for exploration and is only valid for this tiny example.
gRPC Service
Our gRPC service will have a single procedure CreateUser that accepts user information as input and returns some generic response. We will mimic the same format in our HTTP+JSON server as well.
grpc/users.proto
syntax = "proto3";
option go_package = "grpc/gen";
service Users {
rpc CreateUser(User) returns (CreateUserResponse) {}
}
message User {
string id = 1;
string email = 2;
string name = 3;
}
message CreateUserResponse {
string message = 1;
uint64 code = 2;
User user = 3;
}Now, let's use the protoc command to create the building blocks for our service. This includes generating the Go code for both the server (unimplemented) and the client from our users.proto file.
protoc -I./grpc --go_out=. --go-grpc_out=. users.proto


