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

1. ভূমিকা

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

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

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

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

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

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

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

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

পূর্বশর্ত

নিশ্চিত করুন যে আপনি নিম্নলিখিত ইনস্টল করেছেন:

  • Go টুলচেন সংস্করণ 1.24.5 বা তার পরে। ইনস্টলেশন নির্দেশাবলীর জন্য, Go's Getting start দেখুন।
  • প্রোটোকল বাফার কম্পাইলার, protoc , ভার্সন 3.27.1 বা তার পরের। ইনস্টলেশন নির্দেশাবলীর জন্য, কম্পাইলারের ইনস্টলেশন গাইড দেখুন।
  • Go এবং gRPC-এর জন্য প্রোটোকল বাফার কম্পাইলার প্লাগইন। এই প্লাগইনগুলি ইনস্টল করতে, নিম্নলিখিত কমান্ডগুলি চালান:
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest

আপনার PATH ভেরিয়েবল আপডেট করুন যাতে প্রোটোকল বাফার কম্পাইলার প্লাগইনগুলি খুঁজে পেতে পারে:

export PATH="$PATH:$(go env GOPATH)/bin"

কোড পান

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

GitHub থেকে একটি .ZIP সংরক্ষণাগার হিসাবে এই উত্স কোডটি ডাউনলোড করুন এবং এর বিষয়বস্তু আনপ্যাক করুন৷

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

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

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

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

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

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

বার্তার ধরন

সোর্স কোডের 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 কোড তৈরি করুন। routeguide ডিরেক্টরিতে, চালান:

protoc --go_out=. --go_opt=paths=source_relative \
       --go-grpc_out=. --go-grpc_opt=paths=source_relative \
       route_guide.proto

এই কমান্ডটি নিম্নলিখিত ফাইলগুলি তৈরি করে:

  • route_guide.pb.go , যাতে অ্যাপ্লিকেশনের বার্তার ধরন তৈরি করা এবং তাদের ডেটা অ্যাক্সেস করার ফাংশন রয়েছে।
  • route_guide_grpc.pb.go , যেটিতে ক্লায়েন্ট পরিষেবার দূরবর্তী gRPC পদ্ধতিতে কল করতে ব্যবহার করে এবং সেই দূরবর্তী পরিষেবা প্রদানের জন্য সার্ভার দ্বারা ব্যবহৃত ফাংশনগুলি রয়েছে৷

এর পরে, আমরা সার্ভার-সাইডে GetFeature পদ্ধতি প্রয়োগ করব, যাতে ক্লায়েন্ট যখন একটি অনুরোধ পাঠায়, সার্ভার একটি উত্তর দিয়ে উত্তর দিতে পারে।

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

সার্ভারের দিকে GetFeature ফাংশনটি হল যেখানে প্রধান কাজ করা হয়: এটি ক্লায়েন্টের কাছ থেকে একটি Point বার্তা নেয় এবং পরিচিত স্থানগুলির একটি তালিকা থেকে একটি Feature বার্তায় সংশ্লিষ্ট অবস্থানের তথ্য ফেরত দেয়। এখানে server/server.go তে ফাংশনের বাস্তবায়ন রয়েছে:

func (s *routeGuideServer) GetFeature(ctx context.Context, point *pb.Point) (*pb.Feature, error) {
  for _, feature := range s.savedFeatures {
    if proto.Equal(feature.Location, point) {
      return feature, nil
    }
  }
  // No feature was found, return an unnamed feature
  return &pb.Feature{Location: point}, nil
}

যখন এই পদ্ধতিটি একটি দূরবর্তী ক্লায়েন্ট থেকে একটি অনুরোধের পরে চালু করা হয়, তখন ফাংশনটি RPC কল বর্ণনাকারী একটি Context বস্তু এবং সেই ক্লায়েন্ট অনুরোধ থেকে একটি Point প্রোটোকল বাফার অবজেক্ট পাস করা হয়। ফাংশনটি লুক-আপ অবস্থানের জন্য একটি Feature প্রোটোকল বাফার অবজেক্ট এবং প্রয়োজনে একটি error প্রদান করে।

পদ্ধতিতে, প্রদত্ত Point জন্য উপযুক্ত তথ্য সহ একটি Feature অবজেক্ট তৈরি করুন, এবং তারপরে একটি nil ত্রুটি সহ এটিকে return যাতে আপনি আরপিসি-এর সাথে কাজ শেষ করেছেন এবং ক্লায়েন্টকে Feature অবজেক্টটি ফেরত দেওয়া যেতে পারে।

GetFeature পদ্ধতিতে একটি routeGuideServer অবজেক্ট তৈরি এবং নিবন্ধিত করা প্রয়োজন যাতে ক্লায়েন্টদের কাছ থেকে লোকেশন লুক-আপের অনুরোধগুলি সেই ফাংশনে রুট করা যায়। এটি main() এ করা হয়:

func main() {
  flag.Parse()
  lis, err := net.Listen("tcp", fmt.Sprintf("localhost:%d", *port))
  if err != nil {
    log.Fatalf("failed to listen: %v", err)
  }

  var opts []grpc.ServerOption
  grpcServer := grpc.NewServer(opts...)

  s := &routeGuideServer{}
  s.loadFeatures()
  pb.RegisterRouteGuideServer(grpcServer, s)
  grpcServer.Serve(lis)
}

এখানে main() তে কি ঘটছে, ধাপে ধাপে:

  1. lis, err := net.Listen(...) ব্যবহার করে দূরবর্তী ক্লায়েন্টের অনুরোধ শোনার জন্য ব্যবহার করার জন্য TCP পোর্ট নির্দিষ্ট করুন। ডিফল্টরূপে, অ্যাপ্লিকেশন টিসিপি পোর্ট 50051 ব্যবহার করে যা পরিবর্তনশীল port দ্বারা নির্দিষ্ট করা হয়েছে বা সার্ভার চালানোর সময় কমান্ড লাইনে --port সুইচ পাস করে। যদি TCP পোর্ট খোলা না যায়, তাহলে অ্যাপ্লিকেশনটি একটি মারাত্মক ত্রুটির সাথে শেষ হয়।
  2. grpc.NewServer(...) ব্যবহার করে gRPC সার্ভারের একটি উদাহরণ তৈরি করুন, এই উদাহরণটিকে grpcServer নামকরণ করুন।
  3. routeGuideServer এ একটি পয়েন্টার তৈরি করুন, একটি কাঠামো যা অ্যাপ্লিকেশনের API পরিষেবার প্রতিনিধিত্ব করে, পয়েন্টার s.
  4. s.loadFeatures() ব্যবহার করুন অ্যারে s.savedFeatures এমন লোকেশন সহ পপুলেট করতে যা GetFeature মাধ্যমে দেখা যেতে পারে।
  5. GRPC সার্ভারের সাথে API পরিষেবা নিবন্ধন করুন যাতে GetFeature এ RPC কলগুলি উপযুক্ত ফাংশনে রাউট করা হয়।
  6. ক্লায়েন্ট অনুরোধের জন্য একটি ব্লকিং অপেক্ষা করতে আমাদের পোর্টের বিবরণ সহ সার্ভারে কল করুন Serve() ; প্রক্রিয়াটি মারা না যাওয়া পর্যন্ত বা Stop() বলা না হওয়া পর্যন্ত এটি চলতে থাকে।

ফাংশন loadFeatures() server/testdata.go থেকে এর স্থানাঙ্ক-টু-অবস্থান ম্যাপিং পায়।

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

এখন client/client.go সম্পাদনা করুন, যেখানে আপনি ক্লায়েন্ট কোড প্রয়োগ করবেন।

দূরবর্তী পরিষেবার পদ্ধতিগুলিকে কল করার জন্য, আমাদের প্রথমে সার্ভারের সাথে যোগাযোগের জন্য একটি gRPC চ্যানেল তৈরি করতে হবে। আমরা সার্ভারের টার্গেট URI স্ট্রিং (যা এই ক্ষেত্রে সহজভাবে ঠিকানা এবং পোর্ট নম্বর) ক্লায়েন্টের main() ফাংশনে grpc.NewClient() এ পাস করে এটি তৈরি করি:

conn, err := grpc.NewClient("dns:///"+*serverAddr, grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
        log.Fatalf("fail to dial: %v", err)
}
defer conn.Close()

সার্ভারের ঠিকানা, পরিবর্তনশীল serverAddr দ্বারা সংজ্ঞায়িত, ডিফল্টভাবে localhost:50051 , এবং ক্লায়েন্ট চালানোর সময় কমান্ড লাইনে --addr সুইচ দ্বারা ওভাররাইড করা যেতে পারে।

যদি ক্লায়েন্টকে এমন একটি পরিষেবার সাথে সংযোগ করতে হয় যার জন্য TLS বা JWT শংসাপত্রের মতো প্রমাণীকরণের শংসাপত্রের প্রয়োজন হয়, তাহলে ক্লায়েন্ট একটি DialOptions অবজেক্টকে একটি প্যারামিটার হিসাবে grpc.NewClient এ পাঠাতে পারে যাতে প্রয়োজনীয় শংসাপত্র রয়েছে। RouteGuide পরিষেবার কোনো শংসাপত্রের প্রয়োজন নেই।

একবার gRPC চ্যানেল সেট আপ হয়ে গেলে, Go ফাংশন কলের মাধ্যমে RPCগুলি সম্পাদন করার জন্য আমাদের একটি ক্লায়েন্ট স্টাব প্রয়োজন। অ্যাপ্লিকেশনের .proto ফাইল থেকে জেনারেট করা route_guide_grpc.pb.go ফাইল দ্বারা প্রদত্ত NewRouteGuideClient পদ্ধতি ব্যবহার করে আমরা সেই স্টাবটি পাই।

import (pb "github.com/grpc-ecosystem/codelabs/getting_started_unary/routeguide")

client := pb.NewRouteGuideClient(conn)

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

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

সরল আরপিসি

সাধারণ RPC GetFeature কল করা স্থানীয় পদ্ধতিতে কল করার মতোই সহজ, এই ক্ষেত্রে client.GetFeature :

point := &pb.Point{Latitude: 409146138, Longitude: -746188906}
log.Printf("Getting feature for point (%d, %d)", point.Latitude, point.Longitude)

// Call GetFeature method on the client.
feature, err := client.GetFeature(context.TODO(), point)
if err != nil {
  log.Fatalf("client.GetFeature failed: %v", err)
}

ক্লায়েন্ট আগে তৈরি করা স্টাবের পদ্ধতিটিকে কল করে। পদ্ধতির পরামিতিগুলির জন্য, ক্লায়েন্ট একটি Point অনুরোধ প্রোটোকল বাফার অবজেক্ট তৈরি করে এবং পপুলেট করে। আপনি একটি context.Context অবজেক্টও পাস করেন যা প্রয়োজনে আমাদের RPC এর আচরণ পরিবর্তন করতে দেয়, যেমন কলের জন্য একটি সময়সীমা নির্ধারণ করা বা ফ্লাইটে একটি RPC বাতিল করা। যদি কলটি একটি ত্রুটি ফেরত না দেয়, ক্লায়েন্ট প্রথম রিটার্ন মান থেকে সার্ভার থেকে প্রতিক্রিয়া তথ্য পড়তে পারে:

log.Println(feature)

সব মিলিয়ে, ক্লায়েন্টের main() ফাংশনটি এইরকম হওয়া উচিত:

func main() {
        flag.Parse()

        // Set up a connection to the gRPC server.
        conn, err := grpc.NewClient("dns:///"+*serverAddr, grpc.WithTransportCredentials(insecure.NewCredentials()))
        if err != nil {
                log.Fatalf("fail to dial: %v", err)
        }
        defer conn.Close()

        // Create a new RouteGuide stub.
        client := pb.NewRouteGuideClient(conn)

        point := &pb.Point{Latitude: 409146138, Longitude: -746188906}
        log.Printf("Getting feature for point (%d, %d)", point.Latitude, point.Longitude)

        // Call GetFeature method on the client.
        feature, err := client.GetFeature(context.TODO(), point)
        if err != nil {
                log.Fatalf("client.GetFeature failed: %v", err)
        }
        log.Println(feature)
}

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

অ্যাপ্লিকেশনের কার্যকারী ডিরেক্টরিতে নিম্নলিখিত কমান্ডগুলি সম্পাদন করে সার্ভার এবং ক্লায়েন্ট একে অপরের সাথে সঠিকভাবে কাজ করছে তা নিশ্চিত করুন:

  1. একটি টার্মিনালে সার্ভার চালান:
cd server
go run .
  1. অন্য টার্মিনাল থেকে ক্লায়েন্ট চালান:
cd client
go run .

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

Getting feature for point (409146138, -746188906)
name:"Berkshire Valley Management Area Trail, Jefferson, NJ, USA" location:<latitude:409146138 longitude:-746188906 >
Getting feature for point (0, 0)
location:<>

8. পরবর্তী কি