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

1. ভূমিকা

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

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

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

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

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

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

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

২. শুরু করার আগে

আপনার যা যা লাগবে

  • পাইথন ৩.৯ বা তার উচ্চতর সংস্করণ। আমরা পাইথন ৩.১৩ ব্যবহারের পরামর্শ দিই। প্ল্যাটফর্ম-ভিত্তিক ইনস্টলেশন নির্দেশাবলীর জন্য, ‘পাইথন সেটআপ এবং ব্যবহার’ দেখুন। বিকল্পভাবে, uv বা pyenv-এর মতো টুল ব্যবহার করে একটি নন-সিস্টেম পাইথন ইনস্টল করুন।
  • পাইথন প্যাকেজ ইনস্টল করতে pip ব্যবহার করা হয়।
  • পাইথন ভার্চুয়াল এনভায়রনমেন্ট তৈরি করার জন্য venv ব্যবহৃত হয়।

ensurepip এবং venv প্যাকেজগুলো পাইথন স্ট্যান্ডার্ড লাইব্রেরির অংশ এবং সাধারণত ডিফল্টরূপে উপলব্ধ থাকে।

তবে, কিছু ডেবিয়ান-ভিত্তিক ডিস্ট্রিবিউশন (উবুন্টু সহ) পাইথন পুনঃবিতরণের সময় এগুলিকে বাদ দিয়ে থাকে। প্যাকেজগুলি ইনস্টল করতে, চালান:

sudo apt install python3-pip python3-venv

কোডটি নিন

আপনার শেখার প্রক্রিয়াকে সহজ করতে, এই কোডল্যাবটি আপনাকে কাজ শুরু করতে সাহায্য করার জন্য একটি পূর্ব-নির্মিত সোর্স কোড কাঠামো প্রদান করে। নিম্নলিখিত ধাপগুলো আপনাকে অ্যাপ্লিকেশনটি সম্পূর্ণ করতে পথ দেখাবে, যার মধ্যে grpc_tools.protoc প্রোটোকল বাফার কম্পাইলার প্লাগইন ব্যবহার করে gRPC কোড জেনারেশনও অন্তর্ভুক্ত।

grpc-codelabs

এই কোডল্যাবের স্কাফোল্ড সোর্স কোডটি `codelabs/grpc-python-getting-started/start_here` ডিরেক্টরিতে পাওয়া যাবে। আপনি যদি নিজে কোডটি ইমপ্লিমেন্ট করতে না চান, তবে সম্পূর্ণ সোর্স কোডটি ` completed ডিরেক্টরিতে পাওয়া যাবে।

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

mkdir grpc-python-getting-started && cd grpc-python-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-python-getting-started/start_here

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

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

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

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

এই RPC মেথড এবং এর মেসেজ টাইপগুলো প্রদত্ত সোর্স কোডের protos/route_guide.proto ফাইলে সংজ্ঞায়িত করা থাকবে।

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

বার্তার প্রকারভেদ

সোর্স কোডের protos/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 কোড তৈরি করুন।

gRPC পাইথন কোড তৈরির জন্য আমরা grpcio-tools তৈরি করেছি। এর মধ্যে রয়েছে:

  1. সাধারণ প্রোটোক কম্পাইলার যা message ডেফিনিশন থেকে পাইথন কোড তৈরি করে।
  2. gRPC প্রোটোবাফ প্লাগইন যা service ডেফিনিশনগুলো থেকে পাইথন কোড (ক্লায়েন্ট ও সার্ভার স্টাব) তৈরি করে।

আমরা pip ব্যবহার করে grpcio-tools পাইথন প্যাকেজটি ইনস্টল করব। আপনার প্রোজেক্টের ডিপেন্ডেন্সিগুলোকে সিস্টেম প্যাকেজ থেকে আলাদা রাখতে চলুন একটি নতুন পাইথন ভার্চুয়াল এনভায়রনমেন্ট (venv) তৈরি করি:

python3 -m venv --upgrade-deps .venv

bash/zsh শেলে ভার্চুয়াল এনভায়রনমেন্ট সক্রিয় করতে:

source .venv/bin/activate

উইন্ডোজ এবং অ-প্রমিত শেলগুলির জন্য, https://docs.python.org/3/library/venv.html#how-venvs-work -এ দেওয়া সারণিটি দেখুন।

এরপর, grpcio-tools ইনস্টল করুন (এর মাধ্যমে grpcio প্যাকেজটিও ইনস্টল হয়ে যাবে):

pip install grpcio-tools

পাইথন বয়লারপ্লেট কোড তৈরি করতে নিম্নলিখিত কমান্ডটি ব্যবহার করুন:

python -m grpc_tools.protoc --proto_path=./protos  \
 --python_out=. --pyi_out=. --grpc_python_out=. \
 ./protos/route_guide.proto

এটি route_guide.proto তে আমাদের সংজ্ঞায়িত ইন্টারফেসগুলির জন্য নিম্নলিখিত ফাইলগুলি তৈরি করবে:

  1. route_guide_pb2.py ফাইলে সেই কোড রয়েছে যা message ডেফিনিশন থেকে তৈরি ক্লাসগুলোকে ডাইনামিকভাবে তৈরি করে
  2. route_guide_pb2.pyi হলো message ডেফিনিশন থেকে তৈরি একটি 'স্টাব ফাইল' বা 'টাইপ হিন্ট ফাইল'। এতে কোনো ইমপ্লিমেন্টেশন ছাড়াই শুধুমাত্র সিগনেচারগুলো থাকে। IDE-গুলো উন্নততর অটোকমপ্লিশন এবং ত্রুটি শনাক্তকরণের জন্য স্টাব ফাইল ব্যবহার করতে পারে।
  3. route_guide_pb2_grpc.py service ডেফিনিশন থেকে তৈরি করা হয় এবং এতে gRPC-এর জন্য নির্দিষ্ট ক্লাস ও ফাংশন রয়েছে।

gRPC-নির্দিষ্ট কোডে রয়েছে:

  1. RouteGuideStub , যা একটি gRPC ক্লায়েন্ট RouteGuide RPC আহ্বান করার জন্য ব্যবহার করতে পারে।
  2. RouteGuideServicer , যা RouteGuide সার্ভিসের ইমপ্লিমেন্টেশনগুলোর জন্য ইন্টারফেস সংজ্ঞায়িত করে।
  3. add_RouteGuideServicer_to_server ফাংশনটি একটি RouteGuideServicer gRPC সার্ভারে রেজিস্টার করতে ব্যবহৃত হয়।

৫. পরিষেবাটি তৈরি করুন

প্রথমে দেখা যাক কিভাবে একটি RouteGuide সার্ভার তৈরি করতে হয়। একটি RouteGuide সার্ভার তৈরি এবং চালানোর কাজটি দুটি ভাগে বিভক্ত:

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

আপনি প্রাথমিক RouteGuide সার্ভারটি start_here/route_guide_server.py ফাইলে খুঁজে পাবেন।

রুটগাইড বাস্তবায়ন করুন

route_guide_server.py একটি RouteGuideServicer ক্লাস আছে যা জেনারেট করা ক্লাস route_guide_pb2_grpc.RouteGuideServicer সাবক্লাস:

# RouteGuideServicer provides an implementation
# of the methods of the RouteGuide service.
class RouteGuideServicer(route_guide_pb2_grpc.RouteGuideServicer):

RouteGuideServicer RouteGuide সার্ভিসের সমস্ত মেথড বাস্তবায়ন করে।

চলুন একটি সাধারণ RPC বাস্তবায়ন বিস্তারিতভাবে দেখি। GetFeature মেথডটি ক্লায়েন্টের কাছ থেকে একটি Point গ্রহণ করে এবং এর ডাটাবেস থেকে সংশ্লিষ্ট ফিচারের তথ্য Feature এ ফেরত দেয়।

def GetFeature(self, request, context):
    feature = get_feature(self.db, request)
    if feature is None:
        return route_guide_pb2.Feature(name="", location=request)
    else:
        return feature

এই মেথডটিতে RPC-এর জন্য একটি route_guide_pb2.Point রিকোয়েস্ট এবং একটি grpc.ServicerContext অবজেক্ট পাস করা হয়, যা টাইমআউট লিমিটের মতো RPC-নির্দিষ্ট তথ্য সরবরাহ করে। এটি একটি route_guide_pb2.Feature রেসপন্স রিটার্ন করে।

সার্ভার চালু করা হচ্ছে

একবার আপনি সমস্ত RouteGuide মেথড প্রয়োগ করে ফেললে, পরবর্তী ধাপ হলো একটি gRPC সার্ভার চালু করা, যাতে ক্লায়েন্টরা আপনার পরিষেবাটি ব্যবহার করতে পারে:

def serve():
    server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
    route_guide_pb2_grpc.add_RouteGuideServicer_to_server(
        RouteGuideServicer(),
        server,
    )
    listen_addr = "localhost:50051"
    server.add_insecure_port(listen_addr)
    print(f"Starting server on {listen_addr}")
    server.start()
    server.wait_for_termination()

`server start() ` মেথডটি নন-ব্লকিং। অনুরোধগুলো পরিচালনা করার জন্য একটি নতুন থ্রেড তৈরি করা হবে। যে থ্রেডটি server.start() কল করে, এই অন্তর্বর্তী সময়ে তার প্রায়শই অন্য কোনো কাজ থাকে না। এই ক্ষেত্রে, সার্ভারটি বন্ধ না হওয়া পর্যন্ত কলিং থ্রেডটিকে সুষ্ঠুভাবে ব্লক করার জন্য আপনি server.wait_for_termination() কল করতে পারেন।

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

এই অংশে, আমরা আমাদের RouteGuide সার্ভিসের জন্য একটি ক্লায়েন্ট তৈরি করা দেখব। প্রাথমিক ক্লায়েন্ট কোডটি আপনি start_here/route_guide_client.py ফাইলে দেখতে পারেন।

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

সার্ভিস মেথড কল করার জন্য, আমাদের প্রথমে একটি স্টাব তৈরি করতে হবে।

আমরা route_guide_client.py ফাইলের ভিতরে আমাদের .proto থেকে তৈরি route_guide_pb2_grpc মডিউলের RouteGuideStub ক্লাসটিকে ইনস্ট্যানশিয়েট করি।

channel = grpc.insecure_channel("localhost:50051")
stub = route_guide_pb2_grpc.RouteGuideStub(channel)

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

যেসব RPC মেথড একটিমাত্র রেসপন্স রিটার্ন করে—যা রেসপন্স-ইউনারি মেথড নামে পরিচিত—তাদের জন্য gRPC পাইথন সিনক্রোনাস (ব্লকিং) এবং অ্যাসিনক্রোনাস (নন-ব্লকিং) উভয় প্রকার কন্ট্রোল ফ্লো সেম্যান্টিকস সমর্থন করে।

সরল আরপিসি

প্রথমে, সার্ভিসটি কল করার জন্য একটি Point নির্ধারণ করা যাক। এটি route_guide_pb2 প্যাকেজ থেকে কিছু প্রোপার্টিসহ একটি অবজেক্ট ইনস্ট্যানশিয়েট করার মতোই সহজ হওয়া উচিত:

point = route_guide_pb2.Point(latitude=412346009, longitude=-744026814)

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

feature = stub.GetFeature(point)
print(feature)

আপনি Feature অবজেক্টের ফিল্ডগুলো পরিদর্শন করতে এবং অনুরোধের ফলাফল আউটপুট করতে পারেন:

if feature.name:
    print(f"Feature called '{feature.name}' at {format_point(feature.location)}")
else:
    print(f"Found no feature at at {format_point(feature.location)}")

৭. এটি পরীক্ষা করে দেখুন

সার্ভারটি চালান:

python route_guide_server.py

অন্য একটি টার্মিনাল থেকে ভার্চুয়াল এনভায়রনমেন্টটি আবার সক্রিয় করুন, তারপর ক্লায়েন্টটি চালান:

python route_guide_client.py

আপনি এইরকম আউটপুট দেখতে পাবেন, স্পষ্টতার জন্য টাইমস্ট্যাম্পগুলো বাদ দেওয়া হয়েছে:

name: "16 Old Brook Lane, Warwick, NY 10990, USA"
location {
  latitude: 412346009
  longitude: -744026814
}

Feature called '16 Old Brook Lane, Warwick, NY 10990, USA' at latitude: 412346009, longitude: -744026814

৮. এরপর কী?