gRPC مقابل REST: مقارنة الأساليب لصنع APIs

في نص اليوم، أرغب في إلقاء نظرة أقرب على gRPC و REST، ربما أكثر الأساليب استخدامًا في تكوين APIs في الوقت الحاضر.

I will start with a short characteristic of both tools — what they are and what they can offer. Then I will compare them according to seven categories, in my opinion, most crucial for modern-day systems.

تنقسم الفئات إلى ما يلي:

  1. البروتوكولات HTTP الأساسية
  2. أشكال البيانات المدعومة
  3. حجم البيانات
  4. الناتج
  5. التعريفات
  6. سهولة التبني
  7. دعم الأدوات

السبب

عندما يسمع الناس “API”، ربما يفكرون في REST API على الفور. ومع ذلك، فإن REST هو واحد من عدة أساليب لبناء APIs. إنه ليس الحل المثالي لجميع الحالات الاستخدامية. هناك طرق أخرى، حيث يعتبر RPC (استدعاء الإجراء البعيد) واحدًا منها، و gRPC ربما هو الإطار الأكثر نجاحًا في العمل مع RPC.

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

السبب الرئيسي لكتابة هذه المدونة هو نشر gRPC وتحديد الحالات الاستخدامية التي يمكن أن يتميز فيها.

ما هو REST؟

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

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

REST ليس بروتوكولًا ولا أداة (إلى درجة معينة): إنه نهج تشغيلي لبناء التطبيقات. الخدمات التي تتبع نهج REST تسمى خدمات RESTFul. كنهج تشغيلي، فإنه يفرض العديد من القيود على مستخدميه. وتشمل ذلك:

  • التواصل العميل-الخادم
  • التواصل عديم الحالة
  • التخزين المؤقت
  • واجهة موحدة
  • النظام المتعدد الطبقات
  • التعليمات البرمجية عند الطلب

المفاهيم الحاسمة الأساسية لـ REST هي:

  1. النقاط النهائية: عنوان URL فريد (عنوان الموقع الموحد للموارد) يمثل موردًا محددًا؛ يمكن النظر إليه على أنه طريقة للوصول إلى عملية أو عنصر بيانات معين عبر الإنترنت
  2. المورد: قطعة بيانات معينة متاحة تحت URL محدد

علاوة على ذلك، هناك وصف يسمى نموذج تشكل ريتشاردسون — نموذج يصف درجة “الاحترافية” في واجهات برمجة التطبيقات REST. يقسم واجهات برمجة التطبيقات REST إلى 3 مستويات (أو 4، حسب ما إذا كنت تعتبر المستوى 0) بناءً على مجموعة السمات التي يتمتع بها API معين.

إحدى هذه السمات هي أن نقطة الوصول REST يجب أن تستخدم الأسماء في URL وطرق طلب HTTP الصحيحة لإدارة خصوصياتها.

  • مثال: DELETE user/1 بدلاً من GET user/deleteById/1

أما بخصوص طرق HTTP والإجراءات المرتبطة بها، فتسير كما يلي:

  • GET — استرداد مورد محدد أو مجموعة من الموارد
  • POST — إنشاء مورد جديد
  • PUT — تعديل كامل للمورد
  • PATCH — تحديث جزئي لمورد محدد
  • DELETE — إزالة مورد محدد حسب المعرف

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

A full description of the maturity model is out of the scope of this blog — you can read more about it here.

تحذير: العديد من الأشياء المذكورة في هذه الفقرة أكثر تعقيدًا مما هو موصوف هنا. REST موضوع شاسع للغاية ويستحق سلسلة كاملة من المقالات. ومع ذلك، كل شيء هنا يتوافق مع أفضل الممارسات المعروفة عادةً لـ REST.

ما هو gRPC؟

هي تنفيذ آخر لمفهوم قديم نسبيًا لمكالمات الإجراءات البعيدة. أنشأها أشخاص من جوجل – ولهذا السبب يحمل الحرف “g” في اسمه. من المحتمل أنها أكثر الأدوات حداثة وكفاءة للعمل مع مكالمات RPC وأيضاً مشروع حضانة CNCF.

gRPC يستخدم بروتوكولات بافونت Google كصيغة تحويل البيانات بينما يستخدم HTTP/2 كوسيط نقل البيانات، على الرغم من أن gRPC يمكن أن يعمل أيضًا مع JSON كطبقة بيانات.

اللبنات الأساسية لـ gRPC تشمل:

  • الطرف المتنفذ: اللبنة الأساسية لـ gRPC، كل طرف هو مكالمة إجراء بعيدة تأخذ بعض المدخلات وتعيد مخرجات. يؤدي عملية مفردة مُحللة أكثر في لغة البرمجة المختارة. حتى الآن، يدعم gRPC 4 أنواع من الطرق: 
  1. أحادي النواة: نموذج طلب-استجابة كلاسيكي حيث يأخذ الطرف مدخلات ويعيد مخرجات
  2. تدفق الخادم: الطرق تقبل رسالة كمدخل بينما تعيد تدفق الرسائل كمخرجات. gRPC يضمن ترتيب تسلسل الرسائل داخل مكالمة RPC مفردة.
  3. تدفق العميل: الطرف يأخذ تدفق الرسائل كمدخل، يعالجها حتى لا تتبقى رسائل، ثم يعيد رسالة واحدة كمخرجات. مشابه للأعلى، gRPC يضمن ترتيب تسلسل الرسائل داخل مكالمة RPC مفردة.
  4. دفق ثنائي الاتجاه: تأخذ الطريقة الدفق كمدخل وتعيد الدفق كمخرج، مما يستخدم بشكل فعال دفقين للقراءة والكتابة. يعملان بشكل مستقل ويتم الحفاظ على ترتيب الرسائل على مستوى الدفق.
  • الخدمة: تمثل مجموعة من الطرق – يجب أن يكون لكل طريقة إسم فريد داخل الخدمة. تصف الخدمات أيضًا ميزات مثل الأمان والزمن المتاح وإعادة المحاولات.
  • الرسالة: كائن يمثل مدخلات أو مخرجات الطرق.

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

يمكننا تنفيذ طرق الخادم بأي شكل نريد. يجب أن نلتزم بعقدة المدخلات-المخرجات للواجهة.

على الجانب العميل، يوجد كائن يسمى العميل (أو العصب) – مثل عميل HTTP. يعرف جميع الطرق من الخادم ويتعامل فقط مع استدعاء الإجراءات البعيدة وإرجاع استجاباتها.

المقارنة

بروتوكول HTTP الأساسي

هذه هي الفئة الأولى وربما الأكثر أهمية، حيث يمكن أن يظهر تأثيرها أيضًا في الآخرين.

بشكل عام، يعتمد REST على الطلب والاستجابة ويستخدم HTTP/1.1 كوسيط نقل. يجب استخدام بروتوكول مختلف مثل WebSocket (المزيد عنها هنا) أو أي نوع من الدفق أو الاتصالات الأطول مدى الحياة.

يمكننا أيضًا تنفيذ رمز متعرض حول لجعل REST تبدو مثل البث. أكثر من ذلك، استخدام HTTP/1.1 REST يتطلب اتصالًا واحدًا لكل تبادل طلب-استجابة. مثل هذا النهج قد يكون مشكل بالنسبة للطلبات طويلة المدى أو عندما لدينا قدرات شبكية محدودة.

بالطبع، يمكننا استخدام HTTP/2 لبناء APIs تشبه REST؛ ومع ذلك، لا يدعم جميع الخوادم والمكتبات HTTP/2 بعد. وبالتالي، قد تنشأ مشاكل في أماكن أخرى.

gRPC، من ناحية أخرى، يستخدم HTTP/2 فقط. يسمح بإرسال عدة مجموعات طلب-استجابة من خلال اتصال TCP واحد. مثل هذا النهج يمكن أن يكون تعزيزًا أدائيًا كبيرًا لتطبيقاتنا.

  • النتيجة: الفوز البسيط لـ gRPC

أشكال البيانات المدعومة

على افتراض الحالة الافتراضية عندما يستخدم REST API HTTP/1.1، فإنه يمكن أن يدعم العديد من الأشكال.

REST بشكل عام لا يفرض أي قيود على تنسيق الرسائل والأسلوب. أساسًا كل تنسيق يمكن تجميعه إلى نص قديم بسيط صالح. يمكننا استخدام أي تنسيق يناسبنا بشكل أفضل في مجال معين.

التنسيق الأكثر شهرة لإرسال البيانات في تطبيقات REST بالتأكيد JSON. يأتي XML في المرتبة الثانية بسبب عدد كبير من التطبيقات القديمة/البالية.

ومع ذلك، عند استخدام REST مع HTTP/2، فقط تنسيقات التبادل الثنائية مدعومة. في هذه الحالة، يمكننا استخدام Protobuf أو Avro. بالطبع، مثل هذا النهج يمكن أن يكون له عيوبه، ولكن المزيد عن ذلك في النقاط التالية.

وفي الوقت نفسه، gRPC يدعم فقط تنسيقين لتبادل البيانات:

  1. Protobuf — افتراضيًا
  2. JSON — عندما تحتاج للتكامل مع واجهة برمجة التطبيقات (API) أقدم

إذا قررت تجربة JSON، ستستخدم gRPC JSON كصيغة لترميز الرسائل و GSON كصيغة رسالة. علاوة على ذلك، سيتطلب استخدام JSON بعض التكوين الإضافي للقيام به. هنا دليل gRPC الوثائقي حول كيفية القيام بذلك.

  • النتيجة: الفوز لـ REST، حيث تدعم صيغًا أكثر.

حجم البيانات

بشكل افتراضي، يستخدم gRPC تبادل بيانات بتنظيم ثنائي، مما يقلل بشكل كبير حجم الرسائل المرسلة عبر الشبكة: البحث يقول حوالي 40-50% أقل حجم بالبايت — تجربتي من أحد المشاريع السابقة تقول حتى 50-70% أقل.

المقالة المذكورة أعلاه توفر مقارنة حجمية نسبيًا بين JSON و Protobuff. قدم المؤلف أيضًا أداة توليد JSONs وملفات ثنائية. وبالتالي يمكنك إعادة تشغيل تجاربه ومقارنة النتائج.

الكائنات من المقالة معقدة بشكل معقول. ومع ذلك، القاعدة العامة هي — كلما زادت الكائنات المضمنة وكان تنظيم JSON أكثر تعقيدًا، كلما كان أثقل مقارنة بـ Protobuf. فرق في الحجم بنسبة 50% لصالح Protobuf هو خط افتراضي جيد.

يمكن تقليل الفرق أو القضاء عليه عند استخدام تنسيق التبادل الثنائي لـ REST. ومع ذلك، هذه ليست الطريقة الأكثر شيوعًا أو الأكثر دعمًا لإنشاء APIs RESTful، لذا قد تنشأ مشكلات أخرى.

  • نتيجة: في الحالة الافتراضية، الانتصار لـ gRPC؛ في حالة استخدام كلاهما تنسيق البيانات الثنائية، تعادل.

الناتج الكلي

مجددًا، في حالة REST، كل شيء يعتمد على البروتوكول HTTP الأساسي والخادم.

في الحالة الافتراضية، REST مبني على HTTP/1.1، حتى أفضل خادم عالي الأداء لن يتغلب على أداء gRPC، خاصة عندما نضيف التكلفة الزائدة لتسلسل وتفكيك البيانات عند استخدام JSON. على الرغم من ذلك، عندما ننتقل إلى HTTP/2 يبدو الفرق مخفضًا.

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

  • نتيجة: في الحالة الافتراضية، gRPC؛ في حالة استخدام كلاهما البيانات الثنائية وHTTP/2، تعادل أو انتصار باهت لـ gRPC.

التعريفات

في هذا الجزء، سأصف كيف نعرّف رسائلنا وخدمتنا في كلتا الطريقتين.

في معظم تطبيقات REST، نعلن ببساطة طلباتنا وردودنا الفعل كطبقات أو كائنات، أو أي تركيبة يدعمها لغة معينة. ثم نعتمد على المكتبات المتوفرة لتسلسل وتفكيك JSON/XML/YAML، أو أي تنسيق نحتاجه.

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

لا توجد فروق كبيرة بين التنسيقات الثنائية وغير الثنائية لتطبيقات REST، حيث تكون القاعدة في كلتا الحالتين أكثر أو أقل متطابقة. بالنسبة للتنسيق الثنائي، نحدد كل شيء بالطريقة المطلوبة من قبل التنسيق المحدد.

إضافةً إلى ذلك، حددنا خدمة REST لدينا عبر طرق أو تعليقات من المكتبة الأساسية أو الإطار الزمني لدينا. الأداة مسؤولة أيضًا عن عرضها إلى العالم الخارجي مع الإعدادات الأخرى.

في حالة gRPC، لدينا Protobuf كافتراضي والواقع الوحيد لكتابة التعاريف. علينا أن نعلن عن كل شيء: الرسائل والخدمات والأساليب في ملفات .proto، لذا الأمر واضح تمامًا.

ثم نستخدم الأداة التي توفرها gRPC لإنشاء الكود لنا، وعلينا فقط تنفيذ طرقنا. بعد ذلك، يجب أن يعمل كل شيء كما هو مخطط له.

علاوة على ذلك، Protobuf يدعم الاستيراد لذا يمكننا توزيع الإعداد لدينا عبر ملفات متعددة بطريقة معقولة البساطة.

  • النتيجة: لا يوجد فائز هنا، فقط وصف ونصيحة مني: اختر الأسلوب الذي يناسبك أكثر.

سهولة التبني

في هذا الجزء، سأقارن الدعم المكتبة/الإطار الزمني لكل نهج في لغات البرمجة الحديثة.

بشكل عام، كل لغة برمجة (جافا، سكالا، بايثون) التي التقيت بها في حياتي القصيرة كمهندس نظم تحتوي على ما لا يقل عن 3 مكتبات/إطارات رئيسية لإنشاء تطبيقات تشبه REST، ناهيك عن عدد مماثل من المكتبات المخصصة لتحليل JSONs إلى كائنات/فصول.

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

باختصار، الدعم لتطبيقات أسلوب REST جيد على الأقل.

في سكالا، لدينا حتى أداة اسمها tapir — التي كنت متألقًا بكوني أحد المصورين لبعض الوقت. Tapir تتيح لنا تجريد خادم HTTP لدينا وكتابة نقاط الاتصال التي ستعمل لعدة خوادم.

gRPC نفسه يوفر مكتبة عميل لأكثر من 8 لغات برمجة شهيرة. غالبًا ما يكون هذا كافيًا حيث تحتوي هذه المكتبات على كل ما يلزم لجعل API gRPC. علاوة على ذلك، أنا على علم بوجود مكتبات توفر تجريدًا أعلى لجافا (عبر Spring Boot Starter) ولـScala.

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

  • النتيجة: REST، كما يتم اعتماده بشكل أوسع ولديه الكثير من المكتبات والإطارات المتعلقة به

دعم الأدوات

تمت التغطية للمكتبات والإطارات والحصص السوقية العامة أعلاه، لذا في هذا الجزء، أود تغطية الأدوات المحيطة بكلتا الأسلوبين. وهذا يعني أدوات للاختبارات، واختبارات الأداء/الإجهاد، والوثائق.

اختبارات التشغيل الآلي/الاختبارات

أولاً، في حالة REST، توجد أدوات لبناء اختبارات تشغيلية ضمن مكتبات وإطارات مختلفة أو هي أدوات منفصلة بناءً على هذا الغرض الوحيد، مثل REST-assured.

في حالة gRPC، يمكننا توليد سكراب واستخدامه للاختبارات. إذا أردنا أن نكون أكثر صرامة، يمكننا استخدام العميل المولد كتطبيق منفصل واستخدامه كأساس لاختباراتنا على الخدمة الحية الواقعية.

أما بالنسبة لدعم الأدوات الخارجية لـ gRPC، فأنا على علم بـ:

  • تطبيق Postman دعم gRPC
  • يمكن لعميل JetBrains HTTP المستخدم في برامج التصميم الخاصة بهم دعم gRPC ببعض التكوينات البسيطة

  • نتيجة واحدة: الانتصار لـ REST؛ ومع ذلك، يبدو أن الوضع يتحسن لـ gRPC.

اختبارات الأداء

هنا، لدى REST مزايا كبيرة، حيث تجعل الأدوات مثل JMeter أو Gatling اختبار الضغط على واجهات برمجة التطبيقات REST مهمة معقولة السهولة.

لسوء الحظ، لا يوجد لـ gRPC مثل هذا الدعم. أعرف أن الأشخاص من Gatling لديهم ملحق gRPC مُدرج في إصدار Gatling الحالي، لذا يبدو أن الوضع يتحسن.

ومع ذلك، حتى الآن، كان لدينا ملحق ومكتبة واحدة غير رسمية تسمى ghz. كل هذه الأشياء جيدة؛ إنها مجرد دعم غير متساوٍ مثل REST.

  • نتيجة الثانية: الانتصار لـ REST؛ ومع ذلك، يبدو أن الوضع يتحسن لـ gRPC مرة أخرى 😉

الوثائق

في حالة وثائق API، الانتصار مرة أخرى لـ REST مع OpenAPI و Swagger يتم تبنيهما على نطاق واسع في صناعة التكنولوجيا ويعتبران المعيار القياسي لا ريب فيه. تقريباً جميع المكتبات لـ REST يمكن أن تكشف عن وثائق swagger بجهد أقل بكثير أو فقط مباشرةً من غير صيانة.

لسوء الحظ، لا يوجد لـ gRPC شيء مثل هذا.

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

بشكل عام، ملفات .proto مع وصف API لدينا أكثر تفصيلًا ومكتظًا من الكود المسؤول عن جعل كود API REST لدينا، لذا ربما لا يحتاج إلى مزيد من الوثائق من gRPC. الإجابة التي أتركها لك.

  • النتيجة الثالثة: انتصار لـ REST؛ ومع ذلك، لا يزال السؤال حول وثائق gRPC مفتوحًا.

النتيجة الكلية:

A significant victory for REST


ملخص

جدول النتائج النهائي يبدو هكذا.


تتساوى النتائج بين كلا النمطين، مع ثلاثة انتصارات لكل منهما وفئة واحدة بدون فائز واضح.

لا يوجد رصاصة أثرية: فكر فقط في أي فئات قد تكون الأكثر أهمية لتطبيقك ثم اختر الطريقة التي فازت في معظمها – على الأقل هذه توصيتي.

بقولي، أجرب gRPC إذا استطعت، حيث عملت بشكل جيد في المشروع الأخير لي. قد يكون خيارًا أفضل من زميل REST العتيق.

إذا كنت تحتاج في أي وقت مساعدة في اختيار REST على gRPC أو التعامل مع أي نوع آخر من المشاكل التقنية، فقط اسألني. قد أكون قادرًا على المساعدة.

شكرًا لك على وقتك.

Source:
https://dzone.com/articles/grpc-vs-rest-comparison