title: "gRPC vs REST:微服务通信协议的正确选择"
date: "2026-07-10"
tags: ["gRPC", "REST", "微服务", "协议"]
gRPC vs REST:微服务通信协议的正确选择
微服务之间的通信方式直接影响系统的性能、可维护性和开发效率。gRPC 和 REST 是两种主流选择,各有适用场景。
REST:简单直观
REST 基于 HTTP,使用 JSON 作为数据格式,是最广泛使用的 API 风格。
# REST 服务端 (Flask)
from flask import Flask, jsonify, request
app = Flask(__name__)
@app.route('/api/users/<int:user_id>', methods=['GET'])
def get_user(user_id: int):
user = db.query("SELECT * FROM users WHERE id = %s", user_id)
return jsonify({
"id": user.id,
"name": user.name,
"email": user.email,
"created_at": user.created_at.isoformat()
})
@app.route('/api/users', methods=['POST'])
def create_user():
data = request.json
user_id = db.execute(
"INSERT INTO users (name, email) VALUES (%s, %s) RETURNING id",
data['name'], data['email']
)
return jsonify({"id": user_id}), 201# REST 客户端
import requests
response = requests.get('http://api.example.com/api/users/123')
user = response.json()
print(user['name'])gRPC:高性能
gRPC 使用 Protocol Buffers 定义接口,基于 HTTP/2 传输,性能远超 REST。
// user.proto
syntax = "proto3";
service UserService {
rpc GetUser (GetUserRequest) returns (User);
rpc CreateUser (CreateUserRequest) returns (User);
rpc ListUsers (ListUsersRequest) returns (stream User);
}
message GetUserRequest {
int64 user_id = 1;
}
message CreateUserRequest {
string name = 1;
string email = 2;
}
message User {
int64 id = 1;
string name = 2;
string email = 3;
string created_at = 4;
}# gRPC 服务端
import grpc
from concurrent import futures
import user_pb2
import user_pb2_grpc
class UserServiceServicer(user_pb2_grpc.UserServiceServicer):
def GetUser(self, request, context):
user = db.query("SELECT * FROM users WHERE id = %s", request.user_id)
return user_pb2.User(
id=user.id,
name=user.name,
email=user.email,
created_at=user.created_at.isoformat()
)
def CreateUser(self, request, context):
user_id = db.execute(
"INSERT INTO users (name, email) VALUES (%s, %s) RETURNING id",
request.name, request.email
)
return user_pb2.User(id=user_id, name=request.name, email=request.email)
def ListUsers(self, request, context):
users = db.query("SELECT * FROM users LIMIT 100")
for user in users:
yield user_pb2.User(
id=user.id,
name=user.name,
email=user.email
)
server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
user_pb2_grpc.add_UserServiceServicer_to_server(UserServiceServicer(), server)
server.add_insecure_port('[::]:50051')
server.start()# gRPC 客户端
import grpc
import user_pb2
import user_pb2_grpc
channel = grpc.insecure_channel('localhost:50051')
stub = user_pb2_grpc.UserServiceStub(channel)
# 同步调用
user = stub.GetUser(user_pb2.GetUserRequest(user_id=123))
print(user.name)
# 流式调用
for user in stub.ListUsers(user_pb2.ListUsersRequest()):
print(user.name)性能对比
实测数据(1000 次请求,相同数据量):
| 指标 | REST (JSON) | gRPC (Protobuf) | 差距 |
|------|-------------|-----------------|------|
| 平均延迟 | 12ms | 3ms | 4x |
| P99 延迟 | 45ms | 8ms | 5.6x |
| 请求大小 | 1.2KB | 180B | 6.7x |
| 响应大小 | 2.8KB | 420B | 6.7x |
| 吞吐量 | 850 req/s | 3200 req/s | 3.8x |
四种通信模式
1. 简单 RPC(一元)
rpc GetUser (GetUserRequest) returns (User);客户端发送一个请求,服务端返回一个响应。等同于 REST 的 GET/POST。
2. 服务端流式
rpc ListUsers (ListUsersRequest) returns (stream User);客户端发送一个请求,服务端返回一个数据流。适合大数据量查询。
3. 客户端流式
rpc UploadLogs (stream LogEntry) returns (UploadResult);客户端发送一个数据流,服务端返回一个响应。适合批量上传。
4. 双向流式
rpc Chat (stream Message) returns (stream Message);客户端和服务端都可以随时发送消息。适合实时通信。
选型决策
选择 REST 的场景
- 对外公开的 API(浏览器、移动端、第三方)
- 需要人类可读的请求/响应(调试友好)
- 团队对 REST 更熟悉
- 需要利用 HTTP 缓存机制
选择 gRPC 的场景
- 内部微服务通信
- 对延迟和带宽敏感
- 需要流式传输
- 多语言环境(Protobuf 自动生成各语言代码)
混合使用
外部客户端 → REST API Gateway → gRPC 内部服务# API Gateway 示例
from fastapi import FastAPI
import grpc
app = FastAPI()
grpc_channel = grpc.insecure_channel('user-service:50051')
user_stub = user_pb2_grpc.UserServiceStub(grpc_channel)
@app.get('/api/users/{user_id}')
async def get_user(user_id: int):
user = user_stub.GetUser(user_pb2.GetUserRequest(user_id=user_id))
return {
"id": user.id,
"name": user.name,
"email": user.email
}常见陷阱
gRPC 的浏览器支持
gRPC 不能直接在浏览器中使用,需要 gRPC-Web 代理:
# Envoy 配置
static_resources:
listeners:
- name: listener_0
address:
socket_address: { address: 0.0.0.0, port_value: 8080 }
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
route_config:
virtual_hosts:
- name: local_service
routes:
- match: { prefix: "/" }
route: { cluster: user_service }
http_filters:
- name: envoy.filters.http.grpc_web
- name: envoy.filters.http.cors
- name: envoy.filters.http.routerProtobuf 版本兼容
message User {
int64 id = 1;
string name = 2;
string email = 3;
// 新增字段用新编号,不要复用已删除的编号
string phone = 4;
// reserved 5, 6; // 标记已删除的字段
}gRPC 和 REST 不是非此即彼的关系。理解各自的优势和局限,根据场景选择合适的协议,才是正确的做法。
读者评论 4