المقدمة
الـ gRPC هي اختصار لـ Google Remote Procedure Call وهي تكنولوجيا بتخلي الـ Service تقدر تنادي الـ function اللي موجودة في Service تانية كأنها بتناديها عادي كـ Function Call، حتى لو الـ Service التانية دي مكتوبة بلغة برمجة مختلفة ومش موجودة على نفس الـ Machine!
بشكل أبسط يعني لو عندنا Service مكتوبة بـ Java و Service تانية مكتوبة بـ Python، نقدر نخلي الـ Python ينادي Function في الـ Java بسهولة.
في الـ Microservices لو كل Service بدأت تعمل Generate لـ Client Library عشان الـ Services التانية تستخدمها ، هنضطر نعمل Client Library بلغات برمجة مختلفة على حسب الـ Services التانية ، وده مش حاجة منطقية! وهنا بتيجي ميزة الـ gRPC في انها بتوفر Unified Framework وكمان Language Agnostic ، فاحنا بنقول ده الـ proto اللي عاوزها والـ Client بيستعمل الـ gRPC Framework في انه يبعتلنا الـ Proto ويستقبل الـ Proto كـ Response وخلاص.
الـ gRPC بيبدأ من الـ Schema ، بـ Define الـ APIs بتاعتي وبقول دول الـ Functions اللي عندي أو الـ Contracts بتاعتي ، وبحدد الـ Request/Response كـ proto واللي هي اختصار للـ Protocol Buffer.
الـ gRPC شغال إزاي؟
الـ gRPC بيعتمد على حاجة اسمها Protocol Buffers (Protobuf). دي زي JSON كده، بس أخف وأسرع، بتستخدمها علشان توصف شكل البيانات اللي رايحة واللي جاية.

فبدل ما نبعت JSON كبير ومليان تفاصيل، بنكتب ملف .proto نعرف فيه الـ Message والـ Functions اللي عاوزين نتبادلها بين الـ Client والـ Server.
فانا بقول عندي service x بتشمل الـ functions الآتية وكل function بتستقبل proto request وبترجع proto response وخلاص كده ، فمش محتاج باه احدد الـ params دي هتيجي من الـ query , url , body والـ complexity بتاعة الـ REST.
مثال سريع على ملف .proto:
syntax = "proto3";
service KitchenService {
rpc PrepareOrder (OrderRequest) returns (OrderResponse);
}
message OrderRequest {
int32 order_id = 1;
string meal = 2;
string extra = 3;
}
message OrderResponse {
bool ready = 1;
string note = 2;
}
gRPC Proto Definition
الـ compiler بعد كده بيطلع كود للـ (Client) والـ (Server) تلقائيًا بلغاتهم المكتوبة بيهم سواء Java / Go.
نقدر دلوقتي لو عندنا مثلًا DeliveryService بتنادي على الـ KitchenService يبقى عندنا حاجة شبه كده:
OrderRequest request = OrderRequest.newBuilder()
.setOrderId(123)
.setMeal("koshary")
.setExtra("spicy")
.build();
OrderResponse response = kitchenStub.prepareOrder(request);
والـ KitchenService لو مكتوبة بـ Go تكون شبه كده:
func (s *KitchenServer) PrepareOrder(ctx context.Context, req *pb.OrderRequest) (*pb.OrderResponse, error) {
fmt.Printf("Preparing order %d\n", req.OrderId)
return &pb.OrderResponse{Ready: true, Note: "Extra spicy added"}, nil
}gRPC vs RESTful APIs
Format
الـ gRPC بتعتمد على الـ Protocol Buffer ، وهو Efficient جدًا لانه بيستعمل Binary Format مش Human Readable Text فالكلام ده بيكون كحجم أقل بكتير جدًا فانت على الاقل بتوفر نص الـ Bytes اللي بتبعتها.
HTTP2
في الـ gRPC بيعتمدوا بشكل أساسي على الـ HTTP 2 كـ Standard عشان ياخدوا منه الـ Multiplexing ، ميزة الـ HTTP2 وموضوع الـ Multiplexing ان بدل ما الـ Order Service يجيلها 1,000 request وتبعتهم للـ shipping وبالتالي افتح 1,000 TCP Connection ، فانا فالـ HTTP 2 بفتح Channel واحدة وببعت الكلام ده في الـ Channel من خلال الـ Multiplexing فمش محتاج افتح 1,000 connection ويكون عندي كمية overhead كبيرة من الـ TCP. فهي TCP Connection واحدة وبنخليها keep-alive.
ومن ضمن الحاجات برضو الـ Header Compression ، فالـ gRPC اشتغل على انه يحسن كل الطرق الممكنة في الـ communication بين الـ Services وبعضها.
Streaming
الـ gRPC كذلك بتدعم الـ Streaming بسهولة .. شبه الـ web sockets ، فبدل معمل الـ pagination من خلال الطرق التقليدية ، اقدر دلوقتي افتح stream واشوف الـ orders in realtime. في حين ان تطبيق ده بالـ REST هيكون صعب جدًا.
استخدامات الـ gRPC
- الـ Microservices: لو عندنا نظام كبير متقسم لـ Services صغيرة، الـ gRPC بيخلي الـ Services دي تتكلم مع بعض بكفاءة.
- في الـ Mobile apps: لأنه خفيف وسريع جدًا.
- في الـ Real-time systems: زي الـ Chat apps أو Video streaming.
في الختام
الـ gRPC بيلمع وبيظهر أكتر في الـ Micro-services Arhcitecture وخصوصا لو فيه عندنا Services كتير ويهمنا نحل مشاكل الـ Network والـ Communication بينهم وبين بعض. ودي بعض الحالات اللي ممكن يكون مميز فيها وبيستخدم فيها:
Discussion