اتاق دانشتکنولوژیدانشنامهدواپسسایر

مقایسه SSE و WebSockets و هر آنچه در رابطه با آنها باید بدانید

در این متن، قصد داریم نگاهی دقیق‌تر به Server Sent Events (یا به اختصار SSE) و WebSockets داشته باشیم. هر دو رویکردهای خوب و آزمایش‌شده‌ای برای تبادل داده هستند. ابتدا با توضیح مختصری از هر دو ابزار شروع می‌کنیم – آن‌ها چه هستند و چه چیزی ارائه می‌دهند؟ سپس آن‌ها را بر اساس هشت دسته که به نظر ما برای سیستم‌های امروزی حیاتی هستند، مقایسه می‌کنیم.

دسته‌بندی‌ها به شرح زیر هستند:

  • جهت ارتباط (Communication Direction)
  • پروتکل پایه‌ای (Underlying Protocol)
  • امنیت (Security)
  • سادگی (Simplicity)
  • کارایی (Performance)
  • ساختار پیام (Message Structure)
  • سهولت پذیرش (Ease of Adoption)
  • ابزار (Tooling)

برخلاف مقایسه‌های قبلی ما، در اینجا برنده‌ای اعلام نخواهیم کرد و امتیازی به ازای هر دسته اختصاص نمی‌دهیم. در عوض، در بخش «خلاصه»، جدولی ارائه خواهیم داد. این جدول حاوی تفاوت‌های کلیدی بین هر دو فناوری در حوزه‌های ذکر شده در بالا است.

چرا باید از آن‌ها استفاده کرد؟

برخلاف REST، هر دو روش SSE و WebSockets بیشتر بر روی سناریوهای خاص تمرکز دارند. در این مورد (یا موارد) خاص، تمرکز اصلی هر دو مفهوم بر روی فراهم کردن یک بستر ارتباطی “لحظه‌ای” (real-time) است. به دلیل تمرکز خاص آنها، محبوبیت کمتری نسبت به REST دارند که یک ابزار عمومی‌تر و همه‌کاره است.

با این حال، هر دو SSE و WebSockets مجموعه‌ای جالب از امکانات و یک به‌روزرسانی کوچک نسبت به رویکرد سنتی REST برای حل مشکلات ارائه می‌دهند.

به نظر ما، خوب است که از آنها آگاه باشیم و فضایی برای آنها در جعبه ابزار خود پیدا کنیم، زیرا ممکن است روزی به کارمان بیایند. راه‌حلی ساده‌تر برای یک مشکل نسبتاً پیچیده ارائه می‌دهند. به خصوص زمانی که به به‌روزرسانی‌های “لحظه‌ای” نیاز داشته باشید یا زمانی که برنامه شما به رویکرد push oriented بیشتری نیاز داشته باشد.

وب‌سوکت چیست؟

به‌طور خلاصه، وب‌سوکت (Websocket) یک پروتکل ارتباطی است که امکان برقراری ارتباط دوطرفه بین سرور و کلاینت را با استفاده از یک اتصال TCP پایدار و طولانی‌مدت فراهم می‌کند. به لطف این ویژگی، ما مجبور نیستیم دائماً داده‌های جدید را از سرور دریافت کنیم. در عوض، داده‌ها بین طرفین علاقه‌مند به صورت “لحظه‌ای” تبادل می‌شوند. هر پیام می‌تواند حاوی داده‌های دودویی یا متن یونیکد باشد.

این پروتکل در سال ۲۰۱۱ توسط IETF در قالب RFC ۶۴۵۵ استانداردسازی شد. پروتکل وب‌سوکت از HTTP متمایز است، اما هر دو در لایه ۷ مدل OSI قرار دارند و به TCP در لایه ۴ وابسته‌اند.

این پروتکل مجموعه منحصربه‌فردی از پیشوندها دارد که مشابه پیشوندهای HTTP یعنی http و https عمل می‌کند:

ws -> نشان می‌دهد که اتصال با TLS امن نشده است.
wss -> نشان می‌دهد که اتصال با TLS امن شده است.

علاوه بر این، اتصالات وب‌سوکت غیر ایمن (ws) نباید از سایت‌های ایمن (https) باز شوند. به طور مشابه، اتصالات وب‌سوکت ایمن (wss) نباید از سایت‌های غیر ایمن (http) باز شوند.

از سوی دیگر، وب‌سوکت به‌طور پیش‌فرض روی پورت‌های ۸۰ و ۴۴۳ HTTP کار می‌کند و مفاهیم HTTP مانند پراکسی‌ها و واسطه‌ها را پشتیبانی می‌کند. همچنین، handshake وب‌سوکت از یک هدر ارتقاء HTTP برای ارتقاء پروتکل از HTTP به وب‌سوکت استفاده می‌کند.

بزرگترین نقطه ضعف وب‌سوکت به عنوان یک پروتکل، امنیت است. وب‌سوکت توسط same-origin policy محدود نمی‌شود، که می‌تواند حملات شبیه به CSRF را بسیار آسان‌تر کند.

وب‌سوکت چیست

SSE چیست؟

Server Sent Events یا SSE تکنولوژی‌ای است که به یک وب‌سرور اجازه می‌دهد تا به یک صفحه وب به‌روزرسانی ارسال کند. این تکنولوژی بخشی از مشخصات HTML5 است و مشابه وب‌سوکت از یک اتصال HTTP طولانی‌مدت برای ارسال داده به صورت “لحظه‌ای” استفاده می‌کند. از لحاظ مفهومی، این یک فناوری نسبتاً قدیمی است که پیشینه نظری آن به سال ۲۰۰۴ بازمی‌گردد. اولین رویکرد برای پیاده‌سازی SSE در سال ۲۰۰۶ توسط تیم Opera انجام شد.

اکثر مرورگرهای مدرن از SSE پشتیبانی می‌کنند – مایکروسافت اج در ژانویه ۲۰۲۰ پشتیبانی از SSE را اضافه کرد. همچنین می‌تواند از مزایای کامل HTTP/2 بهره ببرد، که با حذف عملی محدودیت اتصال اعمال‌شده توسط HTTP/1.1، یکی از بزرگترین مشکلات SSE را برطرف می‌کند.

Server Sent Events طبق تعریف دارای دو جزء اصلی هستند:

  • EventSource -> این رابط که بر اساس مشخصات WHATWG ساخته شده و توسط مرورگر اجرا می‌شود، به کلاینت (در این مورد مرورگر) اجازه می‌دهد تا رویدادها را دنبال کند (subscribe کند).
  • جریان رویداد (Event stream) -> پروتکلی است که قالب استاندارد متن ساده رویدادهای ارسال‌شده توسط سرور را تعریف می‌کند که کلاینت EventSource باید آن را درک و توزیع کند.

طبق مشخصات، رویدادها می‌توانند داده‌های متنی دلخواه، یک شناسه اختیاری را حمل کنند و با خطوط جدید از هم جدا می‌شوند. آن‌ها حتی نوع MIME منحصربه‌فرد خود را دارند: text/event-stream.

متأسفانه، Server Sent Events به‌عنوان یک فناوری فقط برای پشتیبانی از پیام‌های مبتنی بر متن طراحی شده‌اند و اگرچه می‌توانیم رویدادهایی با قالب سفارشی ارسال کنیم، در نهایت پیام باید یک رشته با کدگذاری UTF-8 باشد.

علاوه بر این، SSE دو ویژگی بسیار جالب ارائه می‌دهد:

  1. برقراری مجدد خودکار -> اگر کلاینت به طور غیرمنتظره قطع شود، EventSource به طور دوره‌ای تلاش می‌کند تا دوباره وصل شود.
  2. بازگیری خودکار جریان -> EventSource به طور خودکار آخرین شناسه پیام دریافتی را به خاطر می‌سپارد و هنگام تلاش برای اتصال مجدد، به طور خودکار یک هدر Last-Event-ID ارسال می‌کند.

SSE چیست

مقایسه Websocket و SSE

جهت ارتباط (Communication Direction)

احتمالا بزرگترین تفاوت بین این دو، نحوه ارتباط آنهاست.

  • SSE فقط ارتباط یک طرفه را فراهم می کند – رویدادها فقط از سرور به کلاینت قابل ارسال هستند.
  • WebSockets ارتباط دو طرفه کامل را فراهم می کند و به طرف های علاقه مند امکان می دهد اطلاعات را رد و بدل کنند و به هر رویدادی از هر دو طرف واکنش نشان دهند.

می‌توانیم بگوییم که هر دو رویکرد مزایا و معایب خاص خود را دارند و برای هر کدام مجموعه‌ای از موارد استفاده اختصاصی وجود دارد.

از یک طرف، اگر فقط نیاز به ارسال یک جریان از به‌روزرسانی‌های دائمی به مشتری دارید، SSE انتخاب مناسب‌تری است. از طرف دیگر، اگر نیاز دارید به هر یک از آن رویدادها به هر طریق واکنش نشان دهید، WebSocket ممکن است مفیدتر باشد.

از لحاظ تئوری (و عملی)، همه کارهایی که با SSE قابل انجام است با WebSockets نیز قابل انجام است، اما در این صورت وارد حوزه‌هایی مانند پشتیبانی، سادگی راه‌حل یا امنیت می‌شویم.

در پاراگراف‌های بعدی تمام این حوزه‌ها و موارد دیگر را توضیح خواهیم داد. علاوه بر این، استفاده از WebSocket در همه موارد می‌تواند زیاده‌روی باشد و راه‌حل مبتنی بر SSE ممکن است ساده‌تر اجرا شود.

پروتکل پایه‌ای (Underlying Protocol)

اینجا یکی دیگر از تفاوت‌های بزرگ بین این دو فناوری بیان می‌شود.

  • SSE کاملاً بر HTTP تکیه دارد و از هر دو نسخه HTTP/1.1 و HTTP/2 پشتیبانی می‌کند.
  • برعکس، WebSocket از پروتکل سفارشی خود استفاده می‌کند – بله، درست حدس زدید، پروتکل WebSocket.

در مورد SSE، استفاده از HTTP/2 یکی از مشکلات اصلی SSE را حل می‌کند – محدودیت اتصال همزمان. HTTP/1.1، طبق مشخصات خود، تعداد اتصالات همزمان یا parallel connections را محدود می‌کند. این رفتار ممکن است منجر به مشکلی به نام head-of-line blocking شود. HTTP/2 این مشکل را با معرفی مالتی‌پلکسینگ (multiplexing) برطرف می‌کند، که head-of-line blocking را در لایه اپلیکیشن حل می‌کند. با این حال، head-of-line blocking همچنان ممکن است در سطح TCP رخ دهد.

در مورد پروتکل WebSocket، چند خط بالاتر به طور خلاصه به آن اشاره کردیم. در اینجا فقط مهم‌ترین نکات را تکرار می‌کنیم. این پروتکل با وجود استفاده از یک هدر ارتقاء HTTP برای راه‌اندازی اتصال WebSocket و تغییر مؤثر پروتکل‌های ارتباطی، تا حدودی با HTTP کلاسیک متفاوت است.

با این حال، این پروتکل نیز از پروتکل TCP به عنوان پایه استفاده می‌کند و کاملاً با HTTP سازگار است. بزرگترین اشکال پروتکل WebSocket امنیت آن است.

سادگی (Simplicity)

به طور کلی، راه‌اندازی یکپارچه مبتنی بر SSE نسبت به همتای WebSocket آن ساده‌تر است. مهم‌ترین دلیل پشت این موضوع ماهیت ارتباطی است که توسط یک فناوری خاص مورد استفاده قرار می‌گیرد.

روش یک طرفه SSE و مدل push آن باعث می‌شود که از نظر مفهومی آسان‌تر باشد. ترکیب آن با پشتیبانی از اتصال مجدد خودکار (automatic reconnection) و تداوم جریان (stream continuity) که به صورت پیش‌فرض ارائه می‌شود، تعداد کارهایی که باید انجام دهیم به طور قابل توجهی کاهش می‌یابد.

با تمام این ویژگی‌ها، SSE را می‌توان راهی برای کاهش وابستگی بین کلاینت و سرور نیز در نظر گرفت. کلاینت‌ها فقط باید یک نقطه انتهایی (endpoint) را بشناسند که رویدادها را تولید می‌کند.

با این حال، در چنین حالتی، کلاینت فقط می‌تواند پیام‌ها را دریافت کند، بنابراین اگر می‌خواهیم هر نوع اطلاعاتی را به سرور ارسال کنیم، به یک واسطه ارتباطی دیگری نیاز داریم که ممکن است کارها را بسیار پیچیده کند.

در مورد WebSocket، امور کمی پیچیده‌تر هستند. اول از همه، ما باید ارتقاء اتصال از پروتکل HTTP به پروتکل WebSocket را مدیریت کنیم. اگرچه ساده‌ترین کار در اینجا است، اما یک مورد دیگر است که باید به خاطر بسپاریم.

مشکل دوم از ماهیت دوطرفه WebSockets ناشی می‌شود. ما باید وضعیت یک اتصال خاص را مدیریت کنیم و همه استثنائات (exception) احتمالی را که در حین پردازش پیام رخ می‌دهد، مدیریت کنیم. برای مثال، چه اتفاقی می‌افتد اگر پردازش یکی از پیام‌ها در سمت سرور یک exception ایجاد کند؟

مورد بعدی مشکل مدیریت اتصالات مجدد است که در مورد WebSockets باید خودمان آن را مدیریت کنیم. همچنین مشکلی وجود دارد که بر هر دو فناوری تأثیر می‌گذارد – اتصالات طولانی مدت (long-running connections). هر دو فناوری نیاز به حفظ اتصالات باز با عمر طولانی برای ارسال یک جریان مداوم از رویدادها دارند.

مدیریت چنین اتصالاتی، به ویژه در مقیاس بزرگ، می‌تواند چالش‌برانگیز باشد، زیرا ما می‌توانیم به سرعت منابع را تمام کنیم. علاوه بر این، آن‌ها ممکن است به پیکربندی‌های خاصی مانند مهلت تمدید شده (extended timeout) نیاز داشته باشند و در برابر هر گونه مشکل اتصال شبکه آسیب‌پذیرتر باشند.

امنیت (Security)

در مورد SSE، از آنجایی که از پروتکل قدیمی و ساده HTTP به عنوان واسطه حمل و نقل استفاده می‌کند، موضوع امنیت چیز خاصی ندارد. تمام مزایا و معایب امنیتی استاندارد HTTP برای SSE صدق می‌کند، به همین سادگی.

از طرف دیگر، امنیت یکی از بزرگترین اشکالات پروتکل WebSocket به طور کلی است. برای شروع، چیزی به نام «سیاست هم‌ریشه» (Same Origin Policy) وجود ندارد، بنابراین هیچ محدودیتی در مورد مکانی که می‌خواهیم از طریق WebSockets به آن وصل شویم وجود ندارد.

حتی نوع خاصی از حمله با هدف سوءاستفاده از این آسیب‌پذیری وجود دارد که به آن Cross-Origin WebSocket Hijacking می‌گویند.

عملکرد (Performance)

می‌توان گفت که هر دو فناوری از نظر عملکرد در یک سطح قرار دارند. هیچ‌کدام از این فناوری‌ها به‌طور تئوری محدودیت عملکردی ندارند. با این حال، می‌توانیم بگوییم که SSE از نظر تعداد پیام‌های ارسالی در ثانیه، سریع‌تر است، زیرا بر اساس اصل «ارسال و فراموشی» کار می‌کند. WebSocket علاوه بر ارسال پیام، باید پاسخ‌های دریافتی از سمت کاربر را نیز مدیریت کند.

تنها چیزی که می‌تواند بر عملکرد هر دو فناوری تأثیر بگذارد، underlying client است که در برنامه خود استفاده می‌کنیم و نحوه پیاده‌سازی آن است. برای به دست آوردن اطلاعات ارزشمند در مورد ابزاری که استفاده می‌کنید یا کل سیستم خود، اسناد را بررسی کنید، آن‌ها را بخوانید و تست‌های استرس سفارشی اجرا کنید.

ساختار پیام (Message Structure)

ساختار پیام احتمالاً یکی دیگر از مهم‌ترین تفاوت‌های بین این پروتکل‌ها است. همانطور که قبلا ذکر کردیم، SSE یک پروتکل کاملاً متنی است. ما می‌توانیم پیام‌هایی با فرمت‌ها و محتویات مختلف ارسال کنیم، اما در نهایت همه چیز به صورت متن رمزگذاری‌شده با UTF-8 در می‌آید. هیچ فرمت پیچیده یا داده باینری در آن امکان‌پذیر نیست.

از طرف دیگر، WebSocket می‌تواند هم پیام‌های متنی و هم باینری را مدیریت کند. این به ما امکان ارسال تصاویر، صدا یا فقط فایل‌های معمولی را می‌دهد. فقط به خاطر داشته باشید که پردازش فایل‌ها می‌تواند سربار قابل‌توجهی داشته باشد.

سهولت پذیرش (Ease of Adoption)

در اینجا، هر دو فناوری در مرحله بسیار مشابهی قرار دارند. ابزارهای زیادی برای افزودن پشتیبانی از WebSockets و Server Sent Events از هر دو طرف کلاینت و سرور (از دیدگاه SSE) وجود دارد.

اکثر زبان‌های برنامه‌نویسی جاافتاده بیش از یک کتابخانه از این نوع دارند. بدون اینکه وارد جزئیات زیادی شویم، جدولی برای خلاصه کردن کتابخانه‌های اساسی، افزودن پشتیبانی از WebSockets و SSE تهیه کرده‌ایم.

زبان SSE WebSockets
جاوا Spring (SSE), Quarkus (SSE) Spring (WebSockets), Quarkus (WebSockets)
اسکالا Akka (SSE), Play (SSE) Akka (WebSockets), Play (WebSockets)
جاوااسکریپت EventSource, total.js (SSE) Socket.io, total.js (WebSockets)
پایتون Starlette FastAPI

همانطور که می بینید، اگر بخواهیم قابلیت‌های SEE یا WebSockets را به برنامه خود اضافه کنیم، گزینه‌های تثبیت‌شده زیادی در اختیار داریم. البته این فقط یک مثال کوچک است که از بین تمام کتابخانه‌ها انتخاب شده است، تعداد بسیار بیشتری وجود دارد. مشکل واقعی ممکن است یافتن مناسب‌ترین گزینه برای مورد استفاده خاص شما باشد.

ابزار (Tooling)

تست‌های خودکار

تا جایی که می‌دانیم، هیچ ابزار تست خودکاری به طور خاص برای SSE یا WebSockets وجود ندارد. با این حال، شما به راحتی می‌توانید با استفاده از Postman و مجموعه‌های آن به عملکردی مشابه برسید.

Postman از هر دو رویدادهای ارسال شده از سرور (Server Sent Events) و WebSockets پشتیبانی می‌کند. با استفاده از برخی ویژگی‌های کلیدی مجموعه‌های Postman، می‌توانید مجموعه‌ای از تست‌ها را برای تأیید صحت نقاط انتهایی خود آماده کنید.

تست‌های عملکرد

برای تست‌های عملکرد، می‌توانید از JMeter یا Gatling استفاده کنید. تا جایی که می‌دانیم، این دو بالغ‌ترین ابزار برای تست عملکرد کلی هستند. البته هر دوی آن‌ها از SSE (JMeter، Gatling) و WebSockets (JMeter، Gatling) نیز پشتیبانی می‌کنند.

ابزارهای دیگری مانند sse-perf (فقط SSE)، Testable یا k6 (فقط WebSockets) نیز وجود دارد. از بین تمام این ابزارها، ما Gatling یا k6 را توصیه می‌کنیم. به نظر می‌رسد هر دو بهترین تجربه کاربری را دارند و برای تولید آماده‌ترین هستند.

مستندسازی

تا حدودی، هیچ ابزاری به طور اختصاصی برای مستندسازی SSE یا WebSockets وجود ندارد. از طرف دیگر، ابزاری به نام AsyncAPI وجود دارد که به همین روش برای هر دو مفهوم قابل استفاده است. متأسفانه به نظر می‌رسد OpenAPI از هیچکدام از SSE یا WebSockets پشتیبانی نمی‌کند.

نمایش بیشتر

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

همچنین ببینید
بستن
دکمه بازگشت به بالا