Hello, World! From HTTP to gRPC revolution
Are you tired of slow and bulky HTTP requests? Meet gRPC, the high-performance alternative that will revolutionize the way your applications communicate. gRPC is a modern, high-performance, open-source framework that was created by Google. It's designed to facilitate communication between microservices and other distributed systems. In this article, we'll dive into the world of gRPC, exploring its features, differences with HTTP, purpose, companies that use it, and implement an example in NodeJs.
What is HTTP?
HTTP (Hypertext Transfer Protocol) is the most widely used protocol for communication on the World Wide Web. A request-response protocol enables clients to send requests to servers and receive responses back. HTTP is a stateless protocol, which means that each request is independent of the previous request.
What is gRPC?
gRPC is a remote procedure call (RPC) framework that uses Protocol Buffers as its interface definition language (IDL). It's designed to be fast, efficient, and scalable, making it ideal for modern distributed systems. With gRPC, developers can define their APIs using a simple, declarative language, and the framework takes care of generating the necessary code to make remote calls.
One of the key features of gRPC is its ability to support bi-directional streaming. This means that both clients and servers can send multiple messages at once without having to wait for a response from the other side.
Another benefit of using gRPC is its support for automatic code generation through Protocol Buffers (Protobuf). Protobuf provides an easy way to define your API's structure in a concise and readable format allowing you to generate client-side stubs quickly.
Differences with HTTP
Unlike HTTP, which uses text-based protocols like JSON or XML to exchange data, gRPC uses Protocol Buffers, which is a binary serialization format. This results in smaller payloads, faster processing, and improved network efficiency. Additionally, gRPC supports bi-directional streaming, allowing both the client and the server to send and receive data simultaneously.
Why was gRPC created?
gRPC was created to address the shortcomings of traditional RPC frameworks, which were often slow, cumbersome, and difficult to use. Using Protocol Buffers and binary serialization, gRPC can deliver superior performance while maintaining a simple and intuitive API.
Companies that use gRPC
Some of the biggest companies in the world use gRPC in their production systems. Google, of course, was the original creator of gRPC, and they use it extensively throughout their infrastructure. Other companies that use gRPC include Netflix, Square, Cisco, and many more.
Implementation in NodeJS
Let's take a look at an example implementation of gRPC in NodeJS. For this example, we'll create a simple chat application that allows clients to connect to a server and exchange messages.
领英推荐
First, we'll need to define our chat.proto file using Protocol Buffers. Here's what it might look like:
syntax = "proto3"
message ChatMessage {
? string user = 1;
? string message = 2;
}
service Chat {
? rpc SendMessage(ChatMessage) returns (google.protobuf.Empty) {}
? rpc ReceiveMessage(google.protobuf.Empty) returns (stream ChatMessage) {}
}
This file defines a simple message format for chat messages and two RPC methods: SendMessage and ReceiveMessage. The SendMessage method takes a ChatMessage as input and returns an empty response. The ReceiveMessage method takes no input and returns a stream of ChatMessage objects.
Next, we'll need to generate the necessary code using the gRPC-tools package. Here's what the command might look like:
grpc_tools_node_protoc --js_out=import_style=commonjs,binary:. --grpc_out=. --plugin=protoc-gen-grpc=`which grpc_tools_node_protoc_plugin` chat.proto
This command generates two files: chat_pb.js and chat_grpc_pb.js. The former contains the message format, while the latter contains the gRPC service definitions.
With our generated files in hand, we can now create our server and client implementations. Here's what the server might look like:
const grpc = require('grpc')
const { Chat, ChatMessage } = require('./chat_grpc_pb');
const messages = [];
function sendMessage(call, callback) {
const { user, message } = call.request.toObject();
messages.push({ user, message });
console.log(`[${new Date().toISOString()}] ${user}: ${message}`);
callback(null, {});
}
function receiveMessage(call) {
messages.forEach((message) => {
call.write(new ChatMessage().setUser(message.user).setMessage(message.message));
});
call.end();
}
const server = new grpc.Server();
server.addService(ChatService, { sendMessage, receiveMessage });
server.bindAsync('0.0.0.0:50051', grpc.ServerCredentials.createInsecure(), () => {
console.log(`Server running at https://0.0.0.0:50051`);
server.start();
});
This implementation creates a new gRPC server, adds our chat service, and listens for incoming connections on port 50051. The sendMessage function is called when a client sends a message, and it simply adds the message to our array of messages. The receiveMessage function is called when a client requests all the messages that have been sent so far, and it sends each message back to the client using the call.write method.
Finally, we'll need to create our client implementation. Here's what it might look like:
const grpc = require('grpc')
const { Chat, ChatMessage } = require('./chat_grpc_pb');
const client = new Chat('localhost:50051', grpc.credentials.createInsecure());
client.sendMessage(new ChatMessage().setUser('Alice').setMessage('Hello, world!'), (err, response) => {
? console.log('Sent message:', response);
});
const stream = client.receiveMessage();
stream.on('data', (message) => {
? console.log(`[${new Date().toISOString()}] ${message.getUser()}: ${message.getMessage()}`);
});
stream.on('end', () => {
? console.log('No more messages');
});
This implementation creates a new gRPC client, connects to our server, and sends a message using the sendMessage method. It then requests all the messages using the receiveMessage method and listens for incoming messages using the stream.on('data') method.
Conclusion: Which should you choose?
Choosing between gRPC and HTTP depends on your specific use case. If your application requires real-time streaming, low latency, and high throughput, gRPC is the better choice. However, if your application requires a simple request-response communication pattern and does not require real-time streaming, HTTP may be a better choice.
In general, gRPC is a better choice for modern microservices architectures that require fast and efficient communication between services. HTTP, on the other hand, is a better choice for traditional web applications and APIs that follow the principles of RESTful APIs.
So, whether you choose gRPC or HTTP, make sure you understand your application's requirements and choose the protocol that best fits your needs.
Cheers! ??