gRPC-জাভা দিয়ে শুরু করা

1. ভূমিকা

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

টিউটোরিয়ালের শেষে, আপনার কাছে একটি ক্লায়েন্ট থাকবে যেটি একটি মানচিত্রের নির্দিষ্ট স্থানাঙ্কে কী আছে তার নাম বা ডাক ঠিকানা পেতে gRPC ব্যবহার করে একটি দূরবর্তী সার্ভারের সাথে সংযোগ করে। একটি সম্পূর্ণরূপে উন্নত অ্যাপ্লিকেশন এই ক্লায়েন্ট-সার্ভার ডিজাইন ব্যবহার করতে পারে একটি রুট বরাবর আগ্রহের পয়েন্টগুলি গণনা বা সংক্ষিপ্ত করতে।

সার্ভারের API একটি প্রোটোকল বাফার ফাইলে সংজ্ঞায়িত করা হয়েছে, যা ক্লায়েন্ট এবং সার্ভারের জন্য বয়লারপ্লেট কোড তৈরি করতে ব্যবহার করা হবে যাতে তারা একে অপরের সাথে যোগাযোগ করতে পারে, সেই কার্যকারিতা বাস্তবায়নে আপনার সময় এবং প্রচেষ্টা বাঁচাতে পারে।

এই তৈরি করা কোডটি সার্ভার এবং ক্লায়েন্টের মধ্যে যোগাযোগের জটিলতাই নয়, ডেটা সিরিয়ালাইজেশন এবং ডিসিরিয়ালাইজেশনেরও যত্ন নেয়।

আপনি কি শিখবেন

  • একটি পরিষেবা API সংজ্ঞায়িত করতে প্রোটোকল বাফারগুলি কীভাবে ব্যবহার করবেন।
  • স্বয়ংক্রিয় কোড জেনারেশন ব্যবহার করে প্রোটোকল বাফার সংজ্ঞা থেকে কীভাবে একটি জিআরপিসি-ভিত্তিক ক্লায়েন্ট এবং সার্ভার তৈরি করবেন।
  • gRPC এর সাথে ক্লায়েন্ট-সার্ভার যোগাযোগের একটি বোঝাপড়া।

এই কোডল্যাবটি জিআরপিসি-তে নতুন জাভা ডেভেলপারদের জন্য বা জিআরপিসি-র রিফ্রেশার খোঁজার জন্য, বা বিতরণ করা সিস্টেম তৈরি করতে আগ্রহী অন্য যেকেউ লক্ষ্য করে। কোন পূর্ব gRPC অভিজ্ঞতা প্রয়োজন নেই.

2. আপনি শুরু করার আগে

পূর্বশর্ত

  • JDK সংস্করণ 8 বা উচ্চতর

কোড পান

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

প্রথমে, কোডল্যাব ওয়ার্কিং ডিরেক্টরি তৈরি করুন এবং এটিতে সিডি করুন:

mkdir grpc-java-getting-started && cd grpc-java-getting-started

কোডল্যাব ডাউনলোড এবং এক্সট্রাক্ট করুন:

curl -sL https://github.com/grpc-ecosystem/grpc-codelabs/archive/refs/heads/v1.tar.gz \
  | tar xvz --strip-components=4 \
  grpc-codelabs-1/codelabs/grpc-java-getting-started/start_here

বিকল্পভাবে, আপনি শুধুমাত্র কোডল্যাব ডিরেক্টরি ধারণকারী .zip ফাইলটি ডাউনলোড করতে পারেন এবং ম্যানুয়ালি আনজিপ করতে পারেন।

আপনি যদি বাস্তবায়নে টাইপ করা এড়িয়ে যেতে চান তবে সম্পূর্ণ সোর্স কোডটি GitHub-এ উপলব্ধ

3. পরিষেবাটি সংজ্ঞায়িত করুন

আপনার প্রথম ধাপ হল প্রোটোকল বাফার ব্যবহার করে অ্যাপ্লিকেশনটির gRPC পরিষেবা, এর RPC পদ্ধতি এবং এর অনুরোধ এবং প্রতিক্রিয়া বার্তার ধরনগুলিকে সংজ্ঞায়িত করা। আপনার পরিষেবা প্রদান করবে:

  • GetFeature নামে একটি RPC পদ্ধতি যা সার্ভার প্রয়োগ করে এবং ক্লায়েন্ট কল করে।
  • GetFeature পদ্ধতি ব্যবহার করার সময় ক্লায়েন্ট এবং সার্ভারের মধ্যে আদান-প্রদান করা ডেটা স্ট্রাকচার Point এবং Feature ধরন। ক্লায়েন্ট সার্ভারে তার GetFeature অনুরোধে একটি Point হিসাবে মানচিত্র স্থানাঙ্ক সরবরাহ করে এবং সার্ভার একটি সংশ্লিষ্ট Feature সাথে উত্তর দেয় যা সেই স্থানাঙ্কগুলিতে যা আছে তা বর্ণনা করে।

এই RPC পদ্ধতি এবং এর বার্তার ধরনগুলি প্রদত্ত সোর্স কোডের src/main/proto/routeguide/route_guide.proto ফাইলে সংজ্ঞায়িত করা হবে।

প্রোটোকল বাফারগুলি সাধারণত প্রোটোবাফ হিসাবে পরিচিত। gRPC পরিভাষা সম্পর্কে আরও তথ্যের জন্য, gRPC-এর মূল ধারণা, স্থাপত্য, এবং জীবনচক্র দেখুন।

যেহেতু আমরা এই উদাহরণে জাভা কোড তৈরি করছি, আমরা একটি java_package ফাইল বিকল্প এবং আমাদের .proto এ Java ক্লাসের জন্য একটি নাম উল্লেখ করেছি।

option java_package = "io.grpc.examples.routeguide";
option java_outer_classname = "RouteGuideProto";

বার্তার ধরন

সোর্স কোডের routeguide/route_guide.proto ফাইলে, প্রথমে Point বার্তার ধরনটি সংজ্ঞায়িত করুন। একটি Point একটি মানচিত্রে একটি অক্ষাংশ-দ্রাঘিমাংশ স্থানাঙ্ক জুটিকে প্রতিনিধিত্ব করে। এই কোডল্যাবের জন্য, স্থানাঙ্কের জন্য পূর্ণসংখ্যা ব্যবহার করুন:

message Point {
  int32 latitude = 1;
  int32 longitude = 2;
}

1 এবং 2 নম্বরগুলি message কাঠামোর প্রতিটি ক্ষেত্রের জন্য অনন্য আইডি নম্বর।

এর পরে, Feature বার্তার ধরন সংজ্ঞায়িত করুন। একটি Feature একটি Point দ্বারা নির্দিষ্ট একটি অবস্থানে কোনো কিছুর নাম বা ডাক ঠিকানার জন্য একটি string ক্ষেত্র ব্যবহার করে:

message Feature {
  // The name or address of the feature.
  string name = 1;

  // The point where the feature is located.
  Point location = 2;
}

পরিষেবা পদ্ধতি

route_guide.proto ফাইলটিতে RouteGuide নামে একটি service কাঠামো রয়েছে যা অ্যাপ্লিকেশনটির পরিষেবা দ্বারা প্রদত্ত এক বা একাধিক পদ্ধতিকে সংজ্ঞায়িত করে৷

RouteGuide সংজ্ঞার ভিতরে rpc পদ্ধতি GetFeature যোগ করুন। যেমনটি আগে ব্যাখ্যা করা হয়েছে, এই পদ্ধতিটি স্থানাঙ্কের একটি নির্দিষ্ট সেট থেকে একটি অবস্থানের নাম বা ঠিকানা সন্ধান করবে, তাই GetFeature একটি নির্দিষ্ট Point জন্য একটি Feature ফিরিয়ে দিতে হবে:

service RouteGuide {
  // Definition of the service goes here

  // Obtains the feature at a given position.
  rpc GetFeature(Point) returns (Feature) {}
}

এটি একটি unary RPC পদ্ধতি: একটি সাধারণ RPC যেখানে ক্লায়েন্ট সার্ভারে একটি অনুরোধ পাঠায় এবং একটি স্থানীয় ফাংশন কলের মতোই একটি প্রতিক্রিয়া ফিরে আসার জন্য অপেক্ষা করে।

4. ক্লায়েন্ট এবং সার্ভার কোড তৈরি করুন

পরবর্তীতে আমাদের .proto পরিষেবা সংজ্ঞা থেকে gRPC ক্লায়েন্ট এবং সার্ভার ইন্টারফেস তৈরি করতে হবে। আমরা একটি বিশেষ gRPC Java প্লাগইন সহ প্রোটোকল বাফার কম্পাইলার protoc ব্যবহার করে এটি করি। gRPC পরিষেবাগুলি তৈরি করার জন্য আপনাকে proto3 কম্পাইলার (যা proto2 এবং proto3 উভয় সিনট্যাক্স সমর্থন করে) ব্যবহার করতে হবে।

Gradle বা Maven ব্যবহার করার সময়, protoc বিল্ড প্লাগইন বিল্ডের অংশ হিসাবে প্রয়োজনীয় কোড তৈরি করতে পারে। কিভাবে আপনার নিজের .proto ফাইল থেকে কোড জেনারেট করতে হয় তার জন্য আপনি grpc-java README দেখতে পারেন।

আমরা এই প্রকল্পটি তৈরি করতে কোডল্যাবের সোর্স কোডে একটি গ্রেডল পরিবেশ এবং কনফিগারেশন প্রদান করেছি।

grpc-java-getting-started ডিরেক্টরির ভিতরে, নিম্নলিখিত কমান্ডটি চালান:

$ chmod +x gradlew
$ ./gradlew generateProto

নিম্নলিখিত ক্লাসগুলি আমাদের পরিষেবা সংজ্ঞা থেকে তৈরি করা হয়েছে:

  • Feature.java , Point.java , এবং অন্যান্য যেগুলিতে আমাদের অনুরোধ এবং প্রতিক্রিয়া বার্তা প্রকারগুলিকে পপুলেট, সিরিয়ালাইজ এবং পুনরুদ্ধার করার জন্য সমস্ত প্রোটোকল বাফার কোড রয়েছে৷
  • RouteGuideGrpc.java যার মধ্যে রয়েছে (অন্যান্য কিছু দরকারী কোড সহ) RouteGuide সার্ভারগুলিকে বাস্তবায়নের জন্য একটি বেস ক্লাস, RouteGuideGrpc.RouteGuideImplBase , RouteGuide পরিষেবাতে সংজ্ঞায়িত সমস্ত পদ্ধতি এবং ক্লায়েন্টদের ব্যবহার করার জন্য স্টাব ক্লাস।

5. সার্ভার বাস্তবায়ন

প্রথমে দেখা যাক কিভাবে আমরা একটি RouteGuide সার্ভার তৈরি করি। আমাদের RouteGuide পরিষেবাটি তার কাজ করার জন্য দুটি অংশ রয়েছে:

  • আমাদের পরিষেবার সংজ্ঞা থেকে উত্পন্ন পরিষেবা ইন্টারফেস বাস্তবায়ন করা, যা আমাদের পরিষেবার প্রকৃত "কাজ" করে।
  • ক্লায়েন্টদের কাছ থেকে অনুরোধ শোনার জন্য এবং সঠিক পরিষেবা বাস্তবায়নে তাদের পাঠানোর জন্য একটি gRPC সার্ভার চালানো।

RouteGuide বাস্তবায়ন করুন

আপনি দেখতে পাচ্ছেন, আমাদের সার্ভারে একটি RouteGuideService ক্লাস রয়েছে যা জেনারেট করা RouteGuideGrpc.RouteGuideImplBase বিমূর্ত ক্লাসকে প্রসারিত করে:

private static class RouteGuideService extends RouteGuideGrpc.RouteGuideImplBase {
...
}

বৈশিষ্ট্য সহ আপনার সার্ভার শুরু করার জন্য আমরা নিম্নলিখিত 2টি ফাইল সরবরাহ করেছি:

./src/main/java/io/grpc/examples/routeguide/RouteGuideUtil.java

./src/main/resources/io/grpc/examples/routeguide/route_guide_db.json

আসুন বিস্তারিতভাবে একটি সহজ RPC বাস্তবায়নের দিকে তাকাই।

ইউনারি আরপিসি

RouteGuideService আমাদের সমস্ত পরিষেবা পদ্ধতি প্রয়োগ করে। এই ক্ষেত্রে এটি শুধুমাত্র GetFeature() , ক্লায়েন্টের কাছ থেকে একটি Point বার্তা নেয় এবং একটি Feature বার্তায় পরিচিত স্থানগুলির একটি তালিকা থেকে সংশ্লিষ্ট অবস্থানের তথ্য ফেরত দেয়৷

@Override
public void getFeature(Point request, StreamObserver<Feature> responseObserver) {
  responseObserver.onNext(checkFeature(request));
  responseObserver.onCompleted();
}

getFeature() পদ্ধতিতে দুটি প্যারামিটার লাগে:

  • Point : অনুরোধ।
  • StreamObserver<Feature> : একটি প্রতিক্রিয়া পর্যবেক্ষক, যা সার্ভারের প্রতিক্রিয়া সহ কল ​​করার জন্য একটি বিশেষ ইন্টারফেস।

ক্লায়েন্টকে আমাদের প্রতিক্রিয়া ফেরত দিতে এবং কলটি সম্পূর্ণ করতে:

  1. আমরা ক্লায়েন্টে ফিরে যাওয়ার জন্য একটি Feature প্রতিক্রিয়া অবজেক্ট তৈরি এবং পপুলেট করি, যেমন আমাদের পরিষেবার সংজ্ঞায় উল্লেখ করা হয়েছে। এই উদাহরণে, আমরা এটি একটি পৃথক ব্যক্তিগত checkFeature() পদ্ধতিতে করি।
  2. আমরা Feature ফেরত দিতে প্রতিক্রিয়া পর্যবেক্ষকের onNext() পদ্ধতি ব্যবহার করি।
  3. আমরা RPC এর সাথে কাজ শেষ করেছি তা নির্দিষ্ট করতে আমরা প্রতিক্রিয়া পর্যবেক্ষকের onCompleted() পদ্ধতি ব্যবহার করি।

সার্ভার শুরু করুন

একবার আমরা আমাদের সমস্ত পরিষেবা পদ্ধতি প্রয়োগ করার পরে, আমাদের একটি gRPC সার্ভার শুরু করতে হবে যাতে ক্লায়েন্টরা আসলে আমাদের পরিষেবা ব্যবহার করতে পারে। আমরা আমাদের বয়লারপ্লেটে সার্ভারবিল্ডার অবজেক্টের সৃষ্টি অন্তর্ভুক্ত করি:

ServerBuilder.forPort(port), port, RouteGuideUtil.parseFeatures(featureFile)

আমরা কনস্ট্রাক্টরে পরিষেবাটি তৈরি করি:

  1. নির্মাতার forPort() পদ্ধতি ব্যবহার করে ক্লায়েন্টের অনুরোধ শোনার জন্য আমরা যে পোর্টটি ব্যবহার করতে চাই তা নির্দিষ্ট করুন (এটি ওয়াইল্ডকার্ড ঠিকানা ব্যবহার করবে)।
  2. আমাদের পরিষেবা বাস্তবায়ন ক্লাস RouteGuideService এর একটি উদাহরণ তৈরি করুন এবং এটি নির্মাতার addService() পদ্ধতিতে পাস করুন।
  3. আমাদের পরিষেবার জন্য একটি RPC সার্ভার তৈরি করতে নির্মাতাকে build() কল করুন।

নিম্নলিখিত স্নিপেট দেখায় কিভাবে আমরা একটি ServerBuilder অবজেক্ট তৈরি করি।

/** Create a RouteGuide server listening on {@code port} using {@code featureFile} database. */
public RouteGuideServer(int port, URL featureFile) throws IOException {
    this(Grpc.newServerBuilderForPort(port, InsecureServerCredentials.create()),
        port, RouteGuideUtil.parseFeatures(featureFile));
  }

নিম্নলিখিত স্নিপেট দেখায় কিভাবে আমরা আমাদের RouteGuide পরিষেবার জন্য একটি সার্ভার অবজেক্ট তৈরি করি।

/** Create a RouteGuide server using serverBuilder as a base and features as data. */
public RouteGuideServer(ServerBuilder<?> serverBuilder, int port, Collection<Feature> features) {
  this.port = port;
  server = serverBuilder.addService(new RouteGuideService(features))
      .build();
}

একটি স্টার্ট পদ্ধতি প্রয়োগ করুন যা আমরা উপরে তৈরি করা সার্ভারে কল start

public void start() throws IOException {
  server.start();
  logger.info("Server started, listening on " + port);
}

সার্ভার সম্পূর্ণ হওয়ার জন্য অপেক্ষা করার জন্য একটি পদ্ধতি প্রয়োগ করুন যাতে এটি অবিলম্বে প্রস্থান না করে।

/** Await termination on the main thread since the grpc library uses daemon threads. */
private void blockUntilShutdown() throws InterruptedException {
  if (server != null) {
    server.awaitTermination();
  }
}

আপনি দেখতে পাচ্ছেন, আমরা একটি ServerBuilder ব্যবহার করে আমাদের সার্ভার তৈরি এবং শুরু করি।

প্রধান পদ্ধতিতে আমরা:

  1. একটি RouteGuideServer উদাহরণ তৈরি করুন।
  2. আমাদের পরিষেবার জন্য একটি RPC সার্ভার সক্রিয় করতে start() কল করুন।
  3. blockUntilShutdown() কল করে পরিষেবাটি বন্ধ হওয়ার জন্য অপেক্ষা করুন।
 public static void main(String[] args) throws Exception {
    RouteGuideServer server = new RouteGuideServer(8980);
    server.start();
    server.blockUntilShutdown();
  }

6. ক্লায়েন্ট তৈরি করুন

এই বিভাগে, আমরা আমাদের RouteGuide পরিষেবার জন্য একটি ক্লায়েন্ট তৈরি করার বিষয়ে দেখব।

একটি স্টাব তাত্ক্ষণিক

পরিষেবা পদ্ধতি কল করার জন্য, আমাদের প্রথমে একটি স্টাব তৈরি করতে হবে। দুই ধরনের স্টাব আছে, কিন্তু আমাদের শুধুমাত্র এই কোডল্যাবের জন্য ব্লকিং ব্যবহার করতে হবে। দুই প্রকার হল:

  • একটি ব্লকিং/সিঙ্ক্রোনাস স্টাব যা একটি RPC কল করে এবং সার্ভারের সাড়া দেওয়ার জন্য অপেক্ষা করে এবং হয় একটি প্রতিক্রিয়া প্রদান করবে বা একটি ব্যতিক্রম উত্থাপন করবে।
  • একটি নন-ব্লকিং/অসিঙ্ক্রোনাস স্টাব যা সার্ভারে নন-ব্লকিং কল করে, যেখানে প্রতিক্রিয়া অ্যাসিঙ্ক্রোনাসভাবে ফেরত দেওয়া হয়। আপনি শুধুমাত্র অ্যাসিঙ্ক্রোনাস স্টাব ব্যবহার করে নির্দিষ্ট ধরনের স্ট্রিমিং কল করতে পারেন।

প্রথমে আমাদের একটি gRPC চ্যানেল তৈরি করতে হবে এবং তারপর আমাদের স্টাব তৈরি করতে চ্যানেলটি ব্যবহার করতে হবে।

চ্যানেল তৈরি করতে আমরা সরাসরি একটি ManagedChannelBuilder ব্যবহার করতে পারতাম।

ManagedChannelBuilder.forAddress(host, port).usePlaintext().build

তবে আসুন একটি ইউটিলিটি পদ্ধতি ব্যবহার করি যা hostname:port সাথে একটি স্ট্রিং নেয়।

Grpc.newChannelBuilder(target, InsecureChannelCredentials.create()).build();

এখন আমরা আমাদের ব্লকিং স্টাব তৈরি করতে চ্যানেলটি ব্যবহার করতে পারি। এই কোডল্যাবের জন্য, আমাদের কাছে শুধুমাত্র ব্লকিং RPC আছে, তাই আমরা আমাদের .proto থেকে তৈরি করা RouteGuideGrpc ক্লাসে দেওয়া newBlockingStub পদ্ধতি ব্যবহার করি।

blockingStub = RouteGuideGrpc.newBlockingStub(channel);

কল পরিষেবা পদ্ধতি

এখন আসুন আমরা আমাদের পরিষেবা পদ্ধতিগুলিকে কীভাবে বলি তা দেখি।

সরল আরপিসি

সাধারণ RPC GetFeature কল করা স্থানীয় পদ্ধতিতে কল করার মতোই সহজ।

আমরা একটি অনুরোধ প্রোটোকল বাফার অবজেক্ট তৈরি এবং পপুলেট করি (আমাদের ক্ষেত্রে Point ), এটিকে আমাদের ব্লকিং স্টাবের getFeature() পদ্ধতিতে পাস করি এবং একটি Feature ফিরে পাই।

যদি একটি ত্রুটি ঘটে, এটি একটি Status হিসাবে এনকোড করা হয়, যা আমরা StatusRuntimeException থেকে পেতে পারি।

Point request = Point.newBuilder().setLatitude(lat).setLongitude(lon).build();

Feature feature;
try {
  feature = blockingStub.getFeature(request);
} catch (StatusRuntimeException e) {
  logger.log(Level.WARNING, "RPC failed: {0}", e.getStatus());
  return;
}

বয়লারপ্লেট নির্দিষ্ট পয়েন্টে একটি বৈশিষ্ট্য ছিল কি না তার উপর ভিত্তি করে বিষয়বস্তু সম্বলিত একটি বার্তা লগ করে।

7. এটা চেষ্টা করে দেখুন!

  1. start_here ডিরেক্টরির ভিতরে, নিম্নলিখিত কমান্ডটি চালান:
$ ./gradlew installDist

এটি আপনার কোড কম্পাইল করবে, এটি একটি জারে প্যাকেজ করবে এবং স্ক্রিপ্টগুলি তৈরি করবে যা উদাহরণটি চালায়। এগুলি build/install/start_here/bin/ ডিরেক্টরিতে তৈরি করা হবে। স্ক্রিপ্টগুলি হল: route-guide-server এবং route-guide-client

ক্লায়েন্ট শুরু করার আগে সার্ভারটি চলতে হবে।

  1. সার্ভার চালান:
$ ./build/install/start_here/bin/route-guide-server
  1. ক্লায়েন্ট চালান:
$ ./build/install/start_here/bin/route-guide-client

স্পষ্টতার জন্য টাইমস্ট্যাম্প বাদ দিয়ে আপনি এইরকম আউটপুট দেখতে পাবেন:

INFO: *** GetFeature: lat=409,146,138 lon=-746,188,906
INFO: Found feature called "Berkshire Valley Management Area Trail, Jefferson, NJ, USA" at 40.915, -74.619
INFO: *** GetFeature: lat=0 lon=0
INFO: Found no feature at 0, 0

8. পরবর্তী কি