کدام بهتر است SignalR یا grpc
SignalR و gRPC
چندی پیش، زمانی که ASP.NET Core حتی وجود نداشت، مایکروسافت یک کتابخانه برای ASP.NET مبتنی بر .NET Framework ایجاد کرد که ارتباط دو طرفه بین کلاینت ها و سرور را در زمان واقعی امکان پذیر می کرد. این کتابخانه SignalR نام داشت.
هدف این کتابخانه ساده سازی اجرای پروتکل های ارتباطی استانداردی بود که معمولاً برای این نوع ارتباط استفاده می شد. این پروتکل ها شامل WebSocket، long polling و server-send events بود.
هر یک از این پروتکل ها را می توان به طور مستقیم مورد استفاده قرار داد، اما استفاده از هیچ یک به تنهایی آسان نبود. SingnalR با پنهان کردن تمام جزئیات پیاده سازی ، کار را آسان کرد.
با معرفی ASP.NET Core نسخه 2.1، این کتابخانه به طور کامل بازنویسی شد و به بخشی استاندارد از ASP.NET Core تبدیل شد.
gRPC یک پروتکل ارتباطی است که در ابتدا توسط گوگل توسعه داده شد. برخلاف SignalR، از پروتکلهای موجود استفاده نمیکند. این یک پروتکل کاملا مستقل است که از ویژگی های جدید HTTP/2 استفاده می کند که به طور کلی در سال 2015 در دسترس قرار گرفت.
پیاده سازی gRPC در اکثر زبان های برنامه نویسی اصلی موجود است. و از آنجایی که ASP.NET Core 3.0 منتشر شد، به بخشی جدایی ناپذیر از ASP.NET Core تبدیل شد، درست مانند SignalR
هر دوی این فناوری ها بسیار مفید هستند و می توان از آنها برای اهداف مشابهی استفاده کرد. اینکه یکی بهتر از دیگری است یا نه، صرفاً به زمینه کاری که انجام میدهید بستگی دارد.
امروز، نگاهی به مزایا و معایب هر یک از این فناوریها در زمینههای مختلف خواهیم داشت تا بتوانید برای تصمیمگیری در مورد استفاده از کدام یک مجهزتر باشید.
جاهایی که سیگنال آر gRPC را شکست میدهد
بدون نیاز به استفاده از HTTP/2 یعنی تقریباً در همه جا کار می کند
بدون HTTP/2، نمی توانید gRPC داشته باشید. این بدان معنی است که همه سیستم ها نمی توانند از آن استفاده کنند. اگر کلاینت یا برنامه سروری که روی آن کار میکنید روی سیستمی میزبانی میشود که از HTTP/2 پشتیبانی نمیکند، هیچ کاری نمیتوانید انجام دهید تا کار کند.
SignalR، از سوی دیگر، با HTTP اولیه کار می کند. به همین دلیل است که تقریباً در هر سیستمی قابل استفاده است.
البته همه سیستم ها نمی توانند از پروتکل WebSocket استفاده کنند. بنابراین ممکن است در برخی تنظیمات نتوانید از SignalR به کارآمدترین روش استفاده کنید. اما دقیقاً به همین دلیل است که دو پروتکل بازگشتی دارد – server-send events و long polling.
و این واقعیت که SignalR از HTTP/2 استفاده نمی کند به این معنی نیست که عملکرد کمتری نسبت به gRPC دارد. بله، HTTP/2 مزایای عملکردی زیادی مانند هدرهای فشرده را ارائه می دهد که عملکرد را افزایش می دهد. و مکانیسم پیامرسانی مورد استفاده توسط gRPC، بافر پروتکل، پیامها را به شیوهای کارآمد سریالسازی میکند و بار را تا حد ممکن کوچک میکند، که عملکرد را حتی بیشتر افزایش میدهد.
با این حال، SignalR، زمانی که با WebSocket استفاده می شود، از نظر کارایی قابل مقایسه است. اول از همه، فقط از هدر HTTP برای برقراری اتصال اولیه استفاده می کند، بنابراین فشرده سازی هدر ارائه شده توسط HTTP/2 تقریباً بی ربط است. ثانیاً، میتوان آن را برای استفاده از پروتکل JSON باینری اختصاصی به نام MessagePack پیکربندی کرد، که درست مانند بافر پروتکل، به میزان قابل توجهی اندازه بار را کاهش میدهد و بنابراین عملکرد را بهبود میبخشد.
از نظر عملکرد، SignalR و gRPC قابل مقایسه هستند. و هر دوی آنها استانداردهای ارتباطی مبتنی بر HTTP را شکست دادند
رویدادها می توانند توسط یک کلاینت یا سرور آغاز شوند
یکی از محدودیتهای gRPC این است که هنوز تا حد زیادی شبیه به یک مدل استاندارد response-request استفاده شده توسط HTTP است. فقط مشتری می تواند رویدادها را آغاز کند. سرور فقط می تواند به آنها پاسخ دهد.
البته برای این مورد یک راه حل وجود دارد. gRPC میتواند از استریم سرور استفاده کند، جایی که کلاینت درخواست اولیه را ارسال میکند و سپس هم کلاینت و هم سرور جریان را باز نگه میدارند، بنابراین سرور میتواند پیامها را در هنگام شروع یک اقدام خاص در آن قرار دهد.
اما اجرای این باید نسبتاً ناشیانه باشد. تماس های استریم برای استفاده به این صورت طراحی نشده اند. شما باید حلقه لوپی را به کلاینت و سرور اضافه کنید و باید وضعیت اتصال را به صورت دستی مدیریت کنید. بعلاوه شما باید این کار را برای هر متد مجزایی که نیاز به برقراری ارتباط هر دو طرفه دارد انجام دهید.
از طرف دیگر، با SignalR، تنها کاری که باید از مشتری انجام دهید ارسال درخواست اتصال اولیه است. پس از این، هم مشتری و هم سرور می توانند با استفاده از هر یک از endpointهای یکدیگر، پیام هایی را برای یکدیگر ارسال کنند. تنها کاری که باید انجام دهید این است که متدهایی را در سمت سرور اضافه کنید و شنوندگان رویداد نامگذاری شده را در سمت مشتری اضافه کنید. اتصال می تواند به طور نامحدود باز بماند. خود کتابخانه SignalR با ارسال ضربان قلب یا heartbeats در فواصل زمانی منظم و با تلاش برای اتصال مجدد خودکار در صورت قطع شدن اتصال، وضعیت اتصال را برای شما مدیریت می کند.
و درست مانند gRPC، SignalR کاملاً قادر است دادههای بلادرنگ را هم به سرور و هم از سرور پخش کند.
بدون نیاز به نوشتن هیچ گونه قرارداد ارتباطی و تولید کد از آنها
برای فعال کردن ارتباط gRPC، باید یک proto file بنویسید که حاوی تعاریف سرویسهای gRPC و تمام رویههای راه دور در این سرویسها باشد که کلاینت ها میتوانند با آنها تماس بگیرند. هنگامی که این کار انجام شد، باید یک ابزار خاص زبان را برای تولید کدی که با این تعاریف مطابقت دارد اجرا کنید. و تنها پس از آن می توانید شروع به نوشتن منطق واقعی کنید.
با SignalR، لازم نیست هیچ یک از این کارها را انجام دهید. تنها کاری که باید انجام دهید این است که هر گونه تعاریف متد دلخواه را در برنامه سمت سرور خود بنویسید و کنترل کننده های پیام نامگذاری شده را روی کلاینت خود بنویسید.
البته، این بدون مشکلات بالقوه خودش نیست. به عنوان مثال، شما باید بیشتر مراقب باشید که نام متد ها هم در کلاینت و هم در سرور یکسان نوشته شود. اما با این وجود، عدم نیاز به نوشتن یک قرارداد به طور واضح تعریف شده و عدم تکیه بر ابزارهای مختلف برای تولید کد بر اساس این قرارداد، به طور قابل توجهی روند توسعه را سرعت می بخشد.
جایی که gRPC SignalR را شکست می دهد
نسخه API بسیار ساده تر
حتی اگر زمانی که از gRPC استفاده می کنید، باید یک قرارداد صریح بین کلاینت و سرور بنویسید، این همیشه یک نقطه ضعف نیست. به عنوان مثال، نحوه طراحی فرمت proto به شما امکان می دهد به راحتی نسخه API را اعمال کنید.
هنگام تعریف ساختار پیام ها در یک فایل proto، از شما خواسته می شود که به هر یک از فیلدهای خود یک عدد صحیح منحصر به فرد بدهید. و این مکانیسم چیزی است که نسخه API را آسان می کند. بیایید سناریویی را تصور کنیم که به ما کمک می کند تا ببینیم چرا چنین است.
در اولین نسخه سرویس gRPC خود، یک تعریف پیام دارید که شامل دو فیلد است - request_id و payload_collection. این فیلدها به ترتیب شماره 1 و 2 را به خود اختصاص داده اند. اکنون، برای نسخه دوم خود، تصمیم گرفته ایم یک فیلد جدید، timestamp اضافه کنیم و عدد 3 را به آن اختصاص دهیم.
تا زمانی که هیچ یک از فیلدها را با شمارههای موجود تغییر ندهیم، کلاینتهایی که این بهروزرسانی را دریافت نکردهاند همچنان با تعریف پیام جدید کار خواهند کرد. اگر این تعریفی از یک شی response است که سرور به کلاینت ارسال می کند، کلاینت به سادگی فیلد جدید را نادیده می گیرد، زیرا فیلد با شماره 3 در تعریف اولیه خود مشخص نشده است. اگر این یک شی request بود، کلاینت دو فیلد اول را پر میکرد و فیلد شماره 3 یک مقدار پیشفرض در سمت سرور داده میشد.
در هر صورت، هم کلاینت و هم سرور همچنان کار خواهند کرد. نکته کلیدی این است که فیلدها را با اعداد موجود تغییر ندهید.
SignalR هیچ کدام از این ها را ندارد. البته، هیچ چیزی شما را از پیادهسازی مکانیسم نسخهسازی API خود که شبیه به این است، باز نمیدارد. اما با gRPC، شما قبلاً چنین مکانیزمی را در اختیار دارید، بنابراین نیازی به اختراع مجدد چرخ ندارید.
کتابخانه ها تقریباً به هر زبانی موجود است
اگرچه SignalR منبع باز است، اما همچنان فناوری اختصاصی مایکروسافت است. و به همین دلیل است که سرور SignalR فقط میتواند به زبانهای پشتیبانی شده ی خود مایکروسافت سرویس دهد که عمدتاً C#است، اگرچه استفاده از F# نیز پشتیبانی میشود.
کلاینت های SignalR همچنین فقط به تعداد محدودی از زبان ها قابل نوشتن هستند. در زمان نگارش این مقاله، فقط کلاینت های دات نت، جاوا اسکریپت و جاوا پشتیبانی می شدند. البته، میتوانید با استفاده از WebSocket خالص، کلاینت خود را به هر زبانی بنویسید، اما اگر بخواهید این کار را انجام دهید، تمام مزایای استفاده از SignalR را از دست خواهید داد.
از طرف دیگر، gRPC یک استاندارد باز است. و به همین دلیل است که در بسیاری از زبان های محبوب در دسترس است. این هم برای کلاینت و هم برای سرور صدق می کند.
کاربرد آسانتر در معماری میکروسرویس
حوزه دیگری که در آن gRPC سیگنال آر را به صورت دستی شکست می دهد، ارتباط بین میکروسرویس ها و کانتینرها است.
سازمانهای بیشتری از شر برنامههای یکپارچه بزرگ خلاص میشوند و آنها را به اجزای کوچکتری تقسیم میکنند که میتوانند به صورت جداگانه اجرا و بهروزرسانی شوند. با این حال، این مؤلفه ها هنوز یک برنامه کاربردی توزیع شده بزرگ را تشکیل می دهند. و به همین دلیل است که باید یک مکانیسم کارآمد برای برقراری ارتباط آنها با یکدیگر وجود داشته باشد.
اشکال مختلفی از مکانیسم های فراخوانی متدهای از راه دور (RPC) به طور سنتی برای این منظور استفاده می شود. آنها معمولاً کارآمدتر از HTTP هستند، زیرا داده های زیادی در هدرها ندارند. همچنین، آنها مجبور نیستند استانداردهای رایج قدیمی را رعایت کنند و می توانند کاملاً اختصاصی باشند. مکانیزم Azure Service Fabric Remoting نمونه ای از این موارد است.
gRPC نیاز به استفاده از مکانیزم های اختصاصی RPC را برای انواع مختلف فناوری ها از بین برد. این یک استاندارد باز است، بنابراین هر سیستمی می تواند از آن استفاده کند. و بسیار کارآمد است، زیرا در روی HTTP/2 اجرا می شود.
از سوی دیگر، SignalR برای برقراری ارتباط میکروسرویس ها با یکدیگر به اندازه کافی کارآمد نخواهد بود. حتی اگر به شما امکان میدهد کدی بنویسید که به نظر میرسد کلاینت و سرور از راه دور متدهای یکدیگر را فراخوانی میکنند سیگتال آر یک ارتباط دائمی بین مشتری و سرور برقرار می شود. و این ارتباط با ارسال پیام های ضربان قلب کوچک از هر دو طرف حفظ می شود.
اگر یک برنامه توزیع شده با تعداد زیادی جز مستقل دارید، تصور کنید اگر همه اجزای جداگانه تعدادی اتصال دائمی را برای برقراری ارتباط با یکدیگر باز کنند، چقدر از پهنای باند استفاده می شود. از سوی دیگر، با gRPC، هر داده ای تنها زمانی رد و بدل می شود که چنین تبادلی مورد نیاز باشد. تنها زمانی که به اتصال طولانی مدت نیاز دارید، زمانی است که از استریم ها استفاده می کنید. اما حتی در این صورت، پس از انتقال تمام داده ها، جریان را می بندید.
جمع بندی
SignalR و gRPC هر دو مکانیسم های ارتباطی عالی هستند که هر توسعه دهنده نرم افزار Microsoft-stack باید آنها را بیاموزد. و هیچ کدام بهتر از دیگری نیست. فقط سناریوهای خاصی وجود دارد که به نفع استفاده از یک سناریو خاص است.
به عنوان مثال، اگر نیاز به ساخت چیزی دارید که سرور به طور منظم با مشتری ارتباط برقرار کند، SignalR بهتر خواهد بود. از طرف دیگر، اگر در حال ساخت یک برنامه کاربردی توزیع شده بزرگ با قطعات متحرک زیاد هستید، gRPC مکانیسم بهتری برای ارتباط آن قطعات با یکدیگر خواهد بود.

دیدگاه کاربران