জাভা দিয়ে একটি gRPC পরিষেবা তৈরি করা

১. সংক্ষিপ্ত বিবরণ

gRPC হলো গুগলে তৈরি একটি ভাষা-নিরপেক্ষ, প্ল্যাটফর্ম-নিরপেক্ষ রিমোট প্রসিডিউর কল (RPC) ফ্রেমওয়ার্ক এবং টুলসেট। এটি আপনাকে প্রোটোকল বাফার্স (Protocol Buffers) ব্যবহার করে একটি সার্ভিস সংজ্ঞায়িত করতে দেয়, যা একটি অত্যন্ত শক্তিশালী বাইনারি সিরিয়ালাইজেশন টুলসেট ও ভাষা। এরপর এটি আপনাকে আপনার সার্ভিস ডেফিনিশন থেকে বিভিন্ন ভাষায় প্রচলিত ক্লায়েন্ট এবং সার্ভার স্টাব তৈরি করতে দেয়।

এই কোডল্যাবে, আপনি শিখবেন কীভাবে gRPC ফ্রেমওয়ার্ক ব্যবহার করে একটি API প্রদানকারী জাভা-ভিত্তিক সার্ভিস তৈরি করতে হয় এবং তারপর তৈরি করা gRPC ক্লায়েন্ট-সাইড স্টাবটি ব্যবহার করার জন্য একটি ক্লায়েন্ট লিখতে হয়।

আপনি যা শিখবেন

  • প্রোটোকল বাফার ভাষা
  • জাভা ব্যবহার করে কীভাবে একটি gRPC পরিষেবা বাস্তবায়ন করা যায়
  • জাভা ব্যবহার করে কীভাবে একটি gRPC ক্লায়েন্ট বাস্তবায়ন করা যায়

আপনি এই টিউটোরিয়ালটি কীভাবে ব্যবহার করবেন?

শুধু পুরোটা পড়ুন এটি পড়ুন এবং অনুশীলনগুলো সম্পূর্ণ করুন।

Node.js অ্যাপ তৈরির অভিজ্ঞতাকে আপনি কীভাবে মূল্যায়ন করবেন?

শিক্ষানবিশ মধ্যবর্তী দক্ষ

Go অ্যাপ তৈরির অভিজ্ঞতাকে আপনি কীভাবে মূল্যায়ন করবেন?

শিক্ষানবিশ মধ্যবর্তী দক্ষ

২. সেটআপ এবং প্রয়োজনীয়তা

স্ব-গতিতে পরিবেশ সেটআপ

  1. ক্লাউড কনসোলে সাইন ইন করুন এবং একটি নতুন প্রজেক্ট তৈরি করুন অথবা বিদ্যমান কোনো প্রজেক্ট পুনরায় ব্যবহার করুন। যদি আপনার আগে থেকে কোনো Gmail বা Google Workspace অ্যাকাউন্ট না থাকে, তবে আপনাকে অবশ্যই একটি তৈরি করতে হবে।

96a9c957bc475304.png

b9a10ebdf5b5a448.png

a1e3c01a38fa61c2.png

প্রজেক্ট আইডিটি মনে রাখবেন, যা সমস্ত গুগল ক্লাউড প্রজেক্ট জুড়ে একটি অনন্য নাম (উপরের নামটি ইতিমধ্যে ব্যবহৃত হয়েছে এবং আপনার জন্য কাজ করবে না, দুঃখিত!)। এই কোডল্যাবে এটিকে পরবর্তীতে PROJECT_ID হিসাবে উল্লেখ করা হবে।

  1. এরপরে, গুগল ক্লাউড রিসোর্স ব্যবহার করার জন্য আপনাকে ক্লাউড কনসোলে বিলিং চালু করতে হবে।

এই কোডল্যাবটি চালাতে খুব বেশি খরচ হওয়ার কথা নয়, এমনকি আদৌ কোনো খরচ নাও হতে পারে। "পরিষ্কার-পরিচ্ছন্নতা" (Cleaning up) বিভাগে দেওয়া নির্দেশাবলী অবশ্যই অনুসরণ করবেন, যেখানে রিসোর্স বন্ধ করার পরামর্শ দেওয়া হয়েছে, যাতে এই টিউটোরিয়ালের বাইরে আপনার কোনো বিল না আসে। গুগল ক্লাউডের নতুন ব্যবহারকারীরা ৩০০ মার্কিন ডলারের ফ্রি ট্রায়াল প্রোগ্রামের জন্য যোগ্য।

গুগল ক্লাউড শেল

যদিও এই কোডল্যাবটি আপনার কম্পিউটার থেকে চালানো যায়, তবুও আমরা এখানে গুগল ক্লাউড শেল ব্যবহার করব, যা ক্লাউডে চালিত একটি কমান্ড লাইন এনভায়রনমেন্ট।

এই ডেবিয়ান-ভিত্তিক ভার্চুয়াল মেশিনটিতে আপনার প্রয়োজনীয় সমস্ত ডেভেলপমেন্ট টুলস লোড করা আছে। এটি একটি স্থায়ী ৫ জিবি হোম ডিরেক্টরি প্রদান করে এবং গুগল ক্লাউডে চলে, যা নেটওয়ার্ক পারফরম্যান্স ও অথেনটিকেশনকে ব্যাপকভাবে উন্নত করে। এর মানে হলো, এই কোডল্যাবের জন্য আপনার শুধু একটি ব্রাউজার প্রয়োজন হবে (হ্যাঁ, এটি ক্রোমবুকেও কাজ করে)।

  1. ক্লাউড কনসোল থেকে ক্লাউড শেল সক্রিয় করতে, কেবল 'Activate Cloud Shell'-এ ক্লিক করুন। a8460e837e9f5fda.png (পরিবেশের জন্য ব্যবস্থা করতে এবং সংযোগ স্থাপন করতে মাত্র কয়েক মুহূর্ত সময় লাগা উচিত)।

b532b2f19ab85dda.png

Screen Shot 2017-06-14 at 10.13.43 PM.png

ক্লাউড শেলে সংযুক্ত হওয়ার পর, আপনি দেখতে পাবেন যে আপনাকে ইতিমধ্যেই প্রমাণীকৃত করা হয়েছে এবং প্রজেক্টটি আপনার PROJECT_ID তে সেট করা আছে।

gcloud auth list

কমান্ড আউটপুট

Credentialed accounts:
 - <myaccount>@<mydomain>.com (active)
gcloud config list project

কমান্ড আউটপুট

[core]
project = <PROJECT_ID>

যদি কোনো কারণে প্রজেক্টটি সেট করা না থাকে, তাহলে নিম্নলিখিত কমান্ডটি দিন:

gcloud config set project <PROJECT_ID>

আপনার PROJECT_ID খুঁজছেন? সেটআপের ধাপগুলিতে আপনি কোন আইডি ব্যবহার করেছিলেন তা দেখে নিন অথবা ক্লাউড কনসোল ড্যাশবোর্ডে এটি খুঁজে দেখুন:

2485e00c1223af09.png

ক্লাউড শেল ডিফল্টরূপে কিছু এনভায়রনমেন্ট ভেরিয়েবলও সেট করে, যা ভবিষ্যতে কমান্ড চালানোর সময় কাজে লাগতে পারে।

echo $GOOGLE_CLOUD_PROJECT

কমান্ড আউটপুট

<PROJECT_ID>
  1. অবশেষে, ডিফল্ট জোন এবং প্রজেক্ট কনফিগারেশন সেট করুন।
gcloud config set compute/zone us-central1-f

আপনি বিভিন্ন ধরনের জোন বেছে নিতে পারেন। আরও তথ্যের জন্য, অঞ্চল ও জোন দেখুন।

৩. একটি gRPC সার্ভিস তৈরি করুন

Maven ব্যবহার করে একটি নতুন জাভা প্রজেক্ট তৈরি করুন:

$ mvn archetype:generate -DgroupId=com.example.grpc \
 -DartifactId=grpc-hello-server \
 -DarchetypeArtifactId=maven-archetype-quickstart \
 -DinteractiveMode=false
$ cd grpc-hello-server

একটি gRPC ডেফিনিশন ফাইল যোগ করুন

gRPC-তে, সার্ভিস পেলোড (রিকোয়েস্ট এবং রেসপন্স) এবং সার্ভিস অপারেশনগুলোকে একটি IDL (ইন্টারফেস ডেফিনিশন ল্যাঙ্গুয়েজ)-এ লিপিবদ্ধ করতে হয়। gRPC মেসেজ পেলোড এবং অপারেশনগুলো সংজ্ঞায়িত করার জন্য প্রোটোবাফার ৩ সিনট্যাক্স ব্যবহার করে। চলুন, একটি হ্যালো রিকোয়েস্ট এবং হ্যালো রেসপন্স সহ একটি সাধারণ গ্রিটিং সার্ভিসের জন্য একটি প্রোটো ফাইল তৈরি করি।

প্রথমে, নতুন প্রোটো ফাইলটি রাখার জন্য একটি নতুন প্রোটো ডিরেক্টরি তৈরি করুন:

$ mkdir -p src/main/proto

এরপর, src/main/proto/GreetingService.proto একটি নতুন প্রোটো ফাইল তৈরি করুন।

ফাইলটি সম্পাদনা করতে আপনি vim,nano, বা emacs ব্যবহার করতে পারেন:

src/main/proto/GreetingService.proto

syntax = "proto3";
package com.example.grpc;

// Request payload
message HelloRequest {
  // Each message attribute is strongly typed.
  // You also must assign a "tag" number.
  // Each tag number is unique within the message.
  string name = 1;

  // This defines a strongly typed list of String
  repeated string hobbies = 2;

  // There are many more basics types, like Enum, Map
  // See https://developers.google.com/protocol-buffers/docs/proto3
  // for more information.
}

message HelloResponse {
  string greeting = 1;
}

// Defining a Service, a Service can have multiple RPC operations
service GreetingService {
  // Define a RPC operation
  rpc greeting(HelloRequest) returns (HelloResponse);
}

gRPC নির্ভরতা এবং প্লাগইন যোগ করুন

একবার সংজ্ঞাটি পেয়ে গেলে, আমরা এই ফাইলটি থেকে সার্ভার-সাইড স্টাব এবং ক্লায়েন্ট-সাইড স্টাব উভয়ই তৈরি করতে পারব। আপনাকে gRPC ডিপেন্ডেন্সি এবং প্লাগইনগুলো যোগ করতে হবে।

প্রথমে, pom.xml এ gRPC নির্ভরতাগুলি যোগ করুন:

pom.xml

<project>
  ...
  <dependencies>
    <dependency>
      <groupId>io.grpc</groupId>
      <artifactId>grpc-netty-shaded</artifactId>
      <version>1.24.0</version>
    </dependency>
    <dependency>
      <groupId>io.grpc</groupId>
      <artifactId>grpc-protobuf</artifactId>
      <version>1.24.0</version>
    </dependency>
    <dependency>
      <groupId>io.grpc</groupId>
      <artifactId>grpc-stub</artifactId>
      <version>1.24.0</version>
    </dependency>
    <dependency>
      <groupId>javax.annotation</groupId>
      <artifactId>javax.annotation-api</artifactId>
      <version>1.3.2</version>
    </dependency>
    ...
  </dependencies>
  ...
</project>

তারপর প্লাগইনটি যোগ করুন:

pom.xml

<project>
  ...
  <dependencies>
    ...
  </dependencies>
  <build>
    <extensions>
      <extension>
        <groupId>kr.motd.maven</groupId>
        <artifactId>os-maven-plugin</artifactId>
        <version>1.6.2</version>
      </extension>
    </extensions>
    <plugins>
      <plugin>
        <groupId>org.xolstice.maven.plugins</groupId>
        <artifactId>protobuf-maven-plugin</artifactId>
        <version>0.6.1</version>
        <configuration>
          <protocArtifact>com.google.protobuf:protoc:3.9.0:exe:${os.detected.classifier}</protocArtifact>
          <pluginId>grpc-java</pluginId>
          <pluginArtifact>io.grpc:protoc-gen-grpc-java:1.24.0:exe:${os.detected.classifier}</pluginArtifact>
        </configuration>
        <executions>
          <execution>
            <goals>
              <goal>compile</goal>
              <goal>compile-custom</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>

</project>

স্টাবগুলি তৈরি করুন

যখন আপনি অ্যাপ্লিকেশনটি বিল্ড করবেন, প্লাগইনটি প্রোটো ডেফিনিশনগুলোকে জাভা কোডে রূপান্তর করবে।

$ mvn -DskipTests package

তৈরি হওয়া ফাইলগুলো দেখতে:

$ find target/generated-sources

পরিষেবাটি বাস্তবায়ন করুন

প্রথমে, একটি নতুন GreetingServiceImpl ক্লাস তৈরি করুন যা greeting কার্যক্রমটি বাস্তবায়ন করবে:

src/main/java/com/example/grpc/GreetingServiceImpl.java

package com.example.grpc;

import io.grpc.stub.StreamObserver;

public class GreetingServiceImpl extends GreetingServiceGrpc.GreetingServiceImplBase {
  @Override
  public void greeting(GreetingServiceOuterClass.HelloRequest request,
        StreamObserver<GreetingServiceOuterClass.HelloResponse> responseObserver) {
  // HelloRequest has toString auto-generated.
    System.out.println(request);

    // You must use a builder to construct a new Protobuffer object
    GreetingServiceOuterClass.HelloResponse response = GreetingServiceOuterClass.HelloResponse.newBuilder()
      .setGreeting("Hello there, " + request.getName())
      .build();

    // Use responseObserver to send a single response back
    responseObserver.onNext(response);

    // When you are done, you must call onCompleted.
    responseObserver.onCompleted();
  }
}

Implement the Server

অবশেষে, একটি পোর্টে শোনার জন্য আপনাকে একটি সার্ভার চালু করতে হবে এবং এই সার্ভিস ইমপ্লিমেন্টেশনটি রেজিস্টার করতে হবে। App ক্লাস এবং এর main মেথডটি এডিট করুন:

src/main/java/com/example/grpc/App.java

package com.example.grpc;

import io.grpc.*;

public class App
{
    public static void main( String[] args ) throws Exception
    {
      // Create a new server to listen on port 8080
      Server server = ServerBuilder.forPort(8080)
        .addService(new GreetingServiceImpl())
        .build();

      // Start the server
      server.start();

      // Server threads are running in the background.
      System.out.println("Server started");
      // Don't exit the main thread. Wait until server is terminated.
      server.awaitTermination();
    }
}

অবশেষে, সার্ভারটি চালু করুন:

$ mvn -DskipTests package exec:java -Dexec.mainClass=com.example.grpc.App
...
Server Started

৪. পরিষেবা গ্রহণ

জেনারেটরটি ইতিমধ্যে সমস্ত ক্লায়েন্ট-সাইড স্টাব তৈরি করে ফেলেছে। ল্যাবের সুবিধার জন্য, আমরা একই Maven প্রজেক্ট ব্যবহার করব, তবে শুধু একটি নতুন main মেথডসহ একটি নতুন Client ক্লাস যোগ করব।

প্রথমে, একটি নতুন ক্লাউড শেল সেশন খুলতে + চিহ্নে ক্লিক করুন, যাতে আপনাকে সার্ভারটি বন্ধ করতে না হয়:

1ff0fda960b9adfc.png

নতুন সেশনে, grpc-hello-server ডিরেক্টরিতে যান:

$ cd grpc-hello-server

তারপর, নতুন Client ক্লাসটি যোগ করুন:

src/main/java/com/example/grpc/Client.java

package com.example.grpc;

import io.grpc.*;

public class Client
{
    public static void main( String[] args ) throws Exception
    {
      // Channel is the abstraction to connect to a service endpoint
      // Let's use plaintext communication because we don't have certs
      final ManagedChannel channel = ManagedChannelBuilder.forTarget("localhost:8080")
        .usePlaintext(true)
        .build();

      // It is up to the client to determine whether to block the call
      // Here we create a blocking stub, but an async stub,
      // or an async stub with Future are always possible.
      GreetingServiceGrpc.GreetingServiceBlockingStub stub = GreetingServiceGrpc.newBlockingStub(channel);
      GreetingServiceOuterClass.HelloRequest request =
        GreetingServiceOuterClass.HelloRequest.newBuilder()
          .setName("Ray")
          .build();

      // Finally, make the call using the stub
      GreetingServiceOuterClass.HelloResponse response = 
        stub.greeting(request);

      System.out.println(response);

      // A Channel should be shutdown before stopping the process.
      channel.shutdownNow();
    }
}

অবশেষে, ক্লায়েন্টটি চালান:

$ mvn -DskipTests package exec:java -Dexec.mainClass=com.example.grpc.Client
...
greeting: "Hello there, Ray"

ব্যাস! বেশ সহজ, তাই না?

৫. স্ট্রিমিং পরিষেবা

আপনি আরও অনেক কিছু চেষ্টা করতে পারেন। উদাহরণস্বরূপ, আপনি প্রোটো ফাইলে রিকোয়েস্ট অথবা রেসপন্স প্যারামিটারে শুধু stream ' কীওয়ার্ডটি যোগ করেই খুব সহজে একটি স্ট্রিমিং সার্ভিস তৈরি করতে পারেন, যেমন—

src/main/proto/GreetingService.proto

syntax = "proto3";
package com.example.grpc;

...

// Defining a Service, a Service can have multiple RPC operations
service GreetingService {
  // MODIFY HERE: Update the return to streaming return.
  rpc greeting(HelloRequest) returns (stream HelloResponse);
}

আপনার সার্ভারকে একটির পরিবর্তে একাধিক প্রতিক্রিয়া পাঠানোর জন্য আপডেট করুন। আপনি একাধিক responseObserver.onNext(...) কল করার মাধ্যমে এটি করতে পারেন:

src/main/java/com/example/grpc/GreetingServiceImpl.java

package com.example.grpc;

import io.grpc.stub.StreamObserver;

public class GreetingServiceImpl extends GreetingServiceGrpc.GreetingServiceImplBase {
  @Override
  public void greeting(GreetingServiceOuterClass.HelloRequest request,
        StreamObserver<GreetingServiceOuterClass.HelloResponse> responseObserver) {
 
    ...

    // Feel free to construct different responses if you'd like.
    responseObserver.onNext(response);
    responseObserver.onNext(response);
    responseObserver.onNext(response);

    // When you are done, you must call onCompleted.
    responseObserver.onCompleted();
  }
}

ক্লায়েন্টকে ব্লকিং স্টাবের পরিবর্তে অবশ্যই একটি অ্যাসিঙ্ক্রোনাস স্টাব ব্যবহার করতে হবে। ক্লায়েন্ট কোডটি আপডেট করুন এবং নিশ্চিত করুন যে stub ধরনটি GreetingServiceStub এ আপডেট করা হয়েছে।

src/main/java/com/example/grpc/Client.java

package com.example.grpc;

import io.grpc.*;

// New import
import io.grpc.stub.*;

public class Client
{
    public static void main( String[] args ) throws Exception
    {
      final ManagedChannel channel = ManagedChannelBuilder.forTarget("localhost:8080")
        .usePlaintext(true)
        .build();

      // Replace the previous synchronous code with asynchronous code.
      // This time use an async stub:
       GreetingServiceGrpc.GreetingServiceStub stub = GreetingServiceGrpc.newStub(channel);

      // Construct a request
      GreetingServiceOuterClass.HelloRequest request =
        GreetingServiceOuterClass.HelloRequest.newBuilder()
          .setName("Ray")
          .build();

      // Make an Asynchronous call. Listen to responses w/ StreamObserver
      stub.greeting(request, new StreamObserver<GreetingServiceOuterClass.HelloResponse>() {
        public void onNext(GreetingServiceOuterClass.HelloResponse response) {
          System.out.println(response);
        }
        public void onError(Throwable t) {
        }
        public void onCompleted() {
          // Typically you'll shutdown the channel somewhere else.
          // But for the purpose of the lab, we are only making a single
          // request. We'll shutdown as soon as this request is done.
          channel.shutdownNow();
        }
      });
    }
}

অ্যাপ্লিকেশনটি পুনর্নির্মাণ করুন:

$ mvn -DskipTests package

সার্ভার এবং ক্লায়েন্ট উভয়কেই নিজ নিজ ক্লাউড শেল সেশনে পুনরায় চালু করুন।

সার্ভার চালু করতে:

$ mvn exec:java -Dexec.mainClass=com.example.grpc.App
...
Server Started

ক্লায়েন্ট শুরু করতে:

$ mvn exec:java -Dexec.mainClass=com.example.grpc.Client
...
greeting: "Hello there, Ray"
greeting: "Hello there, Ray"
greeting: "Hello there, Ray"

৬. অভিনন্দন!

আমরা যা আলোচনা করেছি:

  • প্রোটোকল বাফার ভাষা
  • জাভা ব্যবহার করে কীভাবে একটি gRPC সার্ভার বাস্তবায়ন করবেন
  • জাভা ব্যবহার করে কীভাবে একটি gRPC ক্লায়েন্ট বাস্তবায়ন করা যায়

পরবর্তী পদক্ষেপ:

আপনার মতামত দিন

  • অনুগ্রহ করে একটু সময় নিয়ে আমাদের এই সংক্ষিপ্ত সমীক্ষাটি পূরণ করুন।