क्यों आधुनिक माइक्रोसर्विसेज REST की तुलना में GRPC को प्राथमिकता देते हैं

क्यों आधुनिक माइक्रोसर्विसेज REST की तुलना में GRPC को प्राथमिकता देते हैं

एक अखंड वास्तुकला में, घटक इन-मेमोरी विधि कॉल के माध्यम से संचार करते हैं, जो तात्कालिक और अत्यधिक विश्वसनीय होते हैं। हालाँकि, माइक्रोसर्विसेज आर्किटेक्चर की ओर बढ़ते समय, इन घटकों को नेटवर्क सीमाओं द्वारा अलग किया जाता है। संचार एक आउट-ऑफ-प्रोसेस नेटवर्क कॉल (इंटर-प्रोसेस कम्युनिकेशन, या आईपीसी) बन जाता है।

वर्षों से, JSON पेलोड के साथ HTTP/1.1 पर REST (प्रतिनिधि राज्य स्थानांतरण) वेब एपीआई के निर्माण के लिए डिफ़ॉल्ट मानक रहा है। जबकि REST सार्वजनिक-सामना वाली वेब सेवाओं और क्लाइंट-टू-सर्वर इंटरैक्शन के लिए उत्कृष्ट है, उच्च-आवृत्ति, कम-विलंबता, आंतरिक सेवा-से-सेवा संचार के लिए उपयोग किए जाने पर यह महत्वपूर्ण बाधाओं का परिचय देता है।

यही कारण है कि आधुनिक माइक्रोसर्विसेज तेजी से gRPC (Google रिमोट प्रोसीजर कॉल) की ओर बढ़ रहे हैं। इस लेख में, हम REST की सीमाओं का विश्लेषण करेंगे, GRPC के वास्तुशिल्प स्तंभों का विश्लेषण करेंगे, और Java में GRPC सेवा के पूर्ण कार्यान्वयन के बारे में जानेंगे।


1. माइक्रोसर्विसेज में REST की बाधाएँ

REST ने दो दशकों से अधिक समय से वेब को संचालित किया है। हालाँकि, इसकी अंतर्निहित प्रौद्योगिकियाँ आंतरिक वितरित आर्किटेक्चर के लिए अनुकूलित नहीं हैं:

A. प्लेन-टेक्स्ट JSON का ओवरहेड

JSON मानव-पठनीय है, जो डिबगिंग को आसान बनाता है, लेकिन यह मशीन-टू-मशीन संचार के लिए बेहद अक्षम है:

  • क्रमबद्धता/डीसेरिएलाइज़ेशन लागत: टेक्स्ट स्ट्रिंग टोकन को पार्स करना और उन्हें ऑब्जेक्ट में परिवर्तित करना पर्याप्त सीपीयू चक्र की खपत करता है।
  • बड़ा पेलोड आकार: JSON कुंजियाँ हर एक अनुरोध में दोहराई जाती हैं (उदाहरण के लिए, {"transactionId": "123", "amount": 99.99})। प्रति सेकंड लाखों अनुरोधों को संसाधित करने वाले सिस्टम के लिए, यह अनावश्यक मेटाडेटा विशाल नेटवर्क बैंडविड्थ को बर्बाद करता है।

बी. HTTP/1.1 कनेक्शन सीमाएँ

REST आमतौर पर HTTP/1.1 पर चलता है, जो कई संरचनात्मक अक्षमताओं को प्रदर्शित करता है:

  • हेड-ऑफ़-लाइन (एचओएल) ब्लॉकिंग: एकल टीसीपी कनेक्शन पर, क्लाइंट को अगला अनुरोध भेजने से पहले वर्तमान अनुरोध की प्रतिक्रिया की प्रतीक्षा करनी होगी।
  • कनेक्शन पूलिंग थकावट: समवर्ती अनुरोधों को संभालने के लिए, ग्राहकों को एकाधिक टीसीपी कनेक्शन खोलने होंगे। इसके परिणामस्वरूप महत्वपूर्ण OS संसाधन ओवरहेड, सॉकेट थकावट, और धीमी गति से प्रारंभ प्रदर्शन दंड होता है क्योंकि कनेक्शन लगातार खोले और बंद किए जाते हैं।

सी. कमजोर एपीआई अनुबंध

REST API में अंतर्निहित, संकलन-समय अनुबंध का अभाव है। जबकि ओपनएपीआई/स्वैगर दस्तावेज़ एपीआई की मदद करता है, वे कोडबेस से अलग होते हैं। बैकएंड डेवलपर के लिए JSON फ़ील्ड का नाम बदलना और संकलन-समय की चेतावनियों के बिना गलती से डाउनस्ट्रीम सेवाओं को तोड़ना आसान है।


2. जीआरपीसी के वास्तुशिल्प स्तंभ

2015 में Google द्वारा प्रस्तुत, gRPC एक ओपन-सोर्स, उच्च-प्रदर्शन RPC फ्रेमवर्क है जिसे विशेष रूप से क्लाउड-नेटिव अनुप्रयोगों के लिए डिज़ाइन किया गया है। यह तीन प्रमुख तकनीकों का उपयोग करके REST की बाधाओं को हल करता है:

जीआरपीसी के 3 वास्तुशिल्प स्तंभ: प्रोटोकॉल बफ़र्स, HTTP/2 ट्रांसपोर्ट, और कोड जेनरेशन

ए. प्रोटोकॉल बफ़र्स (प्रोटोबफ़)

JSON के बजाय, gRPC अपने इंटरफ़ेस डेफिनिशन लैंग्वेज (IDL) और संदेश क्रमांकन प्रारूप के रूप में प्रोटोकॉल बफ़र्स का उपयोग करता है।

  • प्रोटोबफ़ एक अत्यधिक अनुकूलित बाइनरी क्रमबद्धता तंत्र है।
  • फ़ील्ड्स को टेक्स्ट नामों के बजाय छोटे संख्यात्मक टैग के रूप में क्रमबद्ध किया जाता है।
  • पेलोड JSON की तुलना में 70-80% छोटे होते हैं, और क्रमबद्धता 10x तेज तक होती है, जिससे CPU और बैंडविड्थ का उपयोग काफी कम हो जाता है।

बी. HTTP/2 मल्टीप्लेक्सिंग

जीआरपीसी अपने परिवहन प्रोटोकॉल के रूप में HTTP/2 का उपयोग करता है, जिससे कई प्रदर्शन अनुकूलन आते हैं:

  • ट्रू मल्टीप्लेक्सिंग: एक सिंगल लंबे समय तक चलने वाले टीसीपी कनेक्शन पर कई अनुरोधों और प्रतिक्रियाओं को एक साथ इंटरलीव किया जा सकता है, जिससे हेड-ऑफ-लाइन ब्लॉकिंग पूरी तरह खत्म हो जाती है।
  • हेडर संपीड़न (HPACK): HTTP हेडर संपीड़ित होते हैं, जिससे अनुरोध का आकार और कम हो जाता है।
  • स्ट्रीमिंग समर्थन: HTTP/2 मूल रूप से यूनिडायरेक्शनल क्लाइंट स्ट्रीमिंग, सर्वर स्ट्रीमिंग और पूर्ण द्विदिशीय स्ट्रीमिंग का समर्थन करता है।

सी. कोड जनरेशन और सख्त अनुबंध

.proto फ़ाइल में एपीआई संरचना को परिभाषित करके, जीआरपीसी दर्जनों भाषाओं (जावा, गो, पायथन, सी++, आदि) में क्लाइंट स्टब्स और सर्वर बेस क्लास उत्पन्न करता है। अनुबंध संकलन-समय सुरक्षित है; यदि सर्वर अपने इंटरफ़ेस को अपडेट करता है, तो क्लाइंट बिल्ड नए अनुबंध से मेल नहीं खाने पर तुरंत विफल हो जाते हैं।


3. जावा कार्यान्वयन: एक जीआरपीसी सेवा का निर्माण

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

चरण 1: एपीआई अनुबंध को परिभाषित करें (payment.proto)

हम प्रोटोकॉल बफ़र फ़ाइल में अपने सेवा इंटरफ़ेस और संदेश संरचनाओं को परिभाषित करके प्रारंभ करते हैं।

syntax = "proto3";

option java_multiple_files = true;
option java_package = "com.ghaznix.grpc.payment";
option java_outer_classname = "PaymentProto";

package payment;

// The Payment Service definition
service PaymentService {
  // Unary RPC: Sends a single payment request and receives a confirmation
  rpc ProcessPayment (PaymentRequest) returns (PaymentResponse);
}

// The Payment Request message
message PaymentRequest {
  string transaction_id = 1;
  string customer_id = 2;
  double amount = 3;
  string currency = 4;
}

// The Payment Response message
message PaymentResponse {
  string transaction_id = 1;
  string status = 2;
  string message = 3;
  string timestamp = 4;
}

चरण 2: सर्वर-साइड लॉजिक लागू करें

.proto फ़ाइल को संकलित करने के बाद (आमतौर पर मेवेन या ग्रैडल gRPC प्लगइन्स द्वारा स्वचालित रूप से नियंत्रित किया जाता है), टूल PaymentServiceImplBase क्लास उत्पन्न करता है। हम व्यावसायिक तर्क को लागू करने के लिए इस वर्ग का विस्तार करते हैं।

package com.ghaznix.grpc.payment;

import io.grpc.stub.StreamObserver;
import java.time.Instant;

public class PaymentServiceImpl extends PaymentServiceGrpc.PaymentServiceImplBase {

    @Override
    public void processPayment(PaymentRequest request, StreamObserver<PaymentResponse> responseObserver) {
        System.out.println("Received payment request for customer: " + request.getCustomerId() 
                + " with amount: " + request.getAmount() + " " + request.getCurrency());

        // Process payment logic (simulation)
        String status = request.getAmount() > 0 ? "SUCCESS" : "DECLINED";
        String message = status.equals("SUCCESS") ? "Payment processed successfully." : "Invalid payment amount.";

        PaymentResponse response = PaymentResponse.newBuilder()
                .setTransactionId(request.getTransactionId())
                .setStatus(status)
                .setMessage(message)
                .setTimestamp(Instant.now().toString())
                .build();

        // Send the response to the client
        responseObserver.onNext(response);
        
        // Signal that the RPC execution is complete
        responseObserver.onCompleted();
    }
}

चरण 3: जीआरपीसी सर्वर को बूटस्ट्रैप करें

इसके बाद, हम एक विशिष्ट पोर्ट पर जीआरपीसी सर्वर शुरू करने और हमारी सेवा कार्यान्वयन को पंजीकृत करने के लिए एक सर्वर क्लास बनाते हैं।

package com.ghaznix.grpc.payment;

import io.grpc.Server;
import io.grpc.ServerBuilder;
import java.io.IOException;
import java.util.concurrent.TimeUnit;

public class PaymentServer {

    private Server server;

    public void start() throws IOException {
        int port = 50051;
        server = ServerBuilder.forPort(port)
                .addService(new PaymentServiceImpl())
                .build()
                .start();
        
        System.out.println("gRPC Server started, listening on port " + port);

        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            System.err.println("*** Shutting down gRPC server since JVM is shutting down");
            try {
                PaymentServer.this.stop();
            } catch (InterruptedException e) {
                e.printStackTrace(System.err);
            }
            System.err.println("*** Server shut down");
        }));
    }

    public void stop() throws InterruptedException {
        if (server != null) {
            server.shutdown().awaitTermination(30, TimeUnit.SECONDS);
        }
    }

    public void blockUntilShutdown() throws InterruptedException {
        if (server != null) {
            server.awaitTermination();
        }
    }

    public static void main(String[] args) throws IOException, InterruptedException {
        final PaymentServer server = new PaymentServer();
        server.start();
        server.blockUntilShutdown();
    }
}

चरण 4: क्लाइंट को लागू करें (ब्लॉकिंग और एसिंक स्टब्स)

जीआरपीसी का एक प्रमुख लाभ यह है कि यह क्लाइंट के लिए दो प्रकार के स्टब्स उत्पन्न करता है:

  1. ब्लॉकिंगस्टब: सिंक्रोनस, ब्लॉकिंग निष्पादन (मानक REST कॉल के समान)।
  2. स्टब: कॉलबैक पर्यवेक्षकों का उपयोग करके अतुल्यकालिक, गैर-अवरुद्ध निष्पादन।
package com.ghaznix.grpc.payment;

import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import java.util.concurrent.TimeUnit;

public class PaymentClient {

    private final ManagedChannel channel;
    private final PaymentServiceGrpc.PaymentServiceBlockingStub blockingStub;

    public PaymentClient(String host, int port) {
        // Create a communication channel to the server
        this.channel = ManagedChannelBuilder.forAddress(host, port)
                .usePlaintext() // Disables TLS for local development
                .build();
        
        // Create the synchronous blocking stub
        this.blockingStub = PaymentServiceGrpc.newBlockingStub(channel);
    }

    public void shutdown() throws InterruptedException {
        channel.shutdown().awaitTermination(5, TimeUnit.SECONDS);
    }

    public void executePayment(String txId, String customerId, double amount) {
        PaymentRequest request = PaymentRequest.newBuilder()
                .setTransactionId(txId)
                .setCustomerId(customerId)
                .setAmount(amount)
                .setCurrency("USD")
                .build();

        System.out.println("Sending payment request for: " + txId);
        
        // Execute unary synchronous call
        PaymentResponse response = blockingStub.processPayment(request);
        
        System.out.println("Server Response: " + response.getStatus() + " | " + response.getMessage());
    }

    public static void main(String[] args) throws InterruptedException {
        PaymentClient client = new PaymentClient("localhost", 50051);
        try {
            client.executePayment("TX-99081", "customer-abc-123", 250.75);
        } finally {
            client.shutdown();
        }
    }
}

4. वास्तुशिल्प तुलना: जीआरपीसी बनाम आरईएसटी

नीचे दी गई तालिका दोनों प्रतिमानों की मुख्य विशेषताओं को रेखांकित करती है:

वास्तुशिल्प विशेषता REST (प्रतिनिधि राज्य स्थानांतरण) जीआरपीसी (गूगल रिमोट प्रोसीजर कॉल)
प्रोटोकॉल HTTP/1.1 (मानक), HTTP/2 (वैकल्पिक) HTTP/2 (सख्त आवश्यकता)
पेलोड प्रारूप सादा पाठ JSON, XML, HTML बाइनरी प्रोटोकॉल बफ़र्स (प्रोटोबफ़)
एपीआई प्रतिमान संसाधन (यूआरआई पथ + प्राप्त/पोस्ट/पुट/डिलीट) दूरस्थ प्रक्रियाएँ (तरीके/फ़ंक्शन कॉल)
अनुबंध गुणवत्ता ढीला (ओपनएपीआई/स्वैगर वैकल्पिक/बाहरी है) सख्त (संकलन के समय .proto फ़ाइलों में परिभाषित)
मल्टीप्लेक्सिंग नहीं (HTTP/1.1 में हेड-ऑफ़-लाइन ब्लॉकिंग) हां (एकल टीसीपी कनेक्शन पर एकाधिक स्ट्रीम)
स्ट्रीमिंग प्रकार केवल यूनिडायरेक्शनल सर्वर-भेजे गए इवेंट (एसएसई) क्लाइंट, सर्वर और द्विदिशीय स्ट्रीमिंग
कोड जनरेशन बाहरी उपकरणों की आवश्यकता (उदाहरण के लिए, स्वैगर कोडजेन) प्रोटोबफ़ कंपाइलर (protoc) के माध्यम से अंतर्निर्मित
ब्राउज़र समर्थन यूनिवर्सल (डायरेक्ट वेब क्लाइंट एक्सेस) सीमित (grpc-web प्रॉक्सी अनुवाद की आवश्यकता है)

5. REST के स्थान पर GRPC कब चुनें?

जीआरपीसी के व्यापक प्रदर्शन लाभों के बावजूद, यह कोई उम्मीद की किरण नहीं है। प्रोटोकॉल का चुनाव आपके सिस्टम आर्किटेक्चर के संदर्भ पर निर्भर करता है:

  • आंतरिक माइक्रोसर्विस मेश के लिए जीआरपीसी का उपयोग करें: उच्च-मात्रा सेवा-से-सेवा संचार के लिए, जीआरपीसी की कम विलंबता, बाइनरी कॉम्पैक्टनेस और स्ट्रीमिंग क्षमताएं इसे बेहतर विकल्प बनाती हैं। यह आंतरिक सर्वर सीपीयू ओवरहेड को कम करता है और समग्र प्रतिक्रिया समय को गति देता है।
  • एज/सार्वजनिक एपीआई के लिए REST का उपयोग करें: क्योंकि वेब ब्राउज़र अनुवाद परतों के बिना मूल रूप से GRPC कॉल नहीं कर सकते हैं, REST सार्वजनिक एपीआई, तृतीय-पक्ष वेबहुक के साथ एकीकरण और क्लाइंट ब्राउज़र से आपके आर्किटेक्चर के किनारे तक सीधे संचार के लिए सबसे अच्छा विकल्प बना हुआ है।

दोनों को मिलाकर - एपीआई गेटवे स्तर पर REST को उजागर करना और आंतरिक माइक्रोसर्विस संचार के लिए gRPC का लाभ उठाना - आर्किटेक्ट ऐसे सिस्टम का निर्माण कर सकते हैं जो अत्यधिक इंटरऑपरेबल और बहुत तेज़ दोनों हैं।


ग़ज़निक्स ब्लॉग पर अधिक सॉफ़्टवेयर विकास और बैकएंड इंजीनियरिंग अंतर्दृष्टि का अन्वेषण करें →