paint-brush
gRPC-सीक्रेट: डेडलाइन, टाइमआउट और कस्टम संदर्भों पर महारत हासिल करनाद्वारा@gultm
757 रीडिंग
757 रीडिंग

gRPC-सीक्रेट: डेडलाइन, टाइमआउट और कस्टम संदर्भों पर महारत हासिल करना

द्वारा Tatyana9m2024/08/01
Read on Terminal Reader

बहुत लंबा; पढ़ने के लिए

gRPC एक ओपन-सोर्स रिमोट प्रोसीजर कॉल (RPC) फ्रेमवर्क है। यह सेवाओं के बीच कुशल और स्केलेबल संचार को सक्षम बनाता है। एक महत्वपूर्ण पहलू समय सीमा, अनुरोध समय-सीमा और संदर्भ के प्रसार का प्रबंधन है। इन तंत्रों को समझने से यह सुनिश्चित करने में मदद मिलती है कि सेवाएँ तुरंत प्रतिक्रिया दें।
featured image - gRPC-सीक्रेट: डेडलाइन, टाइमआउट और कस्टम संदर्भों पर महारत हासिल करना
Tatyana HackerNoon profile picture

gRPC, एक ओपन-सोर्स रिमोट प्रोसीजर कॉल (RPC) फ्रेमवर्क है, जो सेवाओं के बीच कुशल और स्केलेबल संचार को सक्षम बनाता है। gRPC का एक महत्वपूर्ण पहलू समय-सीमाओं, अनुरोध समय-सीमाओं और कस्टम संरचनाओं सहित संदर्भ के प्रसार का प्रबंधन है।


इन तंत्रों को समझने से यह सुनिश्चित करने में मदद मिलती है कि सेवाएं शीघ्र प्रतिक्रिया दें, संसाधनों को उचित समय सीमा से अधिक समय तक चलने वाले कार्यों पर बर्बाद न किया जाए, तथा कस्टम मेटाडेटा को प्रभावी ढंग से प्रेषित किया जाए।

समय-सीमा और अनुरोध टाइमआउट को समझना

समय सीमा

gRPC में समय-सीमा वह अधिकतम समय निर्दिष्ट करती है जिसके भीतर किसी ऑपरेशन को पूरा किया जाना चाहिए। यदि ऑपरेशन इस समय-सीमा के भीतर पूरा नहीं होता है, तो इसे स्वचालित रूप से समाप्त कर दिया जाएगा। समय-सीमा यह सुनिश्चित करने के लिए आवश्यक है कि सिस्टम संसाधन अनुत्तरदायी या धीमी सेवाओं के कारण अनिश्चित काल तक बंधे न रहें।

अनुरोध समय समाप्ति

अनुरोध टाइमआउट वह अवधि है जिसके दौरान क्लाइंट सर्वर से प्रतिक्रिया के लिए प्रतीक्षा करने को तैयार रहता है। यदि सर्वर इस अवधि के भीतर प्रतिक्रिया नहीं देता है, तो अनुरोध निरस्त कर दिया जाता है। यह तंत्र क्लाइंट को प्रतिक्रिया के लिए अनिश्चित काल तक प्रतीक्षा करने से बचाता है।

gRPC में समय-सीमा और अनुरोध समय-सीमा निर्धारित करना

gRPC क्लाइंट और सर्वर दोनों तरफ़ डेडलाइन सेट करने और टाइमआउट का अनुरोध करने के लिए लचीले विकल्प प्रदान करता है। यहाँ बताया गया है कि आप इसे Go में कैसे कर सकते हैं:

क्लाइंट-साइड सेटिंग समय सीमा


 import ( "context" "log" "time" "google.golang.org/grpc" pb "path/to/your/protobuf/package" ) func main() { conn, err := grpc.Dial("server_address", grpc.WithInsecure()) if err != nil { log.Fatalf("did not connect: %v", err) } defer conn.Close() client := pb.NewYourServiceClient(conn) ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() resp, err := client.YourMethod(ctx, &pb.YourRequest{}) if err != nil { log.Fatalf("could not call method: %v", err) } log.Printf("Response: %v", resp) }

सर्वर-साइड हैंडलिंग

सर्वर साइड पर, gRPC आपको समय-सीमा लागू करने और ऐसे परिदृश्यों को संभालने की अनुमति देता है जहां क्लाइंट द्वारा निर्दिष्ट समय-सीमा पार हो जाती है:


 import ( "context" "log" "net" "time" "google.golang.org/grpc" pb "path/to/your/protobuf/package" ) type server struct { pb.UnimplementedYourServiceServer } func (s *server) YourMethod(ctx context.Context, req *pb.YourRequest) (*pb.YourResponse, error) { select { case <-time.After(10 * time.Second): return &pb.YourResponse{}, nil case <-ctx.Done(): return nil, ctx.Err() } } func main() { lis, err := net.Listen("tcp", ":50051") if err != nil { log.Fatalf("failed to listen: %v", err) } s := grpc.NewServer() pb.RegisterYourServiceServer(s, &server{}) if err := s.Serve(lis); err != nil { log.Fatalf("failed to serve: %v", err) } }


संदर्भ में कस्टम संरचनाओं का प्रचार करना

gRPC में संदर्भ के माध्यम से कस्टम संरचनाएँ भेजने के लिए, आपको संदर्भ में संलग्न करने से पहले डेटा को क्रमबद्ध करना होगा और फिर प्राप्त करने वाले छोर पर इसे अक्रमबद्ध करना होगा। इसमें आपके कस्टम संरचनाओं को एक ऐसे प्रारूप में परिवर्तित करना शामिल है जिसे नेटवर्क पर प्रसारित किया जा सकता है, जैसे JSON या प्रोटोकॉल बफ़र्स, और फिर इस क्रमबद्ध डेटा को संदर्भ मेटाडेटा में जोड़ना।

चरण-दर-चरण प्रक्रिया

  1. अपनी कस्टम संरचना निर्धारित करें : वह कस्टम संरचना निर्धारित करें जिसे आप भेजना चाहते हैं।
  2. संरचना को क्रमबद्ध करें : कस्टम संरचना को स्ट्रिंग या बाइट सरणी में परिवर्तित करें।
  3. संदर्भ से जोड़ें : क्रमबद्ध डेटा को संदर्भ मेटाडेटा में जोड़ें।
  4. संचारित करें : संदर्भ के साथ gRPC कॉल भेजें.
  5. सर्वर पर निकालें और डिसेरिएलाइज़ करें : सर्वर साइड पर संदर्भ से मेटाडेटा निकालें और इसे वापस कस्टम संरचना में डिसेरिएलाइज़ करें।

चरण 1: अपनी कस्टम संरचना को परिभाषित करें


 type CustomStruct struct { Field1 string Field2 int }


चरण 2: संरचना को क्रमबद्ध करें


 import ( "context" "encoding/json" "fmt" "google.golang.org/grpc/metadata" ) func serializeCustomStruct(customStruct CustomStruct) (string, error) { data, err := json.Marshal(customStruct) if err != nil { return "", err } return string(data), nil }


चरण 3: संदर्भ से जुड़ें


 func attachCustomStructToContext(ctx context.Context, customStruct CustomStruct) (context.Context, error) { serializedData, err := serializeCustomStruct(customStruct) if err != nil { return nil, err } md := metadata.Pairs("custom-struct", serializedData) ctx = metadata.NewOutgoingContext(ctx, md) return ctx, nil }


चरण 4: संचारित करें


 func main() { conn, err := grpc.Dial("localhost:50051", grpc.WithInsecure()) if err != nil { log.Fatalf("did not connect: %v", err) } defer conn.Close() client := pb.NewYourServiceClient(conn) ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() customStruct := CustomStruct{Field1: "value1", Field2: 42} ctx, err = attachCustomStructToContext(ctx, customStruct) if err != nil { log.Fatalf("could not attach custom struct to context: %v", err) } resp, err := client.YourMethod(ctx, &pb.YourRequest{}) if err != nil { log.Fatalf("could not call method: %v", err) } log.Printf("Response: %v", resp) }


चरण 5: सर्वर पर एक्सट्रेक्ट और डिसेरीलाइज़ करें


 func deserializeCustomStruct(data string) (CustomStruct, error) { var customStruct CustomStruct err := json.Unmarshal([]byte(data), &customStruct) if err != nil { return CustomStruct{}, err } return customStruct, nil } func extractCustomStructFromContext(ctx context.Context) (CustomStruct, error) { md, ok := metadata.FromIncomingContext(ctx) if !ok { return CustomStruct{}, fmt.Errorf("no metadata found in context") } serializedData := md["custom-struct"] if len(serializedData) == 0 { return CustomStruct{}, fmt.Errorf("no custom struct found in metadata") } return deserializeCustomStruct(serializedData[0]) } func (s *server) YourMethod(ctx context.Context, req *pb.YourRequest) (*pb.YourResponse, error) { customStruct, err := extractCustomStructFromContext(ctx) if err != nil { return nil, err } log.Printf("Received custom struct: %+v", customStruct) select { case <-time.After(10 * time.Second): return &pb.YourResponse{}, nil case <-ctx.Done(): return nil, ctx.Err() } }


सभी gRPC कॉल के लिए मिडलवेयर का क्रियान्वयन

सभी gRPC कॉल में कस्टम संरचनाओं सहित संदर्भ प्रसार को संभालने के लिए, आप इंटरसेप्टर का उपयोग कर सकते हैं। इंटरसेप्टर मिडलवेयर हैं जो अनुरोधों और प्रतिक्रियाओं को संसाधित करते हैं, लॉगिंग, मॉनिटरिंग और संदर्भ मेटाडेटा हैंडलिंग जैसी कार्यक्षमता जोड़ते हैं।

यूनरी और स्ट्रीमिंग इंटरसेप्टर

विभिन्न प्रकार के RPC कॉलों को प्रबंधित करने के लिए आपको यूनरी और स्ट्रीमिंग दोनों इंटरसेप्टर की आवश्यकता होती है:


  • यूनरी इंटरसेप्टर : एकल अनुरोध-प्रतिक्रिया चक्रों को संभालते हैं।


  • स्ट्रीमिंग इंटरसेप्टर : क्लाइंट-साइड स्ट्रीमिंग, सर्वर-साइड स्ट्रीमिंग और द्विदिशात्मक स्ट्रीमिंग सहित अनुरोधों और प्रतिक्रियाओं की धाराओं को संभालते हैं।

यूनरी इंटरसेप्टर कार्यान्वयन

क्लाइंट-साइड यूनरी इंटरसेप्टर:


 func unaryClientInterceptor( ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption, ) error { customStruct, ok := ctx.Value("customStruct").(CustomStruct) if ok { ctx, err := attachCustomStructToContext(ctx, customStruct) if err != nil { return err } } return invoker(ctx, method, req, reply, cc, opts...) }


सर्वर-साइड यूनरी इंटरसेप्टर:


 func unaryServerInterceptor( ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler, ) (interface{}, error) { customStruct, err := extractCustomStructFromContext(ctx) if err != nil { return nil, err } ctx = context.WithValue(ctx, "customStruct", customStruct) return handler(ctx, req) }

स्ट्रीमिंग इंटरसेप्टर कार्यान्वयन

क्लाइंट-साइड स्ट्रीमिंग इंटरसेप्टर:


 func streamClientInterceptor( ctx context.Context, desc *grpc.StreamDesc, cc *grpc.ClientConn, method string, streamer grpc.Streamer, opts ...grpc.CallOption, ) (grpc.ClientStream, error) { customStruct, ok := ctx.Value("customStruct").(CustomStruct) if ok { ctx, err := attachCustomStructToContext(ctx, customStruct) if err != nil { return nil, err } } return


सर्वर-साइड स्ट्रीमिंग इंटरसेप्टर:


 import ( "context" "google.golang.org/grpc" "google.golang.org/grpc/metadata" ) // StreamServerInterceptor handles server-side streaming func streamServerInterceptor( srv interface{}, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler, ) error { ctx := ss.Context() customStruct, err := extractCustomStructFromContext(ctx) if err != nil { return err } // Add custom struct to context for server handling newCtx := context.WithValue(ctx, "customStruct", customStruct) wrapped := grpc_middleware.WrapServerStream(ss) wrapped.WrappedContext = newCtx // Handle the request return handler(srv, wrapped) } // Example of using the interceptor in a gRPC server setup func main() { lis, err := net.Listen("tcp", ":50051") if err != nil { log.Fatalf("failed to listen: %v", err) } // Register the interceptors server := grpc.NewServer( grpc.UnaryInterceptor(unaryServerInterceptor), grpc.StreamInterceptor(streamServerInterceptor), ) // Register your gRPC service implementations here pb.RegisterYourServiceServer(server, &yourServiceServer{}) if err := server.Serve(lis); err != nil { log.Fatalf("failed to serve: %v", err) } }


यूनेरी और स्ट्रीमिंग इंटरसेप्टर बनाकर और पंजीकृत करके, आप यह सुनिश्चित कर सकते हैं कि कस्टम संरचनाओं सहित संदर्भ प्रसार, सभी gRPC कॉल में लगातार संभाला जाता है। यह दृष्टिकोण सुनिश्चित करता है कि आपका कस्टम मेटाडेटा ठीक से प्रबंधित और प्रसारित किया जाता है, जिससे आप मजबूत और लचीली gRPC सेवाएँ बना सकते हैं।