১. ভূমিকা
এই কোডল্যাবে, আপনি gRPC-Go ব্যবহার করে একটি ক্লায়েন্ট ও সার্ভার তৈরি করবেন, যা Go-তে লেখা একটি রাউট-ম্যাপিং অ্যাপ্লিকেশনের ভিত্তি তৈরি করবে।
এই টিউটোরিয়ালটি শেষ করার পর, আপনি এমন একটি ক্লায়েন্ট তৈরি করতে পারবেন যা gRPC ব্যবহার করে একটি রিমোট সার্ভারের সাথে সংযোগ স্থাপন করে মানচিত্রের নির্দিষ্ট স্থানাঙ্কে অবস্থিত কোনো কিছুর নাম বা ডাক ঠিকানা সংগ্রহ করতে পারবে। একটি পূর্ণাঙ্গ অ্যাপ্লিকেশন কোনো পথের গুরুত্বপূর্ণ স্থানগুলোর তালিকা তৈরি বা সারসংক্ষেপ করার জন্য এই ক্লায়েন্ট-সার্ভার ডিজাইনটি ব্যবহার করতে পারে।
সার্ভিসটি একটি প্রোটোকল বাফারস ফাইলে সংজ্ঞায়িত করা আছে, যা ক্লায়েন্ট এবং সার্ভারের জন্য বয়লারপ্লেট কোড তৈরি করতে ব্যবহৃত হবে, যাতে তারা একে অপরের সাথে যোগাযোগ করতে পারে। এর ফলে ঐ কার্যকারিতাটি বাস্তবায়নে আপনার সময় ও শ্রম বাঁচবে।
এই জেনারেট করা কোডটি শুধু সার্ভার ও ক্লায়েন্টের মধ্যকার যোগাযোগের জটিলতাই নয়, ডেটার সিরিয়ালাইজেশন এবং ডিসিরিয়ালাইজেশনও সামলে নেয়।
আপনি যা শিখবেন
- সার্ভিস এপিআই সংজ্ঞায়িত করতে প্রোটোকল বাফার কীভাবে ব্যবহার করবেন
- স্বয়ংক্রিয় কোড জেনারেশন ব্যবহার করে প্রোটোকল বাফারস ডেফিনিশন থেকে কীভাবে একটি gRPC-ভিত্তিক ক্লায়েন্ট এবং সার্ভার তৈরি করা যায়।
- gRPC ব্যবহার করে ক্লায়েন্ট-সার্ভার যোগাযোগ সম্পর্কে ধারণা।
এই কোডল্যাবটি সেইসব Go ডেভেলপারদের জন্য তৈরি করা হয়েছে যারা gRPC-তে নতুন অথবা এর বিষয়ে নিজেদের জ্ঞান ঝালিয়ে নিতে চান, কিংবা যারা ডিস্ট্রিবিউটেড সিস্টেম তৈরিতে আগ্রহী। gRPC-তে পূর্ব অভিজ্ঞতার কোনো প্রয়োজন নেই।
২. শুরু করার আগে
পূর্বশর্ত
নিশ্চিত করুন যে আপনি নিম্নলিখিতগুলি ইনস্টল করেছেন:
- গো টুলচেইন সংস্করণ ১.২৪.৫ বা তার পরবর্তী সংস্করণ। ইনস্টলেশন নির্দেশাবলীর জন্য, গো-এর 'গেটিং স্টার্টেড' দেখুন।
- প্রোটোকল বাফার কম্পাইলার,
protoc, সংস্করণ ৩.২৭.১ বা তার পরবর্তী সংস্করণ। ইনস্টলেশন নির্দেশাবলীর জন্য, কম্পাইলারের ইনস্টলেশন গাইড দেখুন। - 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"
কোডটি নিন
যাতে আপনাকে একেবারে গোড়া থেকে শুরু করতে না হয়, সেজন্য এই কোডল্যাবটি অ্যাপ্লিকেশনটির সোর্স কোডের একটি কাঠামো প্রদান করে, যা আপনাকে সম্পূর্ণ করতে হবে। নিম্নলিখিত ধাপগুলো আপনাকে দেখাবে কীভাবে অ্যাপ্লিকেশনটি শেষ করতে হয়, যার মধ্যে প্রোটোকল বাফার কম্পাইলার প্লাগইন ব্যবহার করে বয়লারপ্লেট gRPC কোড তৈরি করার পদ্ধতিও অন্তর্ভুক্ত রয়েছে।
গিটহাব থেকে এই সোর্স কোডটি একটি .ZIP আর্কাইভ হিসেবে ডাউনলোড করুন এবং এর ভেতরের ফাইলগুলো আনপ্যাক করুন।
বিকল্পভাবে, আপনি যদি ইমপ্লিমেন্টেশন টাইপ করার ঝামেলা এড়াতে চান, তাহলে সম্পূর্ণ সোর্স কোডটি গিটহাবে পাওয়া যাবে ।
৩. পরিষেবাটি সংজ্ঞায়িত করুন
আপনার প্রথম পদক্ষেপ হলো প্রোটোকল বাফার ব্যবহার করে অ্যাপ্লিকেশনটির 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 ডেফিনিশনের ভিতরে GetFeature rpc মেথডটি যোগ করুন। আগেই যেমন ব্যাখ্যা করা হয়েছে, এই মেথডটি প্রদত্ত স্থানাঙ্কের সেট থেকে কোনো অবস্থানের নাম বা ঠিকানা খুঁজে বের করবে, তাই GetFeature এমনভাবে তৈরি করুন যেন এটি প্রদত্ত Point জন্য একটি Feature রিটার্ন করে।
service RouteGuide {
// Definition of the service goes here
// Obtains the feature at a given position.
rpc GetFeature(Point) returns (Feature) {}
}
এটি একটি ইউনারি আরপিসি মেথড: এটি একটি সাধারণ আরপিসি যেখানে ক্লায়েন্ট সার্ভারে একটি অনুরোধ পাঠায় এবং একটি লোকাল ফাংশন কলের মতোই প্রতিক্রিয়া ফিরে আসার জন্য অপেক্ষা করে।
৪. ক্লায়েন্ট এবং সার্ভার কোড তৈরি করুন
এরপরে, প্রোটোকল বাফার কম্পাইলার ব্যবহার করে .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 মেথডটি ইমপ্লিমেন্ট করব, যাতে ক্লায়েন্ট যখন কোনো রিকোয়েস্ট পাঠাবে, সার্ভার তখন তার উত্তর দিতে পারে।
৫. পরিষেবাটি বাস্তবায়ন করুন
সার্ভার সাইডের 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 error-সহ return । এর মাধ্যমে gRPC-কে জানানো হয় যে আপনার RPC-এর কাজ শেষ হয়েছে এবং 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() ফাংশনে যা ঘটছে, তা ধাপে ধাপে নিচে দেওয়া হলো:
- রিমোট ক্লায়েন্টের অনুরোধ শোনার জন্য ব্যবহৃত TCP পোর্টটি
lis, err := net.Listen(...)ব্যবহার করে নির্দিষ্ট করুন। ডিফল্টরূপে, অ্যাপ্লিকেশনটি TCP পোর্ট50051ব্যবহার করে, যাportভেরিয়েবলের মাধ্যমে অথবা সার্ভার চালানোর সময় কমান্ড লাইনে--portসুইচটি পাস করে নির্দিষ্ট করা হয়। যদি TCP পোর্টটি খোলা না যায়, তাহলে অ্যাপ্লিকেশনটি একটি মারাত্মক ত্রুটির (fatal error) মাধ্যমে বন্ধ হয়ে যায়। -
grpc.NewServer(...)ব্যবহার করে gRPC সার্ভারের একটি ইনস্ট্যান্স তৈরি করুন এবং এই ইনস্ট্যান্সটির নাম দিনgrpcServer। - অ্যাপ্লিকেশনটির এপিআই পরিষেবা প্রতিনিধিত্বকারী স্ট্রাকচার `
routeGuideServerএর একটি পয়েন্টার তৈরি করুন এবং পয়েন্টারটির নামs. -
GetFeatureমাধ্যমে খুঁজে বের করা যায় এমন লোকেশনগুলো দিয়েs.savedFeaturesঅ্যারেটি পূরণ করতেs.loadFeatures()ব্যবহার করুন। - gRPC সার্ভারে API পরিষেবাটি নিবন্ধন করুন, যাতে
GetFeatureএ করা RPC কলগুলি উপযুক্ত ফাংশনে পাঠানো হয়। - ক্লায়েন্টের অনুরোধের জন্য ব্লকিং অপেক্ষা করতে আমাদের পোর্ট বিবরণ সহ সার্ভারে
Serve()কল করুন; এটি ততক্ষণ চলতে থাকে যতক্ষণ না প্রসেসটি কিল করা হয় বাStop()কল করা হয়।
loadFeatures() ফাংশনটি তার স্থানাঙ্ক-থেকে-অবস্থান ম্যাপিং server/testdata.go থেকে গ্রহণ করে।
৬. ক্লায়েন্ট তৈরি করুন
এখন client/client.go সম্পাদনা করুন, যেখানে আপনি ক্লায়েন্ট কোড লিখবেন।
রিমোট সার্ভিসের মেথডগুলো কল করার জন্য, আমাদের প্রথমে সার্ভারের সাথে যোগাযোগের জন্য একটি gRPC চ্যানেল তৈরি করতে হবে। grpc.NewClient() ফাংশনে সার্ভারের টার্গেট URI স্ট্রিং (যা এই ক্ষেত্রে কেবল অ্যাড্রেস এবং পোর্ট নম্বর) পাস করার মাধ্যমে আমরা এটি main() করি, যেমনটা নিচে দেখানো হলো:
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 ক্রেডেনশিয়ালের মতো অথেনটিকেশন ক্রেডেনশিয়াল প্রয়োজন, তবে ক্লায়েন্ট grpc.NewClient এ প্যারামিটার হিসেবে একটি DialOptions অবজেক্ট পাস করতে পারে, যেটিতে প্রয়োজনীয় ক্রেডেনশিয়ালগুলো থাকে। 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)
}
৭. এটি পরীক্ষা করে দেখুন
অ্যাপ্লিকেশনটির ওয়ার্কিং ডিরেক্টরিতে নিম্নলিখিত কমান্ডগুলো চালিয়ে সার্ভার এবং ক্লায়েন্ট একে অপরের সাথে সঠিকভাবে কাজ করছে কিনা তা নিশ্চিত করুন:
- একটি টার্মিনালে সার্ভারটি চালান:
cd server go run .
- অন্য একটি টার্মিনাল থেকে ক্লায়েন্টটি চালান:
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:<>
৮. এরপর কী?
- gRPC-এর পরিচিতি এবং মূল ধারণা অংশে gRPC কীভাবে কাজ করে তা জানুন।
- বেসিক টিউটোরিয়ালটি অনুসরণ করুন
- এপিআই রেফারেন্স অন্বেষণ করুন