اگر چند سال گذشته را صرف توسعه API کرده باشید، به احتمال زیاد REST API اولین انتخاب شما بوده است. از ساخت یک وبسایت ساده گرفته تا توسعه اپلیکیشنهای موبایل و معماریهای مبتنی بر میکروسرویس،REST به یکی از رایجترین روشهای ارتباط میان کلاینت و سرور تبدیل شده است. سادگی، استفاده از HTTP و فرمت JSON باعث شدهاند که تقریبا تمام زبانهای برنامهنویسی و فریمورکهای محبوب از آن پشتیبانی کنند.
اما با بزرگتر شدن نرمافزارها، افزایش تعداد سرویسها و نیاز به پردازش حجم بیشتری از درخواستها، محدودیتهای REST نیز بیش از پیش خود را نشان دادند. ارسال مکرر دادههای متنی JSON، سربار پردازش، تاخیر در ارتباطات و نبود برخی قابلیتهای پیشرفته مانند Streaming دوطرفه، از جمله چالشهایی هستند که در پروژههای بزرگ و سامانههای توزیعشده اهمیت پیدا میکنند.
تصور کنید دهها یا حتی صدها سرویس مختلف باید در هر ثانیه هزاران بار با یکدیگر ارتباط برقرار کنند. در چنین شرایطی، حتی چند میلیثانیه تاخیر در هر درخواست میتواند در مقیاس کل سیستم به هزینهای قابل توجه از نظر زمان، مصرف منابع و تجربه کاربری تبدیل شود. به همین دلیل، شرکتهای بزرگ فناوری به دنبال راهکاری بودند که بتواند ارتباط میان سرویسها را سریعتر، بهینهتر و قابل اعتمادتر کند.
نتیجه این تلاش، فناوری gRPC بود، یک فریمورک متنباز که توسط گوگل توسعه یافت و بر پایه مفهوم Remote Procedure Call (RPC)، پروتکل HTTP/2 و قالب داده Protocol Buffers ساخته شده است. gRPC با حذف بسیاری از سربارهای موجود در REST، امکان برقراری ارتباطی سریع، کمحجم و تایپمحور را میان سرویسها فراهم میکند و به همین دلیل، امروزه در بسیاری از معماریهای مبتنی بر میکروسرویس، سیستمهای ابری و سرویسهای با کارایی بالا مورد استفاده قرار میگیرد.
در این مقاله ابتدا با مفهوم gRPC و نحوه عملکرد آن آشنا میشویم، سپس تفاوتهای آن با REST API را بررسی میکنیم، مزایا و محدودیتهای هر دو رویکرد را خواهیم دید و در نهایت مشخص خواهیم کرد که در چه شرایطی استفاده از gRPC میتواند انتخاب مناسبتری باشد.
gRPC چیست؟
gRPC یک فریمورک متنباز برای برقراری ارتباط میان سرویسها است که توسط گوگل توسعه داده شده و اکنون تحت مدیریت بنیاد Cloud Native Computing Foundation (CNCF) قرار دارد. این فناوری بر پایه مفهوم Remote Procedure Call (RPC) ساخته شده و به توسعهدهندگان اجازه میدهد توابع یک سرویس راه دور را به همان سادگی توابع محلی فراخوانی کنند.
به بیان ساده، در gRPC بهجای آنکه کلاینت یک درخواست HTTP به آدرس مشخصی ارسال کند و منتظر دریافت یک پاسخ JSON بماند، مستقیما متدی از سرویس مقصد را فراخوانی میکند. جزئیات مربوط به برقراری اتصال، ارسال داده، دریافت پاسخ و مدیریت ارتباط نیز توسط خود gRPC مدیریت میشوند، بنابراین توسعهدهنده میتواند بیشتر بر منطق برنامه تمرکز کند تا جزئیات پیادهسازی ارتباطات شبکه.
برای مثال، فرض کنید سرویسی برای مدیریت کاربران وجود دارد. در REST معمولا درخواستی مشابه نمونه زیر ارسال میشود:
GET /users/10
در مقابل، در gRPC کافی است متدی مانند GetUser() فراخوانی شود و شناسه کاربر به آن ارسال گردد. از دید برنامهنویس، این فراخوانی تفاوت چندانی با اجرای یک تابع معمولی ندارد، در حالی که در پشت صحنه، gRPC درخواست را به سرویس مقصد ارسال کرده و نتیجه را بازمیگرداند.
Remote Procedure Call (RPC) چیست؟
برای درک بهتر gRPC، ابتدا باید با مفهوم Remote Procedure Call یا به اختصار RPC آشنا شد.
RPC یک الگوی ارتباطی است که به یک برنامه اجازه میدهد تابع یا متدی را روی سیستمی دیگر اجرا کند، بدون آنکه نیاز باشد توسعهدهنده جزئیات مربوط به ارتباطات شبکه، ارسال بستههای داده یا مدیریت پاسخها را بهصورت دستی پیادهسازی کند.

در این مدل، کلاینت تنها متد مورد نظر و پارامترهای آن را مشخص میکند و بقیه مراحل بهصورت خودکار انجام میشوند. به همین دلیل، کار با RPC تا حد زیادی شبیه فراخوانی یک تابع محلی است، با این تفاوت که اجرای واقعی تابع روی یک سرور دیگر انجام میشود.
بهعنوان نمونه، فرض کنید متدی با نام GetUserById() روی یک سرور وجود دارد. در برنامه سمت کلاینت میتوان آن را به شکل زیر فراخوانی کرد:
GetUserById(10)
در ظاهر، این تنها یک فراخوانی ساده است، اما در پشت صحنه مراحل زیر رخ میدهد:
- پارامترها به قالبی قابل انتقال تبدیل میشوند.
- درخواست از طریق شبکه به سرور ارسال میشود.
- سرور متد مورد نظر را اجرا میکند.
- نتیجه دوباره به قالب قابل انتقال تبدیل میشود.
- پاسخ برای کلاینت ارسال شده و مانند خروجی یک تابع در اختیار برنامه قرار میگیرد.
تمام این فرایند بدون آنکه توسعهدهنده مستقیما با جزئیات ارتباطات شبکه درگیر شود، انجام میشود.
gRPC چگونه RPC را بهبود داده است؟
اگرچه مفهوم RPC قدمتی چند دهساله دارد، اما نسخههای قدیمی آن معمولا وابسته به زبانهای برنامهنویسی خاص بودند، کارایی محدودی داشتند یا پیادهسازی آنها پیچیده بود.
gRPC این مفهوم را با استفاده از فناوریهای مدرن بازطراحی کرده است. مهمترین ویژگیهایی که gRPCرا از پیادهسازیهای قدیمی RPC متمایز میکنند عبارتاند از:
- استفاده از HTTP/2 برای برقراری ارتباط سریعتر و پایدارتر.
- استفاده از Protocol Buffers بهجای JSON برای کاهش حجم دادهها و افزایش سرعت پردازش.
- تولید خودکار کد برای زبانهای مختلف برنامهنویسی.
- پشتیبانی از ارتباطات Streaming در حالتهای مختلف.
- امکان برقراری ارتباط میان سرویسهایی که با زبانهای برنامهنویسی متفاوت توسعه یافتهاند.
به همین دلیل، gRPC امروزه یکی از گزینههای اصلی برای پیادهسازی ارتباط میان سرویسها، بهویژه در معماریهای مبتنی بر میکروسرویس، محسوب میشود.
gRPC چگونه کار میکند؟
یکی از مهمترین تفاوتهای gRPC با REST API، نحوه تعریف و برقراری ارتباط میان کلاینت و سرور است. در REST معمولا توسعهدهنده باید آدرسهای مختلف (اندپوینتها) نوع درخواستها، ساختار دادههای JSON و مستندات API را بهصورت جداگانه طراحی و نگهداری کند. اما در gRPC همهچیز از یک قرارداد (Contract) مشترک آغاز میشود.
این قرارداد در قالب فایلهایی با پسوند .proto تعریف میشود. در این فایل، توسعهدهنده مشخص میکند که چه سرویسهایی وجود دارند، هر سرویس چه متدهایی ارائه میدهد و ورودی و خروجی هر متد از چه ساختاری تشکیل شده است. سپس gRPC با استفاده از این فایل، کدهای موردنیاز برای کلاینت و سرور را بهصورت خودکار تولید میکند. به همین دلیل، هر دو سمت ارتباط دقیقا از یک تعریف مشترک استفاده میکنند و احتمال بروز ناسازگاری میان آنها به حداقل میرسد.
مراحل برقراری ارتباط در gRPC
بهطور کلی، یک درخواست در gRPC مراحل زیر را طی میکند:
- توسعهدهنده سرویسها و پیامها را در یک فایل
.protoتعریف میکند. - ابزار Protocol Buffers Compiler (protoc) این فایل را پردازش کرده و کدهای لازم را برای زبان برنامهنویسی موردنظر تولید میکند.
- سرور متدهای تولیدشده را پیادهسازی کرده و آماده دریافت درخواستها میشود.
- کلاینت از کلاسهای تولیدشده استفاده میکند و متدهای سرویس را مانند توابع معمولی فراخوانی میکند.
- gRPC دادهها را به فرمت باینری Protocol Buffers تبدیل کرده و از طریق HTTP/2 برای سرور ارسال میکند.
- سرور درخواست را پردازش کرده و پاسخ را دوباره در قالب Protocol Buffers به کلاینت بازمیگرداند.
تمام این مراحل بدون آنکه توسعهدهنده مستقیما با جزئیات مربوط به Serialization، مدیریت سوکتها یا ارسال و دریافت دادهها درگیر شود، انجام میشوند.
نقش فایلهای Proto
هسته اصلی هر پروژه gRPC فایلهای Proto هستند. این فایلها نهتنها ساختار دادهها را مشخص میکنند، بلکه سرویسها و متدهای قابل فراخوانی را نیز تعریف میکنند. به همین دلیل، فایل Proto را میتوان قرارداد مشترک میان کلاینت و سرور دانست.
نمونهای از یک فایل Proto به شکل زیر است:
syntax = "proto3";
service UserService {
rpc GetUser(UserRequest) returns (UserResponse);
}
message UserRequest {
int32 id = 1;
}
message UserResponse {
int32 id = 1;
string name = 2;
string email = 3;
}
در این مثال، سرویس UserService تنها یک متد با نام GetUser دارد. این متد یک شئ از نوع UserRequest را دریافت کرده و در پاسخ، شئی از نوع UserResponse برمیگرداند.
پس از اجرا، protoc کلاسها و متدهای لازم را برای زبان برنامهنویسی انتخابشده تولید میکند، بنابراین دیگر نیازی به نوشتن بخش بزرگی از کدهای تکراری مربوط به ارتباط میان کلاینت و سرور وجود نخواهد داشت.
تولید خودکار کد (Code Generation)
یکی از مهمترین قابلیتهای gRPC، تولید خودکار کد است. کافی است فایل Proto یکبار تعریف شود، سپس gRPC میتواند برای زبانهایی مانند جاوا، C#، Go، پایتون، جاوااسکریپت، تایپ اسکریپت، PHP، روبی و بسیاری از زبانهای دیگر، کلاسهای موردنیاز را ایجاد کند.
این ویژگی چند مزیت مهم به همراه دارد:
- کاهش حجم کدهای تکراری
- جلوگیری از اختلاف میان کلاینت و سرور
- کاهش خطاهای ناشی از تغییر ساختار دادهها
- توسعه آسانتر سرویسها در تیمهای بزرگ
در واقع، فایل Proto به یک منبع واحد (Single Source of Truth) تبدیل میشود و تمام بخشهای سیستم بر اساس همین قرارداد مشترک توسعه پیدا میکنند.
چرا gRPC از HTTP/2 استفاده میکند؟
برخلاف REST که معمولا بر پایه HTTP/1.1 پیادهسازی میشود، gRPC بهصورت پیشفرض از HTTP/2 استفاده میکند.
HTTP/2 امکاناتی را در اختیار gRPC قرار میدهد که دستیابی به آنها در HTTP/1.1 دشوار یا پرهزینه است. از جمله:
- ارسال همزمان چندین درخواست روی یک اتصال (Multiplexing)
- فشردهسازی سربرگها برای کاهش حجم دادههای ارسالی
- نگهداشتن اتصال میان کلاینت و سرور بدون نیاز به ایجاد اتصال جدید برای هر درخواست
- پشتیبانی ذاتی از Streaming
ترکیب HTTP/2 با قالب باینری Protocol Buffers باعث میشود gRPC در بسیاری از سناریوها، بهویژه ارتباط میان سرویسهای داخلی، عملکردی سریعتر و مصرف منابع کمتری نسبت به REST API داشته باشد.
Protocol Buffers چیست؟
یکی از مهمترین دلایلی که gRPC عملکردی سریعتر از بسیاری از APIهای مبتنی بر REST دارد، استفاده از Protocol Buffers یا به اختصار Protobuf است. این تکنولوژی یک مکانیزم سریالسازی (Serialization) داده است که توسط گوگل توسعه یافته و به جای استفاده از فرمتهای متنی مانند JSONیا XML، دادهها را به شکل باینری و فشرده ذخیره و منتقل میکند.

به بیان ساده، زمانی که یک کلاینت قصد ارسال اطلاعات به سرور را دارد، این اطلاعات باید به قالبی تبدیل شوند که امکان انتقال آنها از طریق شبکه وجود داشته باشد. این فرایند را Serialization مینامند. در سمت مقابل نیز سرور باید دادههای دریافتی را دوباره به اشیای قابل استفاده در برنامه تبدیل کند که به این فرایند Deserialization گفته میشود.
در REST معمولا این تبدیل با استفاده از JSON انجام میشود، اما gRPC از Protobuf استفاده میکند که هم حجم کمتری دارد و هم سرعت پردازش آن بیشتر است.
تفاوت JSON و Protocol Buffers
برای درک بهتر تفاوت این دو، فرض کنید قصد دارید اطلاعات یک کاربر را ارسال کنید.
در JSON، دادهها ممکن است به شکل زیر باشند:
{
"id": 1,
"name": "John",
"email": "John@example.com"
}
در این ساختار، علاوه بر مقادیر، نام فیلدها نیز در هر درخواست ارسال میشوند. اگرچه این موضوع باعث خوانایی بیشتر دادهها میشود، اما حجم اطلاعات ارسالی را نیز افزایش میدهد.
در مقابل، در Protobuf ابتدا ساختار داده فقط یک بار در فایل .proto تعریف میشود:
message User {
int32 id = 1;
string name = 2;
string email = 3;
}
پس از آن، هنگام ارسال داده، دیگر نیازی به ارسال نام فیلدها نیست و اطلاعات بهصورت باینری و بر اساس شماره فیلدها کدگذاری میشوند. همین موضوع باعث کاهش قابل توجه حجم داده و افزایش سرعت پردازش میشود.
شماره فیلدها چه کاربردی دارند؟
ممکن است این سوال پیش بیاید که اعدادی مانند 1 یا 2 در فایل Proto چه معنایی دارند. این اعداد شناسه یا Field Number هر فیلد هستند. هنگام تبدیل داده به قالب باینری، Protobuf از این شمارهها برای شناسایی فیلدها استفاده میکند، نه از نام آنها.
برای مثال:
message User {
int32 id = 1;
string name = 2;
string email = 3;
}
در این مثال:
- Id دارای شماره ۱ است.
- name دارای شماره ۲ است.
- email دارای شماره ۳ است.
اگر در آینده فیلدی مانند phone به این پیام اضافه شود، کافی است شماره جدیدی برای آن در نظر گرفته شود:
string phone = 4;
به همین دلیل، Protobuf از Backward Compatibility و Forward Compatibility پشتیبانی مناسبی دارد و تغییرات ساختار داده معمولا باعث از کار افتادن نسخههای قدیمیتر سرویس نمیشوند، البته به شرط آنکه شماره فیلدهای قبلی تغییر نکنند یا دوباره مورد استفاده قرار نگیرند.
مزایای استفاده از Protocol Buffers
استفاده از Protobuf تنها به کاهش حجم دادهها محدود نمیشود، بلکه مزایای دیگری نیز به همراه دارد:
- سرعت بیشتر: تبدیل دادهها به قالب باینری و پردازش آنها سریعتر از JSON انجام میشود.
- حجم کمتر: حذف نام فیلدها و استفاده از قالب باینری باعث کاهش حجم بستههای ارسالی میشود.
- تایپ ایمن (Type Safety): نوع هر فیلد از ابتدا مشخص است و احتمال بروز خطاهای ناشی از دادههای نامعتبر کاهش مییابد.
- پشتیبانی از زبانهای مختلف: یک فایل Proto میتواند برای زبانهای برنامهنویسی گوناگون کد تولید کند.
- نسخهبندی آسانتر: اضافه کردن فیلدهای جدید بدون شکستن نسخههای قبلی معمولا امکانپذیر است.
آیا Protobuf فقط در gRPC استفاده میشود؟
خیر. اگرچه Protobuf یکی از اجزای اصلی gRPC محسوب میشود، اما استفاده از آن به gRPC محدود نیست.
بسیاری از سیستمهای توزیعشده، پیامرسانها ( (Message Broker، ابزارهای ذخیرهسازی داده و حتی برخی سرویسهای ابری نیز از Protocol Buffers برای ذخیره یا انتقال داده استفاده میکنند. بنابراین، Protobuf را میتوان یک فناوری مستقل دانست که gRPC برای افزایش کارایی خود از آن بهره میبرد.
مزایا gRPC
در ادامه مهمترین مزایای gRPC را بررسی میکنیم.
۱. عملکرد و سرعت بالاتر
یکی از مهمترین دلایل استفاده از gRPC، سرعت بالای آن است. استفاده از دادههای باینری به جای JSON و همچنین بهرهگیری از HTTP/2 باعث میشود حجم دادههای ارسالی کاهش یابد و پردازش درخواستها سریعتر انجام شود. این تفاوت شاید در یک API ساده چندان محسوس نباشد، اما در سیستمهایی که روزانه میلیونها درخواست را پردازش میکنند، تاثیر قابل توجهی بر مصرف منابع و زمان پاسخگویی خواهد داشت.
۲. کاهش حجم دادههای ارسالی
JSON فرمت بسیار خوانایی است، اما همین خوانایی باعث افزایش حجم دادهها میشود، زیرا نام تمام فیلدها در هر درخواست تکرار میشوند. در مقابل، Protobuf دادهها را به صورت باینری و فشرده ارسال میکند. در نتیجه:
- حجم بستههای شبکه کاهش پیدا میکند.
- پهنای باند کمتری مصرف میشود.
- انتقال داده سریعتر انجام میشود.
۳. تولید خودکار کد
در gRPC تنها کافی است یک فایل Proto نوشته شود. سپس ابزارهای gRPC کلاسها، مدلها و Stubهای موردنیاز را برای زبانهای مختلف تولید میکنند.
این قابلیت مزایای متعددی دارد:
- کاهش کدنویسی تکراری
- جلوگیری از ناسازگاری میان کلاینت و سرور
- توسعه سریعتر API
- نگهداری آسانتر پروژه
۴. تایپ ایمن (Type Safety)
در REST معمولا ساختار دادهها بر اساس مستندات یا قراردادهای تیمی مشخص میشود و در بسیاری از موارد، خطاهای مربوط به نوع داده تنها هنگام اجرای برنامه آشکار میشوند.
اما در gRPC، تمام پیامها و سرویسها از ابتدا در فایل Proto تعریف شدهاند. بنابراین نوع هر فیلد مشخص است و بسیاری از خطاها پیش از اجرای برنامه یا هنگام تولید کد شناسایی میشوند.
۵. پشتیبانی از Streaming
یکی از قابلیتهایی که gRPC را از REST متمایز میکند، پشتیبانی داخلی از Streaming است.
gRPC چهار نوع ارتباط را پشتیبانی میکند:
- Unary RPC: یک درخواست و یک پاسخ
- Server Streaming: یک درخواست و چند پاسخ از سمت سرور
- Client Streaming: چند درخواست از سمت کلاینت و یک پاسخ
- Bidirectional Streaming: ارسال و دریافت همزمان داده از هر دو سمت
این قابلیت در توسعه سیستمهایی مانند پیامرسانها، داشبوردهای لحظهای، سامانههای مانیتورینگ و پردازش دادههای Real-time بسیار کاربردی است.
۶. مناسب برای معماری میکروسرویس
در معماریهای مبتنی بر Microservices، دهها یا حتی صدها سرویس بهطور مداوم با یکدیگر در ارتباط هستند.
در چنین شرایطی، سرعت، حجم داده و پایداری ارتباط اهمیت زیادی پیدا میکند. به همین دلیل بسیاری از شرکتهای بزرگ مانند گوگل از gRPC برای ارتباط میان سرویسهای داخلی خود استفاده میکنند.
۷. پشتیبانی از زبانهای برنامهنویسی مختلف
یکی از نقاط قوتgRPC، چندسکویی بودن آن است.
یک سرویس میتواند با Go نوشته شده باشد، کلاینت با Java توسعه داده شود و سرویس دیگری با پایتون یا C# با همان API ارتباط برقرار کند. کافی است همه آنها از فایل Proto مشترک استفاده کنند.
معایب gRPC
با وجود تمام مزایای گفتهشده، gRPC راهحل مناسبی برای همه پروژهها نیست. پیش از انتخاب آن، بهتر است محدودیتهای آن نیز در نظر گرفته شوند.
۱. خوانایی کمتر دادهها
دادههای JSON بهراحتی توسط انسان قابل خواندن هستند و حتی بدون ابزار خاص میتوان محتوای آنها را بررسی کرد.
اما پیامهای Protobuf به صورت باینری منتقل میشوند و بدون ابزار مناسب قابل مشاهده نیستند. این موضوع اشکالزدایی (Debugging) را تا حدی دشوارتر میکند.
۲. مناسب نبودن برای APIهای عمومی
بسیاری از APIهای عمومی برای استفاده در مرورگرها یا توسط توسعهدهندگان شخص ثالث منتشر میشوند. در چنین شرایطی، REST به دلیل استفاده از HTTP و JSON همچنان گزینه مناسبتری است، زیرا تقریبا هر ابزار یا زبان برنامهنویسی میتواند بدون تنظیمات خاص با آن ارتباط برقرار کند.
۳. محدودیت در پشتیبانی مستقیم مرورگرها
مرورگرها به صورت مستقیم از gRPC استاندارد پشتیبانی نمیکنند. به همین دلیل برای ارتباط برنامههای تحت وب با سرویسهای gRPC معمولا از راهکارهایی مانند gRPC-Web استفاده میشود. این موضوع باعث میشود پیادهسازی Frontend نسبت به REST کمی پیچیدهتر باشد.
۴. پیچیدگی بیشتر در شروع پروژه
راهاندازی یک پروژه gRPC معمولا شامل نصب ابزارهای لازم، تعریف فایلهای Proto و تولید کد است. بنابراین برای پروژههای کوچک ممکن است این فرایند نسبت به ساخت یک REST API ساده، زمان بیشتری نیاز داشته باشد.
مقایسه gRPC و REST API
| REST API | gRPC | ویژگی |
|---|---|---|
| HTTP | HTTP/2 | پروتکل |
| JSON | Protobuf | فرمت داده |
| مناسب | بسیار بالا | سرعت |
| بیشتر | کم | حجم داده |
| ❌ ندارد (بهصورت پیشفرض) | ✅ دارد | استریم |
| بالا (متنی) | پایین (باینری) | خوانایی |
| APIهای وب و عمومی | میکروسرویسها و سیستمهای پرسرعت | مناسب برای |
جمعبندی
gRPCرا نمیتوان جایگزین مطلق REST API دانست. هر دو فناوری برای حل مسائل متفاوتی طراحی شدهاند و انتخاب میان آنها به نیازهای پروژه بستگی دارد.
اگر هدف، توسعه APIهایی ساده، عمومی و قابل استفاده در مرورگر باشد،REST همچنان یکی از بهترین گزینهها است. اما زمانی که سرعت، کارایی، ارتباط میان سرویسها و مقیاسپذیری اهمیت بیشتری پیدا
میکنند، gRPC با تکیه بر HTTP/2 ،بافرهای پروتکل و تولید خودکار کد میتواند انتخاب هوشمندانهتری باشد.
در حال دریافت نظرات از سرور، لطفا منتظر بمانید
در حال دریافت نظرات از سرور، لطفا منتظر بمانید