gRPC协议架构与HTTP/2传输机制
gRPC是Google开源的高性能RPC框架,基于HTTP/2和Protocol Buffers实现,支持多种语言跨平台调用。相比REST/JSON方案,gRPC在序列化效率、连接复用和流式传输方面有显著优势,特别适合微服务间的高频内部调用。
gRPC的协议栈自底向上:HTTP/2传输层、gRPC帧层、Protocol Buffers编码。HTTP/2提供多路复用、头部压缩、服务器推送等能力,单个TCP连接并行承载多个请求,消除HTTP/1.1的队头阻塞。Protocol Buffers二进制编码比JSON体积小3-10倍,序列化与反序列化速度快20-100倍。
gRPC定义四种通信模式:
– Unary RPC:单次请求-响应,类似HTTP
– Server Streaming:客户端单次请求,服务端流式返回
– Client Streaming:客户端流式发送,服务端单次响应
– Bidirectional Streaming:双向流式通信
Protocol Buffers接口定义与服务生成
用.proto文件定义服务接口和消息类型,protoc编译器生成Go代码:
// api/order/order.proto
syntax = "proto3";
package order;
option go_package = "github.com/myapp/api/order";
service OrderService {
rpc CreateOrder(CreateOrderRequest) returns (CreateOrderResponse);
rpc GetOrder(GetOrderRequest) returns (GetOrderResponse);
rpc ListOrders(ListOrdersRequest) returns (stream Order);
rpc StreamUpdates(StreamUpdatesRequest) returns (stream OrderUpdate);
}
message CreateOrderRequest {
string user_id = 1;
repeated OrderItem items = 2;
string address = 3;
}
message OrderItem {
string product_id = 1;
int32 quantity = 2;
double price = 3;
}
message CreateOrderResponse {
string order_id = 1;
string status = 2;
}
message GetOrderRequest {
string order_id = 1;
}
message GetOrderResponse {
string order_id = 1;
string user_id = 2;
repeated OrderItem items = 3;
string status = 4;
int64 created_at = 5;
}
message ListOrdersRequest {
string user_id = 1;
int32 page_size = 2;
string page_token = 3;
}
message Order {
string order_id = 1;
string status = 2;
int64 created_at = 3;
}
message StreamUpdatesRequest {
string order_id = 1;
}
message OrderUpdate {
string order_id = 1;
string status = 2;
string message = 3;
int64 timestamp = 4;
}
生成Go代码:
protoc --go_out=. --go-grpc_out=. api/order/order.proto
Go语言gRPC服务端实现
服务端实现接口逻辑并启动gRPC Server:
package main
import (
"context"
"log"
"net"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
pb "github.com/myapp/api/order"
)
type OrderServer struct {
pb.UnimplementedOrderServiceServer
store *OrderStore
}
// Unary RPC: 创建订单
func (s *OrderServer) CreateOrder(ctx context.Context, req *pb.CreateOrderRequest) (*pb.CreateOrderResponse, error) {
if req.UserId == "" {
return nil, status.Error(codes.InvalidArgument, "user_id is required")
}
order, err := s.store.Create(ctx, req)
if err != nil {
return nil, status.Errorf(codes.Internal, "create order failed: %v", err)
}
return &pb.CreateOrderResponse{
OrderId: order.ID,
Status: order.Status,
}, nil
}
// Server Streaming: 订单列表流式返回
func (s *OrderServer) ListOrders(req *pb.ListOrdersRequest, stream pb.OrderService_ListOrdersServer) error {
orders, err := s.store.ListByUser(stream.Context(), req.UserId, req.PageSize)
if err != nil {
return status.Errorf(codes.Internal, "query failed: %v", err)
}
for _, order := range orders {
if err := stream.Send(order); err != nil {
return err
}
}
return nil
}
// Bidirectional Streaming: 订单状态实时推送
func (s *OrderServer) StreamUpdates(stream pb.OrderService_StreamUpdatesServer) error {
for {
req, err := stream.Recv()
if err != nil {
return err
}
updateCh := s.store.Subscribe(req.OrderId)
for update := range updateCh {
if err := stream.Send(update); err != nil {
return err
}
}
}
}
func main() {
lis, err := net.Listen("tcp", ":50051")
if err != nil {
log.Fatalf("listen failed: %v", err)
}
s := grpc.NewServer(
grpc.MaxRecvMsgSize(4*1024*1024),
grpc.MaxSendMsgSize(4*1024*1024),
)
pb.RegisterOrderServiceServer(s, &OrderServer{})
log.Printf("gRPC server listening on %s", lis.Addr())
if err := s.Serve(lis); err != nil {
log.Fatalf("serve failed: %v", err)
}
}
拦截器中间件与错误处理规范
gRPC拦截器(Interceptor)类似HTTP中间件,在RPC调用前后插入通用逻辑。Go语言分UnaryInterceptor和StreamInterceptor:
func LoggingInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
start := time.Now()
resp, err := handler(ctx, req)
duration := time.Since(start)
code := codes.OK
if err != nil {
code = status.Convert(err).Code()
}
log.Printf("method=%s duration=%v code=%s", info.FullMethod, duration, code)
return resp, err
}
func RecoveryInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {
defer func() {
if r := recover(); r != nil {
log.Printf("panic recovered: %v", r)
err = status.Errorf(codes.Internal, "internal error")
}
}()
return handler(ctx, req)
}
// 注册拦截器
s := grpc.NewServer(
grpc.ChainUnaryInterceptor(RecoveryInterceptor, LoggingInterceptor),
)
错误处理规范:业务错误用status.Error返回标准gRPC状态码,避免直接返回Go error。常用状态码映射:InvalidArgument(400)、NotFound(404)、AlreadyExists(409)、PermissionDenied(403)、Internal(500)、Unavailable(503)、Unauthenticated(401)。
gRPC网关与REST兼容方案
gRPC适合内部服务间调用,但浏览器和移动端原生不支持。grpc-gateway通过protoc插件自动生成HTTP/JSON反向代理,同时提供gRPC和REST接口:
// 在.proto文件添加HTTP注解
import "google/api/annotations.proto";
service OrderService {
rpc CreateOrder(CreateOrderRequest) returns (CreateOrderResponse) {
option (google.api.http) = {
post: "/v1/orders"
body: "*"
};
}
rpc GetOrder(GetOrderRequest) returns (GetOrderResponse) {
option (google.api.http) = {
get: "/v1/orders/{order_id}"
};
}
}
生成网关代码后运行,网关监听8080端口,将HTTP请求转为gRPC调用转发到50051端口。外部客户端用REST/JSON访问,内部服务用gRPC通信,兼顾开发效率与运行性能。
gRPC的生产部署还需关注:健康检查(grpc.health.v1)、负载均衡(client-side LB或代理层LB)、TLS双向认证、Protobuf文件版本管理。服务发现与gRPC结合推荐使用etcd或Consul,通过Resolver接口实现自定义命名解析。
原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/grpc-gao-xing-neng-rpc-kuang-jia-xie-yi-she-ji-yu-go-fu-wu/