بناء أول خدمة gRPC في بايثون خطوة بخطوة

بناء أول خدمة gRPC في بايثون خطوة بخطوة (gRPC Python)

في السنوات الأخيرة أصبح gRPC واحدًا من أهم بروتوكولات التواصل في الأنظمة الموزعة والمايكروسيرفس. إذا كنت معتادًا على REST وترغب في تجربة بديل أسرع وأكثر كفاءة، فهذه المقالة لك. سنبني معًا أول خدمة gRPC Python من الصفر، خطوة بخطوة، مع مثال عملي بسيط يمكن تشغيله على جهازك مباشرة.

سنستخدم في هذا الدليل:

  • لغة Python
  • مكتبة grpcio و grpcio-tools
  • ملف .proto لتعريف الـ API

إذا كنت مهتمًا بالأنظمة الموزعة، فقد يعجبك أيضًا مقالنا عن Retry Pattern في الأنظمة الموزعة، لأنه يرتبط بشكل مباشر بطريقة التعامل مع فشل الطلبات بين الخدمات.

ما هو gRPC ولماذا نستخدمه؟

gRPC إطار عمل (RPC framework) مفتوح المصدر من جوجل، يسمح للخدمات بالتواصل فيما بينها عبر استدعاءات دوال عن بعد (Remote Procedure Calls)، كأنك تستدعي دالة عادية في مشروعك، لكن في الحقيقة الطلب يذهب عبر الشبكة.

مقارنة سريعة بين gRPC و REST

  • التنسيق: REST غالبًا يستخدم JSON، أما gRPC يعتمد على Protocol Buffers (Protobuf) وهي صيغة ثنائية (Binary) مضغوطة وسريعة.
  • الأداء: gRPC عادة أسرع وأقل في استهلاك الباندوِث.
  • الأنواع (Typing): Protobuf يقدم تعريفًا صارمًا للأنواع (Strongly Typed)، مما يسهل توليد الكود للعميل والخادم.
  • الاتصال الثنائي الاتجاه: gRPC يدعم Streaming (خادم للعميل، عميل للخادم، ثنائي الاتجاه) بسهولة.

هذا يجعل gRPC Python خيارًا ممتازًا لبناء أنظمة موزعة، خاصة عندما يكون هناك عدد كبير من الخدمات التي تتواصل باستمرار وبأداء عالٍ.

المتطلبات الأساسية قبل البدء

قبل أن نغوص في الكود، تأكد أن لديك:

  • Python 3.8 أو أحدث
  • pip مثبت
  • فهم أساسي للبرمجة بكائنات بايثون (Classes/Modules)

إذا كنت تحتاج مراجعة سريعة لأساسيات بايثون، يمكنك الاطلاع على مقال شرح الحلقات في لغة بايثون لفهم كيفية التحكم في تدفق التنفيذ بشكل أفضل.

نظرة عامة على ما سنقوم ببنائه

سنقوم ببناء خدمة gRPC بسيطة باسم GreeterService تقوم بوظيفة واحدة:

  • SayHello: تستقبل اسم مستخدم وترجع رسالة ترحيب.

مكونات المشروع ستكون:

  1. ملف بروتوكول greet.proto لتعريف الرسائل والخدمات.
  2. مولد الكود الخاص بـ gRPC لإنتاج ملفات بايثون من ملف .proto.
  3. كود الخادم server.py.
  4. كود العميل client.py.

الخطوة 1: إنشاء بيئة العمل وتثبيت الحزم

1. إنشاء مجلد المشروع

أنشئ مجلدًا جديدًا للمشروع:

mkdir grpc-python-demo
cd grpc-python-demo

2. تفعيل بيئة افتراضية (اختياري لكنه مفضل)

python -m venv venv
# على لينكس/ماك
source venv/bin/activate
# على ويندوز
venv\Scripts\activate

3. تثبيت حزم gRPC الضرورية

نحتاج إلى حزمتين:

  • grpcio: مكتبة gRPC الأساسية لبايثون.
  • grpcio-tools: لتوليد كود بايثون من ملفات Protobuf.
pip install grpcio grpcio-tools

الخطوة 2: تعريف الخدمة باستخدام ملف .proto

ملف .proto هو قلب أي مشروع gRPC. من خلاله نعرّف:

  • الرسائل (Messages) = تشبه الـ DTO أو الـ Models.
  • الخدمة (Service) = مجموعة الـ RPC methods.

إنشاء ملف greet.proto

داخل مجلد المشروع أنشئ ملفًا جديدًا باسم greet.proto وضع فيه الكود التالي:

syntax = "proto3";

package greet;

// رسالة الطلب من العميل إلى الخادم
message HelloRequest {
  string name = 1;
}

// رسالة الاستجابة من الخادم إلى العميل
message HelloReply {
  string message = 1;
}

// تعريف خدمة gRPC
service Greeter {
  // RPC بسيط: طلب واحد > رد واحد
  rpc SayHello (HelloRequest) returns (HelloReply) {}
}

شرح سريع:

  • syntax = "proto3"; نحدد أننا نستخدم الإصدار الثالث من Protobuf.
  • package greet; اسم حزمة بروتوكول (يظهر في بايثون كموديول).
  • HelloRequest يحتوي على حقل واحد من نوع string باسم name.
  • HelloReply يحتوي على حقل واحد من نوع string باسم message.
  • service Greeter يعرّف خدمة بها دالة SayHello تأخذ HelloRequest وتعيد HelloReply.

الخطوة 3: توليد كود بايثون من ملف .proto

الآن سنستخدم grpcio-tools لتوليد ملفين أساسيين:

  • greet_pb2.py: يحتوي على تعريفات الرسائل (Message classes).
  • greet_pb2_grpc.py: يحتوي على تعريفات الخدمات (Servicer و Stub).

نفذ الأمر التالي داخل مجلد المشروع:

python -m grpc_tools.protoc \
  -I. \
  --python_out=. \
  --grpc_python_out=. \
  greet.proto

بعد التنفيذ ستجد الملفين: greet_pb2.py و greet_pb2_grpc.py في نفس المجلد. لا تعدل هذه الملفات يدويًا؛ لأنها تُولد آليًا، وأي تعديل سيتم فقدانه عند إعادة التوليد.

الخطوة 4: بناء خادم gRPC في بايثون

الآن حان وقت استخدام قوة gRPC Python لبناء الخادم (Server) الذي ينفذ منطق العمل (Business Logic).

إنشاء ملف server.py

أنشئ ملفًا جديدًا باسم server.py وضع فيه الكود التالي:

from concurrent import futures
import time
import grpc

import greet_pb2
import greet_pb2_grpc


# نعرّف الكلاس الذي ينفذ الخدمة Greeter
class GreeterService(greet_pb2_grpc.GreeterServicer):
    def SayHello(self, request, context):
        # request يحتوي على الحقول المرسلة من العميل
        name = request.name
        message = f"مرحبًا يا {name}! هذه رسالة من خادم gRPC مكتوب ببايثون."
        # نرجع كائن من نوع HelloReply
        return greet_pb2.HelloReply(message=message)


def serve():
    # نُنشئ خادم gRPC مع ThreadPool لتعددية التنفيذ
    server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
    
    # نربط خدمة GreeterService بالخادم
    greet_pb2_grpc.add_GreeterServicer_to_server(GreeterService(), server)
    
    # نستمع على المنفذ 50051
    server.add_insecure_port("[::]:50051")
    
    print("خادم gRPC يعمل على المنفذ 50051...")
    server.start()
    
    try:
        # نبقي الخادم يعمل إلى أن يتم إيقافه يدويًا
        while True:
            time.sleep(86400)
    except KeyboardInterrupt:
        print("إيقاف الخادم...")
        server.stop(0)


if __name__ == "__main__":
    serve()

شرح النقاط المهمة في الخادم

  • GreeterService يرث من greet_pb2_grpc.GreeterServicer التي ولدها gRPC تلقائيًا، وكل دالة فيها يجب أن تطابق التوقيع الموجود في ملف .proto.
  • الدالة SayHello تستقبل:
    • request: كائن من نوع HelloRequest.
    • context: كائن يوفر معلومات عن الاتصال (مثل metadata، status).
  • بعد إنشاء رسالة الرد، نرجع HelloReply باستخدام greet_pb2.HelloReply.
  • نستخدم grpc.server مع ThreadPoolExecutor حتى يتمكن الخادم من معالجة عدة طلبات في نفس الوقت. يمكنك الربط هنا بما تعلمته عن Threading في بايثون لفهم آلية تعدد الخيوط في الخلفية.

الخطوة 5: بناء عميل gRPC في بايثون

العميل (Client) هو البرنامج الذي يتواصل مع الخادم ويرسل الطلبات. سنبني عميل بسيط يسأل المستخدم عن اسمه، ثم يرسل الطلب إلى الخادم ويتلقى الرد.

إنشاء ملف client.py

أنشئ ملفًا جديدًا باسم client.py وضع فيه الكود التالي:

import grpc

import greet_pb2
import greet_pb2_grpc


def run():
    # نُنشئ قناة اتصال مع الخادم
    with grpc.insecure_channel("localhost:50051") as channel:
        # نُنشئ Stub (وكيل) للخدمة Greeter
        stub = greet_pb2_grpc.GreeterStub(channel)
        
        name = input("أدخل اسمك: ")
        
        # نُنشئ رسالة الطلب
        request = greet_pb2.HelloRequest(name=name)
        
        # نستدعي الدالة SayHello كما لو كانت دالة محلية
        response = stub.SayHello(request)
        
        print("رد الخادم: ", response.message)


if __name__ == "__main__":
    run()

شرح النقاط المهمة في العميل

  • نستخدم grpc.insecure_channel لفتح قناة بدون تشفير (TLS). في بيئات الإنتاج غالبًا ستحتاج قناة آمنة.
  • GreeterStub هو الكلاس الذي ولّده gRPC من ملف .proto ويقوم بدور الوكيل بين العميل والخادم.
  • استدعاء stub.SayHello(request) يشبه استدعاء دالة عادية، لكن فعليًا يتم إرسال الطلب عبر الشبكة إلى الخادم.

الخطوة 6: تشغيل الخادم والعميل واختبار الخدمة

1. تشغيل الخادم

في نافذة طرفية (Terminal) أولى، تأكد أن بيئة العمل مفعلة، ثم نفذ:

python server.py

يجب أن ترى رسالة مثل:

خادم gRPC يعمل على المنفذ 50051...

2. تشغيل العميل

في نافذة طرفية ثانية، نفذ:

python client.py

سيطلب منك إدخال الاسم:

أدخل اسمك: أحمد
رد الخادم:  مرحبًا يا أحمد! هذه رسالة من خادم gRPC مكتوب ببايثون.

بهذا تكون قد بنيت أول خدمة gRPC Python كاملة: خادم + عميل + تعريف بروتوكول.

الخطوة 7: فهم أنواع الـ RPC في gRPC (نظرة سريعة)

في مثالنا استخدمنا النوع الأبسط من الـ RPC: Unary RPC (طلب واحد > رد واحد). لكن gRPC يدعم أنماطًا أخرى مهمة في الأنظمة الموزعة:

  • Server streaming: العميل يرسل طلبًا واحدًا، الخادم يعيد Stream من الردود.
  • Client streaming: العميل يرسل Stream من الطلبات، الخادم يعيد ردًا واحدًا.
  • Bidirectional streaming: العميل والخادم يتبادلان Stream من الرسائل في نفس الاتصال.

هذه الأنماط تصبح مفيدة جدًا في حالات مثل:

  • تطبيقات المحادثة (Chat) أو الإشعارات اللحظية.
  • نقل ملفات أو بيانات كبيرة على دفعات.
  • تطبيقات تحتاج لاتصال مستمر بين العميل والخادم، وعندها يمكنك مقارنة gRPC مع WebSockets كما في مقال: التعامل مع WebSockets في FastAPI: تطبيق عملي.

نصائح عملية عند استخدام gRPC Python في الأنظمة الموزعة

1. تنظيم ملفات .proto

  • قسّم الخدمات إلى ملفات .proto منطقية (auth.proto, user.proto, order.proto).
  • استخدم package مختلفة لكل مجال (domain) لتجنب تعارض الأسماء.

2. التعامل مع الأخطاء (Error Handling)

لا ترسل رسائل الخطأ كنصوص عادية فقط، استخدم status codes المدمجة في gRPC مثل:

  • NOT_FOUND
  • INVALID_ARGUMENT
  • UNAUTHENTICATED
  • INTERNAL

يمكن الوصول لها من داخل السيرفر عبر كائن context وتحديد الحالة المناسبة.

3. الإعداد للإنتاج (Production Ready)

  • استخدم قناة آمنة (SSL/TLS) بدلاً من insecure_channel.
  • فعّل الـ timeouts و retries من جهة العميل، خاصة عند العمل في شبكة غير مستقرة.
  • راقب أداء الخادم (عدد الطلبات، زمن الاستجابة) لتتمكن من توسيع النظام عند الحاجة (Scalability).

توسيع المثال: ماذا يمكنك أن تفعل بعد ذلك؟

الآن بعد أن فهمت الأساسيات، يمكنك تطوير المثال ليصبح أقرب لتطبيق حقيقي:

  • إضافة دوال جديدة في Greeter مثل:
    • SayHelloAgain ترسل ردًا مختلفًا.
    • ListGreetings تستخدم Server Streaming لإرجاع عدة رسائل ترحيب.
  • ربط خدمة gRPC مع قاعدة بيانات، مثل حفظ سجل لعدد المرات التي تم فيها استدعاء الخدمة لكل مستخدم.
  • دمج الخدمة داخل نظام موزع أكبر، مثلاً خدمة توصيات كما في مقال بناء نظام توصيات بسيط باستخدام Python، بحيث تكون gRPC هي واجهة المايكروسيرفس.

خلاصة: لماذا gRPC Python خيار ممتاز للأنظمة الموزعة؟

باستخدام gRPC Python حصلت على:

  • أداء عالٍ بفضل Protocol Buffers والاتصال الثنائي (HTTP/2).
  • تعريف صارم وواضح للـ API من خلال ملفات .proto.
  • توليد تلقائي لكود الخادم والعميل، مما يقلل من الأخطاء اليدوية.
  • دعم كامل لأنماط الـ Streaming المفيدة في الأنظمة الموزعة المعقدة.

في هذا الدليل طبقنا:

  1. إنشاء ملف greet.proto لتعريف الرسائل والخدمة.
  2. توليد كود بايثون باستخدام grpcio-tools.
  3. بناء خادم gRPC بسيط في server.py.
  4. بناء عميل gRPC في client.py واختبار الاتصال.

الخطوة التالية المنطقية هي تجربة إضافة المزيد من الخدمات والرسائل، وتجربة أنماط الـ Streaming، ثم محاولة دمج gRPC ضمن مشروع أكبر، مثل نظام مايكروسيرفس أو نظام توصيات أو خدمة تحليل صور كما في مقالنا عن تعلم تحديد الأشكال الهندسية والوجوه باستخدام OpenCV في بايثون.

مع الوقت ستجد أن gRPC يصبح أداة أساسية في صندوق أدواتك عندما تعمل على الأنظمة الموزعة أو التطبيقات التي تحتاج إلى أداء عالٍ وتواصل مكثف بين الخدمات.

حول المحتوى:

دليل عملي لإنشاء خدمة gRPC باستخدام بايثون مع مثال بسيط وسهل التطبيق.

هل كان هذا مفيدًا لك؟

أضف تعليقك