Grpc Development

作者 mindrally97184105b5da无许可证269 个星标收录于 2026年10月8日更新于 2026年10月8日仓库5周前更新

Best practices for building high-performance services with gRPC and Protocol Buffers. Use when designing RPC services, defining protobuf schemas, implementing streaming APIs, setting up gRPC interceptors, or building cross-language service communication.

AI 生成的概览

使用 Protocol Buffers 设计、实现、测试和运维 gRPC 服务的指导。

功能
提供构建 gRPC 服务和 API 的最佳实践说明,涵盖 proto 模式设计、命名与风格约定、一元与流式 RPC 模式、拦截器、错误处理、安全、测试和可观测性。其中包含示例 proto 定义和 Go 服务端代码,演示服务契约、流式处理函数和日志拦截器。还给出了 Go、Python 和 Node.js/TypeScript 的语言特定建议。
适用场景
适用于设计 RPC 服务、定义 protobuf 模式、实现流式 API、配置 gRPC 拦截器或搭建跨语言服务通信的场景。也适用于为现有 gRPC 服务添加 TLS、身份验证、重试、链路追踪或指标。
运行要求
不附带脚本,仅为说明性内容。按其操作需要 protobuf 工具链(如带语言插件的 protoc)以及目标语言的 gRPC 运行时库(例如 google.golang.org/grpc、grpcio/grpcio-tools 或 @grpc/grpc-js)。

gRPC Development

This skill covers best practices for building gRPC-based services and APIs using Protocol Buffers, including service design, streaming patterns, interceptors, security, and observability.

Workflow for Building a gRPC Service

  1. Define the service contract — Write .proto files with service definitions, RPC methods, and message types following the style and naming conventions below.
  2. Generate language stubs — Run protoc with the appropriate language plugin (e.g., protoc-gen-go-grpc, grpcio-tools) to produce server and client code.
  3. Implement the server — Create handler functions for each RPC method, register them with a gRPC server, and configure TLS, interceptors, and health checks.
  4. Implement the client — Create a channel to the server, instantiate the generated client stub, and call RPC methods with proper deadlines and error handling.
  5. Add interceptors — Wire in server and client interceptors for logging, authentication, metrics, and tracing.
  6. Write tests — Unit-test handlers with mocked dependencies; integration-test with a real gRPC connection.
  7. Deploy and observe — Enable distributed tracing (OpenTelemetry), structured logging, and metrics dashboards before going to production.

Core Principles

  • gRPC uses Protocol Buffers as both its Interface Definition Language (IDL) and message interchange format
  • Design services around the idea of defining methods that can be called remotely with their parameters and return types
  • Prioritize type safety, performance, and backward compatibility
  • Leave NO todos, placeholders, or missing pieces in the implementation

Protocol Buffer Best Practices

File Organization (1-1-1 Pattern)

  • Structure definitions with one top-level entity (message, enum, or extension) per .proto file
  • Correspond each .proto file to a single build rule
  • This promotes small, modular proto definitions
  • Benefits include simplified refactoring, improved build times, and smaller binary sizes

Message Design

  • Use structured messages for extensibility - Protocol Buffers supports adding fields without breaking existing clients
  • Be careful to use structs in places you may want to add fields later
  • Don't re-use messages across RPCs - APIs may change over time, avoid coupling separate RPC calls tightly together
  • Fields should always be independent of each other - don't have one field influence the semantic meaning of another

Field Guidelines

  • Use descriptive field names with underscore_separated_names
  • Reserve field numbers for deleted fields to prevent future conflicts
  • Use optional for fields that may not always be present
  • Consider using oneof when users need to choose between mutually exclusive options

Enum Best Practices

  • Ensure the first value is always 0
  • Use an "UNSPECIFIED" default value (e.g., STATUS_UNSPECIFIED = 0)
  • Use prefixes to avoid naming collisions (e.g., ORDER_STATUS_CREATED vs STATUS_PENDING)
  • Reserve enum values that are removed to prevent accidental reuse

Style Guidelines

  • Keep line length to 80 characters
  • Prefer double quotes for strings
  • Package names should be in lowercase
  • Use CamelCase (with initial capital) for message names
  • Use underscore_separated_names for field names
  • Use CamelCase for service and RPC method names

Service Design

RPC Patterns

  • Unary RPC: Client sends single request, server responds with single response
  • Server Streaming: Client sends request, server responds with stream of messages
  • Client Streaming: Client sends stream of messages, server responds with single response
  • Bidirectional Streaming: Both sides send streams of messages

Example: Proto Definition

proto
syntax = "proto3";
package order.v1;
option go_package = "gen/order/v1;orderv1";
// OrderService manages customer orders.service OrderService {  // Creates a new order and returns the created resource.  rpc CreateOrder(CreateOrderRequest) returns (CreateOrderResponse);  // Streams real-time status updates for an order.  rpc WatchOrder(WatchOrderRequest) returns (stream OrderStatus);}
message CreateOrderRequest {  string customer_id = 1;  repeated OrderItem items = 2;}
message CreateOrderResponse {  string order_id = 1;  OrderStatus status = 2;}
message WatchOrderRequest {  string order_id = 1;}
message OrderItem {  string product_id = 1;  int32 quantity = 2;}
message OrderStatus {  string order_id = 1;  OrderState state = 2;  string updated_at = 3;}
enum OrderState {  ORDER_STATE_UNSPECIFIED = 0;  ORDER_STATE_CREATED = 1;  ORDER_STATE_PROCESSING = 2;  ORDER_STATE_SHIPPED = 3;  ORDER_STATE_DELIVERED = 4;}

Example: Go Server Implementation

go
package main
import (	"context"	"log"	"net"	"time"
	"google.golang.org/grpc"	"google.golang.org/grpc/codes"	"google.golang.org/grpc/status"
	pb "example.com/gen/order/v1")
type orderServer struct {	pb.UnimplementedOrderServiceServer}
func (s *orderServer) CreateOrder(ctx context.Context, req *pb.CreateOrderRequest) (*pb.CreateOrderResponse, error) {	if req.GetCustomerId() == "" {		return nil, status.Error(codes.InvalidArgument, "customer_id is required")	}	orderID := "ord-" + time.Now().Format("20060102150405")	return &pb.CreateOrderResponse{		OrderId: orderID,		Status: &pb.OrderStatus{			OrderId: orderID,			State:   pb.OrderState_ORDER_STATE_CREATED,		},	}, nil}
func (s *orderServer) WatchOrder(req *pb.WatchOrderRequest, stream pb.OrderService_WatchOrderServer) error {	for i, state := range []pb.OrderState{		pb.OrderState_ORDER_STATE_PROCESSING,		pb.OrderState_ORDER_STATE_SHIPPED,		pb.OrderState_ORDER_STATE_DELIVERED,	} {		select {		case <-stream.Context().Done():			return stream.Context().Err()		case <-time.After(time.Duration(i) * time.Second):			if err := stream.Send(&pb.OrderStatus{				OrderId:   req.GetOrderId(),				State:     state,				UpdatedAt: time.Now().Format(time.RFC3339),			}); err != nil {				return err			}		}	}	return nil}
func main() {	lis, err := net.Listen("tcp", ":50051")	if err != nil {		log.Fatalf("failed to listen: %v", err)	}	srv := grpc.NewServer(		grpc.UnaryInterceptor(loggingUnaryInterceptor),	)	pb.RegisterOrderServiceServer(srv, &orderServer{})	log.Println("serving on :50051")	if err := srv.Serve(lis); err != nil {		log.Fatalf("failed to serve: %v", err)	}}
// loggingUnaryInterceptor logs each unary RPC call.func loggingUnaryInterceptor(	ctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler,) (any, error) {	start := time.Now()	resp, err := handler(ctx, req)	log.Printf("method=%s duration=%s err=%v", info.FullMethod, time.Since(start), err)	return resp, err}

API Design

  • Design clear, intuitive service interfaces
  • Group related methods in the same service
  • Use meaningful method names that describe the action
  • Document each RPC with comments describing behavior, parameters, and return values

Performance Optimization

Channel Management

  • Reuse channels when working with gRPC
  • Creating a gRPC channel is costly as it creates a new HTTP/2 connection
  • Implement connection pooling for high-throughput scenarios
  • Configure keepalive settings appropriately

Message Optimization

  • Keep messages reasonably sized - large messages impact performance
  • Consider streaming for large data transfers
  • Use compression for bandwidth-constrained environments
  • Avoid deeply nested message structures

Error Handling

Status Codes

  • Use appropriate gRPC status codes (OK, INVALID_ARGUMENT, NOT_FOUND, etc.)
  • Include meaningful error messages in status details
  • Use rich error details for complex error scenarios
  • Document expected error conditions in service definitions

Retry Logic

  • Implement retry with exponential backoff for transient failures
  • Use deadlines/timeouts for all RPC calls
  • Handle UNAVAILABLE and RESOURCE_EXHAUSTED with retries
  • Don't retry non-idempotent operations blindly

Security

Authentication

  • Use TLS for transport security in production
  • Implement per-RPC authentication using metadata/headers
  • Support multiple authentication mechanisms (JWT, OAuth2, mTLS)
  • Validate credentials on every request

Authorization

  • Implement method-level access control
  • Use interceptors for centralized authorization logic
  • Validate all input data regardless of authentication status
  • Follow the principle of least privilege

Interceptors and Middleware

Server Interceptors

  • Use interceptors for cross-cutting concerns (logging, auth, metrics)
  • Order interceptors carefully - execution order matters
  • Keep interceptors focused on single responsibilities
  • Handle errors gracefully within interceptors

Client Interceptors

  • Add metadata (headers) for tracing and authentication
  • Implement request/response logging
  • Add automatic retry logic
  • Collect client-side metrics

Testing

Unit Testing

  • Mock gRPC services for isolated testing
  • Test message serialization/deserialization
  • Verify error handling paths
  • Test interceptor logic independently

Integration Testing

  • Test with real gRPC connections where possible
  • Verify streaming behavior end-to-end
  • Test timeout and cancellation scenarios
  • Load test with realistic traffic patterns

Observability

Distributed Tracing

  • Use OpenTelemetry for distributed tracing across service boundaries
  • Propagate trace context in metadata
  • Instrument both client and server sides
  • Start spans for each RPC call

Metrics

  • Track RPC latency histograms
  • Monitor error rates by method and status code
  • Count active connections and streams
  • Alert on anomalies and SLA violations

Logging

  • Use structured logging with consistent fields
  • Log RPC method, duration, and status
  • Include trace IDs for correlation
  • Avoid logging sensitive data

Language-Specific Guidelines

Go

  • Use the official google.golang.org/grpc package
  • Implement services as interface types
  • Use context for cancellation and deadlines
  • Leverage code generation with protoc-gen-go-grpc

Python

  • Use grpcio and grpcio-tools packages
  • Implement async services with grpcio-aio for better concurrency
  • Use type hints with generated stubs
  • Handle blocking calls appropriately in async contexts

Node.js/TypeScript

  • Use @grpc/grpc-js (pure JavaScript implementation)
  • Consider using nice-grpc for better TypeScript support
  • Leverage async/await patterns
  • Use static codegen for type safety

来源与署名

来源:mindrally/skills位于grpc-development提交9718410

许可证: 无许可证

内容归原作者所有。SourceWeft 从公开仓库中收录这些内容。

举报或申请下架