حول المحتوى:
دليل عملي لإنشاء خدمة gRPC باستخدام بايثون مع مثال بسيط وسهل التطبيق.
في السنوات الأخيرة أصبح gRPC واحدًا من أهم بروتوكولات التواصل في الأنظمة الموزعة والمايكروسيرفس. إذا كنت معتادًا على REST وترغب في تجربة بديل أسرع وأكثر كفاءة، فهذه المقالة لك. سنبني معًا أول خدمة gRPC Python من الصفر، خطوة بخطوة، مع مثال عملي بسيط يمكن تشغيله على جهازك مباشرة.
سنستخدم في هذا الدليل:
إذا كنت مهتمًا بالأنظمة الموزعة، فقد يعجبك أيضًا مقالنا عن Retry Pattern في الأنظمة الموزعة، لأنه يرتبط بشكل مباشر بطريقة التعامل مع فشل الطلبات بين الخدمات.
gRPC إطار عمل (RPC framework) مفتوح المصدر من جوجل، يسمح للخدمات بالتواصل فيما بينها عبر استدعاءات دوال عن بعد (Remote Procedure Calls)، كأنك تستدعي دالة عادية في مشروعك، لكن في الحقيقة الطلب يذهب عبر الشبكة.
هذا يجعل gRPC Python خيارًا ممتازًا لبناء أنظمة موزعة، خاصة عندما يكون هناك عدد كبير من الخدمات التي تتواصل باستمرار وبأداء عالٍ.
قبل أن نغوص في الكود، تأكد أن لديك:
إذا كنت تحتاج مراجعة سريعة لأساسيات بايثون، يمكنك الاطلاع على مقال شرح الحلقات في لغة بايثون لفهم كيفية التحكم في تدفق التنفيذ بشكل أفضل.
سنقوم ببناء خدمة gRPC بسيطة باسم GreeterService تقوم بوظيفة واحدة:
مكونات المشروع ستكون:
أنشئ مجلدًا جديدًا للمشروع:
mkdir grpc-python-demo
cd grpc-python-demo
python -m venv venv
# على لينكس/ماك
source venv/bin/activate
# على ويندوز
venv\Scripts\activate
نحتاج إلى حزمتين:
pip install grpcio grpcio-tools
ملف .proto هو قلب أي مشروع gRPC. من خلاله نعرّف:
داخل مجلد المشروع أنشئ ملفًا جديدًا باسم 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) {}
}
شرح سريع:
الآن سنستخدم grpcio-tools لتوليد ملفين أساسيين:
نفذ الأمر التالي داخل مجلد المشروع:
python -m grpc_tools.protoc \
-I. \
--python_out=. \
--grpc_python_out=. \
greet.proto
بعد التنفيذ ستجد الملفين: greet_pb2.py و greet_pb2_grpc.py في نفس المجلد. لا تعدل هذه الملفات يدويًا؛ لأنها تُولد آليًا، وأي تعديل سيتم فقدانه عند إعادة التوليد.
الآن حان وقت استخدام قوة gRPC Python لبناء الخادم (Server) الذي ينفذ منطق العمل (Business Logic).
أنشئ ملفًا جديدًا باسم 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()
العميل (Client) هو البرنامج الذي يتواصل مع الخادم ويرسل الطلبات. سنبني عميل بسيط يسأل المستخدم عن اسمه، ثم يرسل الطلب إلى الخادم ويتلقى الرد.
أنشئ ملفًا جديدًا باسم 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()
في نافذة طرفية (Terminal) أولى، تأكد أن بيئة العمل مفعلة، ثم نفذ:
python server.py
يجب أن ترى رسالة مثل:
خادم gRPC يعمل على المنفذ 50051...
في نافذة طرفية ثانية، نفذ:
python client.py
سيطلب منك إدخال الاسم:
أدخل اسمك: أحمد
رد الخادم: مرحبًا يا أحمد! هذه رسالة من خادم gRPC مكتوب ببايثون.
بهذا تكون قد بنيت أول خدمة gRPC Python كاملة: خادم + عميل + تعريف بروتوكول.
في مثالنا استخدمنا النوع الأبسط من الـ RPC: Unary RPC (طلب واحد > رد واحد). لكن gRPC يدعم أنماطًا أخرى مهمة في الأنظمة الموزعة:
هذه الأنماط تصبح مفيدة جدًا في حالات مثل:
لا ترسل رسائل الخطأ كنصوص عادية فقط، استخدم status codes المدمجة في gRPC مثل:
يمكن الوصول لها من داخل السيرفر عبر كائن context وتحديد الحالة المناسبة.
الآن بعد أن فهمت الأساسيات، يمكنك تطوير المثال ليصبح أقرب لتطبيق حقيقي:
باستخدام gRPC Python حصلت على:
في هذا الدليل طبقنا:
الخطوة التالية المنطقية هي تجربة إضافة المزيد من الخدمات والرسائل، وتجربة أنماط الـ Streaming، ثم محاولة دمج gRPC ضمن مشروع أكبر، مثل نظام مايكروسيرفس أو نظام توصيات أو خدمة تحليل صور كما في مقالنا عن تعلم تحديد الأشكال الهندسية والوجوه باستخدام OpenCV في بايثون.
مع الوقت ستجد أن gRPC يصبح أداة أساسية في صندوق أدواتك عندما تعمل على الأنظمة الموزعة أو التطبيقات التي تحتاج إلى أداء عالٍ وتواصل مكثف بين الخدمات.
دليل عملي لإنشاء خدمة gRPC باستخدام بايثون مع مثال بسيط وسهل التطبيق.
مساحة اعلانية