gRPC 与 Protocol Buffers 入门:高性能微服务通信

David Ng | 2026-08-27T20:55:22 | Java, DevOps

从 protobuf 定义到 gRPC 服务实现,讲解四种通信模式和在微服务架构中的实际应用。

# gRPC 与 Protocol Buffers 入门 ## 什么是 gRPC? gRPC 是 Google 开源的高性能 RPC 框架,使用 Protocol Buffers(protobuf)作为接口定义语言和序列化格式,支持多种编程语言。 ## 对比 REST | 维度 | gRPC | REST | |------|------|------| | 协议 | HTTP/2 | HTTP/1.1 | | 序列化 | Protobuf(二进制) | JSON(文本) | | 性能 | 极高 | 中等 | | 流式传输 | 原生支持 | 需要 WebSocket | | 浏览器支持 | 需 gRPC-Web | 原生 | ## 定义 Proto 文件 ```protobuf // user.proto syntax = "proto3"; package user; option java_package = "com.example.grpc.user"; option go_package = "myapp/proto/user"; service UserService { // 一元 RPC rpc GetUser(GetUserRequest) returns (UserResponse); rpc CreateUser(CreateUserRequest) returns (UserResponse); rpc ListUsers(ListUsersRequest) returns (ListUsersResponse); // 服务端流式 rpc WatchUsers(WatchRequest) returns (stream UserEvent); // 客户端流式 rpc BatchCreate(stream CreateUserRequest) returns (BatchResult); // 双向流式 rpc Chat(stream ChatMessage) returns (stream ChatMessage); } message GetUserRequest { int64 id = 1; } message CreateUserRequest { string name = 1; string email = 2; repeated string roles = 3; } message UserResponse { int64 id = 1; string name = 2; string email = 3; repeated string roles = 4; int64 created_at = 5; } message ListUsersRequest { int32 page = 1; int32 page_size = 2; } message ListUsersResponse { repeated UserResponse users = 1; int32 total = 2; } ``` ## Go 服务端实现 ```go type userServer struct { pb.UnimplementedUserServiceServer users map[int64]*pb.UserResponse mu sync.RWMutex } func (s *userServer) GetUser(ctx context.Context, req *pb.GetUserRequest) (*pb.UserResponse, error) { s.mu.RLock() defer s.mu.RUnlock() user, ok := s.users[req.Id] if !ok { return nil, status.Errorf(codes.NotFound, "user %d not found", req.Id) } return user, nil } func (s *userServer) CreateUser(ctx context.Context, req *pb.CreateUserRequest) (*pb.UserResponse, error) { s.mu.Lock() defer s.mu.Unlock() id := int64(len(s.users) + 1) user := &pb.UserResponse{ Id: id, Name: req.Name, Email: req.Email, Roles: req.Roles, CreatedAt: time.Now().Unix(), } s.users[id] = user return user, nil } func main() { lis, _ := net.Listen("tcp", ":50051") s := grpc.NewServer() pb.RegisterUserServiceServer(s, &userServer{ users: make(map[int64]*pb.UserResponse), }) log.Println("gRPC server listening on :50051") s.Serve(lis) } ``` ## Java 客户端调用 ```java ManagedChannel channel = ManagedChannelBuilder .forAddress("localhost", 50051) .usePlaintext() .build(); UserServiceGrpc.UserServiceBlockingStub stub = UserServiceGrpc.newBlockingStub(channel); // 调用 RPC UserResponse user = stub.getUser( GetUserRequest.newBuilder().setId(1).build() ); System.out.println("用户名: " + user.getName()); channel.shutdown(); ``` ## 错误处理 ```go // gRPC 标准错误码 codes.OK // 成功 codes.NotFound // 资源不存在 codes.InvalidArgument // 参数错误 codes.Unauthenticated // 未认证 codes.PermissionDenied // 无权限 codes.Internal // 服务器内部错误 ``` ## 最佳实践 1. Proto 文件统一管理在独立仓库,通过 CI 自动生成各语言代码 2. 使用拦截器(Interceptor)统一处理认证、日志、链路追踪 3. 微服务内部通信用 gRPC,对外暴露 REST(通过 gRPC-Gateway 转换) 4. 设置合理的超时和重试策略

← Back to Blog