ما هو gRPC؟ فهم معماري لـ Protocol Buffers، البث، وكيفية عمله

دقائق القراءة: 8

يُعد gRPC إطار عمل قويًا للتعامل مع استدعاءات الإجراءات عن بُعد (Remote Procedure Calls - RPCs). تتيح لك RPCs كتابة التعليمات البرمجية كما لو كانت ستُنفذ على جهاز كمبيوتر محلي، على الرغم من أنها قد تُنفذ فعليًا على جهاز آخر. في هذا المقال، سنتعمق في استكشاف gRPC، مع التركيز على المفاهيم الأساسية بدلاً من تفاصيل التنفيذ. ستتعرف على البنية المعمارية الجوهرية لـ gRPC، وستكتشف أيضًا:

  • لماذا يُستخدم gRPC على نطاق واسع من قبل المطورين؟
  • كيف يحقق هذا الأداء المتميز؟
  • وكيف يعمل كل ذلك تحت الغطاء؟

قبل أن نتعمق في gRPC، دعنا نلقي نظرة سريعة على ماهية استدعاءات الإجراءات عن بُعد. RPC هو شكل من أشكال الاتصال بين العميل والخادم (Client-Server Communication) يستخدم استدعاء دالة (function call) بدلاً من استدعاء HTTP المعتاد. يعتمد على لغة تعريف الواجهة (Interface Definition Language - IDL) كشكل من أشكال العقد لتحديد الدوال التي سيتم استدعاؤها وأنواع البيانات المستخدمة.

هندسة استدعاء الإجراءات عن بُعد (RPC)

رسم توضيحي يوضح كيفية عمل استدعاء الإجراءات عن بُعد (RPC) بين العميل والخادم

كما يوحي الاسم، فإن اختصار RPC في gRPC يشير إلى Remote Procedure Call. وبالفعل، يُجسد gRPC هذا النمط المعماري للاتصال بين العميل والخادم عبر استدعاءات الدوال. لذا، فإن gRPC ليس مفهومًا جديدًا بالكامل من الناحية التقنية، بل هو تطوير وتحسين لتقنية قديمة، مما جعله يحقق شعبية واسعة في غضون خمس سنوات فقط.

نظرة عامة على gRPC

شعار gRPC مع إشارة إلى عام 2015

في عام 2015، قامت جوجل بفتح مصدر مشروعها الذي أصبح يُعرف لاحقًا باسم gRPC. ولكن ما الذي يرمز إليه حرف ‘g‘ في gRPC؟ قد يفترض الكثيرون أنه يشير إلى ‘Google’ نظرًا لأنها الشركة المطورة له، ولكن هذا ليس صحيحًا. تقوم جوجل بتغيير معنى حرف ‘g‘ لكل إصدار، لدرجة أنها أنشأت ملف README خاصًا لسرد جميع المعاني. منذ إطلاقه، اكتسب gRPC شعبية كبيرة، وتستخدمه العديد من الشركات الرائدة اليوم.

ما الذي يجعل gRPC شائعًا لهذه الدرجة؟

هناك العديد من الأسباب التي تساهم في الشعبية الواسعة لـ gRPC:

  • سهولة التجريد: يعتمد على استدعاءات الدوال (function calls)، مما يجعله بديهيًا للمطورين.
  • دعم لغوي واسع: يتوفر له دعم في العديد من لغات البرمجة المختلفة.
  • أداء استثنائي: يقدم مستويات عالية جدًا من الأداء.
  • تبسيط الاتصال: غالبًا ما تكون استدعاءات HTTP مربكة، بينما يوفر gRPC طريقة أبسط وأكثر وضوحًا.

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

رسم توضيحي يوضح بنية الخدمات المصغرة وكيفية تفاعلها

يُعد gRPC مفيدًا للغاية في الاتصالات بين الخدمات (service-to-service calls)، حيث غالبًا ما تكون استدعاءات HTTP أصعب في الفهم للوهلة الأولى. دوال gRPC أسهل بكثير في التفكير والتعامل معها، مما يقلل من حاجة المطورين لكتابة الكثير من التوثيق، لأن الكود نفسه يجب أن يكون شارحًا لذاته. كما أن بعض الخدمات قد تكون مكتوبة بلغات مختلفة، وgRPC يأتي مع مكتبات متعددة لدعم ذلك. الأداء المذهل هو بمثابة “الكرز فوق الكعكة” – وهو كرز كبير جدًا!

البنية المعمارية لـ gRPC

رسم توضيحي للبنية المعمارية العامة لـ gRPC

البنية المعمارية التقريبية لـ gRPC. إنها تتشابه إلى حد كبير مع RPC التقليدي. لقد ذكرنا عدة مرات أن أداء gRPC ممتاز، ولكن قد تتساءل ما الذي يجعله كذلك؟ وما الذي يميز gRPC عن RPC على الرغم من تشابه تصميماتهما؟ إليك بعض الاختلافات الرئيسية التي تمنح gRPC هذا الأداء العالي.

HTTP/2: العمود الفقري للأداء

لقد كان بروتوكول HTTP رفيقنا لفترة طويلة، واليوم، تستخدمه جميع خدمات الواجهة الخلفية تقريبًا.

مخطط زمني لتطور بروتوكول HTTP

كما يوضح الرسم البياني أعلاه، ظل HTTP/1.1 ذا صلة لفترة طويلة. ثم في عام 2015، ظهر HTTP/2 ليحل محل HTTP/1.1 بشكل أساسي كبروتوكول النقل الأكثر شعبية على الإنترنت. إذا تذكرت أن عام 2015 كان أيضًا العام الذي صدر فيه gRPC، فهذا ليس مصادفة على الإطلاق. لقد تم إنشاء HTTP/2 أيضًا بواسطة جوجل ليستخدمه gRPC في بنيته المعمارية. يُعد HTTP/2 أحد الأسباب الرئيسية وراء الأداء المتميز لـ gRPC، وفي الأقسام التالية، ستفهم لماذا.

تعدد إرسال الطلبات والاستجابات (Request/Response Multiplexing)

في بروتوكول HTTP التقليدي، لا يمكن إرسال طلبات متعددة أو استقبال استجابات متعددة في اتصال واحد. يتطلب كل طلب أو استجابة إنشاء اتصال جديد. أصبح هذا النوع من تعدد الإرسال ممكنًا في HTTP/2 بفضل إدخال طبقة جديدة تُسمى ‘binary framing‘.

رسم توضيحي لطبقة الإطارات الثنائية (binary framing) في HTTP/2

تقوم هذه الطبقة الثنائية بتغليف البيانات وترميزها. ضمن هذه الطبقة، يتم تقسيم طلب/استجابة HTTP إلى إطارات (frames). يحتوي إطار الرؤوس (headers frame) على معلومات رؤوس HTTP المعتادة، بينما يحتوي إطار البيانات (data frame) على الحمولة (payload). باستخدام هذه الآلية، يمكن نقل بيانات من طلبات متعددة عبر اتصال واحد. هذا يسمح بحمولات من طلبات متعددة تحمل نفس الرأس، وبالتالي يتم تحديدها كطلب واحد منطقيًا.

ضغط الرؤوس (Header Compression)

قد تكون قد واجهت العديد من الحالات حيث تكون رؤوس HTTP أكبر حجمًا من الحمولة الفعلية. ولحل هذه المشكلة، يعتمد HTTP/2 استراتيجية مثيرة للاهتمام تُسمى HPACK. أولاً، يتم ترميز كل شيء في HTTP/2 قبل إرساله، بما في ذلك الرؤوس. وهذا يساهم في تحسين الأداء، لكنه ليس الجانب الأكثر أهمية في ضغط الرؤوس. يقوم HTTP/2 بتعيين الرؤوس على كل من جانب العميل والخادم. ومن خلال ذلك، يستطيع HTTP/2 معرفة ما إذا كان الرأس يحتوي على نفس القيمة، ويرسل قيمة الرأس فقط إذا كانت مختلفة عن الرأس السابق.

رسم توضيحي لآلية ضغط الرؤوس (HPACK) في HTTP/2

كما هو موضح في الصورة أعلاه، سيرسل الطلب الثاني (Request #2) المسار (path) فقط، نظرًا لأن القيم الأخرى متطابقة تمامًا. وهذا يقلل بشكل كبير من حجم الحمولة، وبالتالي يحسن أداء HTTP/2 بشكل أكبر.

بروتوكول المخازن المؤقتة (Protocol Buffers) أو Protobuf

شعار Protocol Buffers

يُعد Protobuf (اختصار لـ Protocol Buffers) لغة تعريف الواجهة (IDL) الأكثر استخدامًا مع gRPC. في الأساس، يتم فيه تخزين عقود البيانات والدوال الخاصة بك في شكل ملف .proto.

message Person {
  required string name = 1;
  required int32 id = 2;
  optional string email = 3;
}

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

ميزات إضافية يقدمها gRPC

صورة توضيحية لميزات gRPC المتقدمة

الآن، يجب أن يكون لديك فهم أساسي لبنية gRPC، وكيف يعمل، وما هي قدراته. ولكن إليك بعض الميزات الأخرى المثيرة للاهتمام التي يقدمها gRPC.

البيانات الوصفية (Metadata)

بدلاً من استخدام رؤوس طلب HTTP المعتادة، يحتوي gRPC على ما يُسمى metadata (البيانات الوصفية). Metadata هي نوع من البيانات على شكل أزواج مفتاح-قيمة (key-value) يمكن تعيينها من جانب العميل أو الخادم. يمكن تعيين Header من جانب العميل، بينما يمكن للخوادم تعيين Header و Trailers طالما أنهما على شكل metadata.

البث (Streaming)

يُعد البث (Streaming) أحد المفاهيم الأساسية في gRPC، حيث يمكن أن تحدث عدة عمليات في طلب واحد. هذا أصبح ممكنًا بفضل قدرة HTTP/2 على تعدد الإرسال (multiplexing) التي ذكرناها سابقًا. هناك عدة أنواع من البث:

  • بث الخادم (Server Streaming RPC): حيث يرسل العميل طلبًا واحدًا، ويمكن للخادم إرسال استجابات متعددة. على سبيل المثال، عندما يرسل العميل طلبًا لصفحة رئيسية تحتوي على قائمة من العناصر المتعددة، يمكن للخادم إرسال الاستجابات بشكل منفصل، مما يتيح للعميل استخدام التحميل الكسول (lazy loading).
  • بث العميل (Client Streaming RPC): حيث يرسل العميل طلبات متعددة، ويرسل الخادم استجابة واحدة فقط. على سبيل المثال، تحميل ملف مضغوط (zip) أو أجزاء (chunk) من ملف بواسطة العميل.
  • بث ثنائي الاتجاه (Bidirectional Streaming RPC): حيث يرسل كل من العميل والخادم رسائل إلى بعضهما البعض في نفس الوقت دون انتظار استجابة.

المُعترضات (Interceptors)

يدعم gRPC استخدام المُعترضات (interceptors) لطلباته واستجاباته. تقوم المُعترضات، ببساطة، باعتراض الرسائل وتسمح لك بتعديلها. هل يبدو هذا مألوفًا؟ إذا كنت قد تعاملت مع عمليات HTTP في واجهة برمجة تطبيقات REST API، فإن المُعترضات تشبه إلى حد كبير البرمجيات الوسيطة (middleware). تدعم مكتبات gRPC عادةً المُعترضات، وتتيح سهولة في التنفيذ. تُستخدم المُعترضات عادةً من أجل:

  • تعديل الطلب/الاستجابة قبل تمريرها. يمكن استخدامها لتوفير معلومات إلزامية قبل إرسالها إلى العميل/الخادم.
  • السماح لك بمعالجة كل استدعاء دالة، مثل إضافة تسجيل إضافي لتتبع وقت الاستجابة.

موازنة الحمل (Load Balancing)

إذا لم تكن على دراية بموازنة الحمل (load balancing)، فهي آلية تسمح بتوزيع طلبات العميل عبر خوادم متعددة. ولكن عادةً ما تتم موازنة الحمل على مستوى الوكيل (proxy level) (على سبيل المثال، NGINX). فلماذا نتحدث عنها هنا؟ اتضح أن gRPC يدعم طريقة لموازنة الحمل من جانب العميل. لقد تم تنفيذها بالفعل في مكتبة Golang، ويمكن استخدامها بسهولة. وبينما قد يبدو هذا كنوع من السحر الجنوني، إلا أنه ليس كذلك. هناك نوع من محلل DNS للحصول على قائمة عناوين IP، وخوارزمية موازنة حمل تعمل تحت الغطاء.

إلغاء الاستدعاء (Call Cancellation)

يمكن لعملاء gRPC إلغاء استدعاء gRPC عندما لا يحتاجون إلى استجابة بعد الآن. ومع ذلك، لا يمكن التراجع عن العملية (rollback) على جانب الخادم. هذه الميزة مفيدة بشكل خاص في بث الخادم (server-side streaming) حيث قد تأتي طلبات خادم متعددة. تأتي مكتبة gRPC مجهزة بنمط طريقة المراقبة (observer method pattern) لمعرفة ما إذا كان الطلب قد تم إلغاؤه والسماح بإلغاء طلبات متعددة متطابقة في وقت واحد.

الخلاصة

صورة ختامية للمقال عن gRPC

كل ما شاركناه اليوم يمثل مجرد لمحة سريعة عن ماهية gRPC، وقدراته، وكيفية عمله بشكل تقريبي. نأمل أن يكون هذا المقال قد ساعدك على فهم المزيد حول gRPC. ولكن لا يزال هناك الكثير لتتعلمه، لذا لا تتوقف هنا! استمر في البحث والتعمق.

الخلاصة التقنية

يُقدم gRPC نقلة نوعية في عالم الاتصالات بين الخدمات، خاصة في بيئات الخدمات المصغرة المعقدة. بفضل اعتماده على HTTP/2 و Protocol Buffers، يتفوق gRPC في الأداء والكفاءة على بروتوكولات REST/HTTP/1.1 التقليدية. إن قدراته على البث المتعدد، وضغط الرؤوس، ودعم اللغات المتعددة، تجعله خيارًا مثاليًا للتطبيقات التي تتطلب استجابة سريعة واستهلاكًا منخفضًا للموارد. على الرغم من أن منحنى تعلمه قد يكون أعلى قليلاً من REST، إلا أن الفوائد التي يقدمها من حيث الأداء والمرونة وتسهيل التفاعل بين الخدمات المتنوعة تبرر هذا الجهد، مما يجعله أداة لا غنى عنها للمطورين الذين يسعون لبناء أنظمة موزعة عالية الكفاءة.

اترك تعليقاً

لن يتم نشر عنوان بريدك الإلكتروني. الحقول الإلزامية مشار إليها بـ *