Ever wondered: "Is gRPC really faster than REST?" Let's not just believe the hype. Let's measure it ourselves!
In this blog, we'll build small REST and gRPC services in Python, benchmark them, and compare their real-world performance.
REST vs gRPC: Quick Intro
Feature | REST (Flask) | gRPC (Protobuf) |
---|---|---|
Protocol | HTTP/1.1 | HTTP/2 |
Data Format | JSON (text) | Protobuf (binary) |
Human-readable? | Yes | No |
Speed | Slower | Faster |
Streaming support | Hard | Native |
Setup: Build Two Simple Services
1. REST API Server (Flask)
# rest_server.py
from flask import Flask, request, jsonify
app = Flask(__name__)
@app.route('/hello', methods=['POST'])
def say_hello():
data = request.json
name = data.get('name', 'World')
return jsonify({'message': f'Hello, {name}!'}), 200
if __name__ == '__main__':
app.run(port=5000)
2. gRPC Server (Python)
First, define your service using Protocol Buffers.
hello.proto
syntax = "proto3";
service HelloService {
rpc SayHello (HelloRequest) returns (HelloResponse);
}
message HelloRequest {
string name = 1;
}
message HelloResponse {
string message = 1;
}
Generate Python files:
python -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. hello.proto
gRPC server:
# grpc_server.py
import grpc
from concurrent import futures
import hello_pb2
import hello_pb2_grpc
class HelloService(hello_pb2_grpc.HelloServiceServicer):
def SayHello(self, request, context):
return hello_pb2.HelloResponse(message=f"Hello, {request.name}!")
server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
hello_pb2_grpc.add_HelloServiceServicer_to_server(HelloService(), server)
server.add_insecure_port('[::]:50051')
server.start()
server.wait_for_termination()
Benchmark: How to Measure?
We will send 1000 requests to each server and measure total time taken.
REST Benchmark Client
import requests
import time
def benchmark_rest():
url = "http://localhost:5000/hello"
data = {"name": "Ninad"}
start = time.time()
for _ in range(1000):
response = requests.post(url, json=data)
_ = response.json()
end = time.time()
print(f"REST Total Time: {end - start:.2f} seconds")
if __name__ == "__main__":
benchmark_rest()
gRPC Benchmark Client
import grpc
import hello_pb2
import hello_pb2_grpc
import time
def benchmark_grpc():
channel = grpc.insecure_channel('localhost:50051')
stub = hello_pb2_grpc.HelloServiceStub(channel)
start = time.time()
for _ in range(1000):
_ = stub.SayHello(hello_pb2.HelloRequest(name="Ninad"))
end = time.time()
print(f"gRPC Total Time: {end - start:.2f} seconds")
if __name__ == "__main__":
benchmark_grpc()
Results: What I Observed
Metric | REST | gRPC |
---|---|---|
Total Time (1000 req) | ~15-20 seconds | ~3-5 seconds |
Avg Latency/request | ~15-20 ms | ~3-5 ms |
Payload Size | Larger (text) | Smaller (binary) |
gRPC was about 4-5x faster than REST in this small test!
Why is gRPC Faster?
- Uses HTTP/2: multiplexing multiple streams.
- Binary Protobufs: smaller, faster to serialize/deserialize.
- Persistent connection: no 3-way TCP handshake every call.
Conclusion
- If you're building frontend APIs (browsers/mobile apps) -> REST is still great.
- If you're building internal microservices at scale -> gRPC shines!
Bonus: Advanced Benchmarking Tools
Final Thought:
Real engineers don't guess performance — they measure it!
Happy benchmarking! 💪
Would love to hear your thoughts — have you tried gRPC before? How did it go for you? Feel free to share in the comments! 🚀