تخطَّ إلى المحتوى

🏗️ شرح المايكروسيرفيس (Microservices)

التواصل عبر gRPC

الدرس 26 من 29· ⏱ 3 دقائق قراءة

لماذا نحتاج بديلاً عن REST؟

تعلّمنا في درس التواصل عبر HTTP أن REST هو الخيار الأسهل للتواصل المتزامن. لكنه يحمل تكلفة: كل طلب واستجابة نص JSON، وكل استدعاء يفتح اتصال HTTP/1.1 منفصلاً غالباً. عندما تتواصل عشرات الخدمات الداخلية مع بعضها آلاف المرات في الثانية — هذه التكلفة تتراكم.

gRPC هو إطار عمل RPC (Remote Procedure Call) طوّرته Google، مبني على HTTP/2 ويستخدم Protocol Buffers (protobuf) كصيغة تسلسل ثنائية بدل JSON النصي. الفكرة: تستدعي دالة في خدمة أخرى وكأنها دالة محلية عندك.

تعريف العقد بـ Protocol Buffers

بدل توثيق REST API بملف OpenAPI منفصل، عقد gRPC هو الكود نفسه — ملف .proto واحد يعرّف الرسائل والخدمة، ويُستخدم لتوليد كود العميل والخادم في أي لغة.

// order_service.proto
syntax = "proto3";

package orders;

service OrderService {
  // Unary RPC — طلب واحد، استجابة واحدة
  rpc GetOrder (GetOrderRequest) returns (Order);

  // Server Streaming — طلب واحد، دفق استجابات
  rpc WatchOrderStatus (GetOrderRequest) returns (stream OrderStatusUpdate);
}

message GetOrderRequest {
  string order_id = 1;
}

message Order {
  string order_id = 1;
  string status = 2;
  double total = 3;
}

message OrderStatusUpdate {
  string order_id = 1;
  string status = 2;
  int64 updated_at = 3;
}

💡 الأرقام بجانب كل حقل (= 1, = 2) ليست قيماً — هي مُعرّف موضع الحقل في الترميز الثنائي، ولهذا لا يمكن إعادة استخدام رقم حقل بعد حذفه في نسخة لاحقة من العقد.

يُترجم protoc (مترجم protobuf) هذا الملف تلقائياً لكود Client و Server في كل لغة تدعمها — TypeScript وGo وPython وJava وغيرها، فيمكن لخدمتين مكتوبتين بلغتين مختلفتين التواصل دون كتابة كود تسلسل يدوي.

الأنماط الأربعة للاستدعاء

gRPC Call Patterns:
  Unary:                 طلب واحد  استجابة واحدة (مثل REST التقليدي)
  Server Streaming:      طلب واحد  دفق استجابات (مثال: تتبع حالة طلب لحظياً)
  Client Streaming:      دفق طلبات  استجابة واحدة (مثال: رفع ملف على دفعات)
  Bidirectional Streaming: دفق طلبات  دفق استجابات (مثال: دردشة حية بين خدمتين)

استخدام الخدمة من خدمة أخرى

import { OrderServiceClient } from './generated/order_service';
import { credentials } from '@grpc/grpc-js';

// عميل مولَّد تلقائياً من order_service.proto
const orderClient = new OrderServiceClient(
  'order-service:50051',
  credentials.createInsecure(), // في الإنتاج: TLS دائماً
);

async function getOrder(orderId: string) {
  return new Promise((resolve, reject) => {
    orderClient.getOrder({ orderId }, (err, response) => {
      if (err) return reject(err);
      resolve(response);
    });
  });
}

متى تستخدم gRPC ومتى تستخدم REST؟

المعيارREST/JSONgRPC
التواصل الداخلي بين الخدماتمقبولمفضّل — أسرع وأخف
API عام للمطورين الخارجيينمفضّل — سهل الاستكشاف والتجربةيحتاج بوابة gRPC-Web إضافية
استدعاء مباشر من المتصفحمباشر عبر fetchغير مباشر — المتصفح لا يدعم HTTP/2 trailers، فيلزم طبقة gRPC-Web
Streaming ثنائي الاتجاهيحتاج WebSocket منفصلمدعوم أصلاً
قابلية القراءة أثناء التصحيحJSON نص عادي، يُقرأ بأي أداةثنائي — يحتاج أدوات مثل grpcurl

⚠️ المتصفح لا يستطيع التحكم بإطارات HTTP/2 الخام ولا يعرض الـ trailers، لذلك لا يمكن استدعاء خدمة gRPC مباشرة من كود JavaScript في المتصفح — الحل هو gRPC-Web، طبقة تُترجم الاستدعاءات عبر بوابة وسيطة (غالباً Envoy).

أشهر الأخطاء

  • استبدال REST بالكامل بـ gRPC لواجهة عامة موجّهة لعملاء خارجيين متعددين — REST أبسط وأوسع دعماً هناك
  • تغيير رقم حقل موجود في ملف .proto بعد النشر — يكسر التوافق مع العملاء القدامى
  • تجاهل TLS في الإنتاج لأن credentials.createInsecure() يعمل محلياً بسهولة

🎯 التالي: Service Mesh — إدارة التواصل بين الخدمات

شرح التواصل عبر gRPC — المايكروسيرفيس (Microservices) بالعربي
التواصل عبر gRPCالمايكروسيرفيس (Microservices) بالعربي · The Code Fix

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