سوکت های وب и SSE
1) کوتاه: چه و برای چه
WebSocket (WS/WSS) - ارتقاء اتصال HTTP به کانال کامل دوبلکس. مناسب برای چت، بازی های زنده، همکاری، تله متری دو طرفه.
رویدادهای ارسال شده توسط سرور (SSE) - جریان یک طرفه از سرور به مرورگر (MIME 'text/event-stream'). ایده آل برای tickers، اطلاعیه ها، نقل قول ها، پیشرفت کار. مشتری - «منبع رویداد».
- شما نیاز به ورودی از مشتری در زمان واقعی (اغلب زیادی) → WebSocket.
- فقط فشار به روز رسانی از سرور، سازگاری و سادگی مهم تر از SSE →.
2) شبکه و پروتکل ها
2. 1 حمل و نقل و سازگاری
WebSocket: شروع می شود به عنوان HTTP 'دریافت... ارتقا: وب سایت '(HTTP/1. 1). برای HTTP/2، RFC 8441 (CONNECT + ': protocol = websocket') امکان پذیر است، پشتیبانی بستگی به پروکسی دارد. این نسخهها کار میکند در بالای TLS (WSS) - اجباری در فروش.
SSE: پاسخ معمولی HTTP طولانی ('200 OK') با جریان. به خوبی از طریق HTTP/1 می رود. 1/2/3، سازگار با CDN/پروکسی (در صورت عدم اتصال طولانی).
2. 2 پروکسی/متعادل کننده/CDN
بررسی: پشتیبانی از اتصالات طولانی مدت، وقفه ها و وقفه ها، جلسات چسبنده (اگر حالت در گره باشد).
برای WS: شامل 'proxy _ read _ timeout'، 'ارتقاء' هدر، محدودیت هر اتصال.
برای SSE، اطمینان حاصل کنید که پروکسی پاسخ را بافر نمی کند (در غیر این صورت مشتری رویدادها را به موقع نمی بیند).
3) مدل پیام و کنترل جریان
WebSocket: متن یا فریم های باینری ؛ یک «پینگ/پونگ» وجود دارد، اما هیچ فشار پشتی داخلی وجود ندارد - پیاده سازی در برنامه (صف، پنجره، خط مشی قطره).
SSE: رویدادهای متنی (UTF-8) ؛ مشتری قادر به اتصال مجدد با تاخیر ساخته شده در است. سرور می تواند 'retry:' را مشخص کند. یک «id:» و یک «Last-Event-ID» وجود دارد که از موقعیت مورد نظر ادامه می یابد.
- نقل قول پیام های خروجی در هر مشتری.
- محدود کردن صف رویدادهای ناخواسته ؛ در سرریز - دور انداختن اولویت کم/مجموع.
- برای WS، از یک پنجره کشویی و ACK در سطح برنامه استفاده کنید.
4) قابلیت اطمینان اتصالات
4. 1 تشخیص و نگهداری
WS: ارسال پینگ هر N ثانیه ؛ فاصله زمانی - دوباره با عقب نشینی نمایشی + jitter متصل شوید.
SSE: سرور "comments" ':\n "را به عنوان ضربان قلب ارسال می کند تا اتصال بیکار نباشد ؛ مشتری خودش را جمع و جور می کند.
4. 2 بازیابی جریان
WS: نگه داشتن پیام های افست/توالی و درخواست دلتا پس از اتصال مجدد.
SSE: استفاده از 'id:' برای هر رویداد و 'Last-Event-ID' در درخواست - سرور رویدادهای از دست رفته را ارسال می کند.
5) احراز هویت و مجوز
JWT Bearer در URL درخواست (WS) ناامن است (نشت در سیاهههای مربوط). از یک هدر (از طریق دست دادن HTTP اولیه) یا کوکی ها با پرچم های «Secure»، «HttpOnly»، «SameSite» استفاده کنید.
mTLS (به ویژه برای B2B) امکان پذیر است، و همچنین امضای (HMAC) بیش از درخواست اصلی.
برای SSE با کوکی ها، در مورد CORS («Access-Control-Allow-Origin»، «Allow-Credentials») به یاد داشته باشید.
چرخش نشانه: جریان را قطع نکنید. رمز عبور «به زودی منقضی خواهد شد» → مشتری ارتباط با توکن جدید را دوباره باز خواهد کرد.
6) فرمت داده ها و فشرده سازی
WebSocket: فعال کردن permessage-deflate با دقت (CPU) ؛ اجتناب از فشرده سازی فرمت های فشرده شده (Proto، Avro). بار باینری اقتصادی تر از JSON است.
SSE: این متن است ؛ برای داده های بزرگ، یک لینک به یک منبع REST/gRPC یا فایل های تکه ارسال کنید ؛ حمل و نقل gzip برای SSE - مناسب است، اما برای بافر در پروکسی/CDN تماشا کنید.
7) پوسته پوسته شدن و فن کردن
7. 1 مقیاس افقی
نگه داشتن برنامه بدون نقص برای راه اندازی مجدد. وضعیت اتصال - در لایه جلو ؛ داده ها - از کارگزار.
مهم (هش توسط جلسه/کاربر) مورد نیاز است اگر صف های محلی وجود دارد.
ایده آل جبهه بی طرف است: گره تنها اشتراک های چندگانه ؛ حوادث از یک میخانه/زیر مشترک آمده است.
7. 2 میخانه/فرعی و کارگزاران
برای یک طرفدار گسترده، از Kafka/NATS/Redis Streams استفاده کنید.
لایه «Fanout Gateway» از طریق WS/SSE به موضوعات و مشتریان مشتری می پردازد.
از یک کلید مسیریابی (به عنوان مثال، 'userId'، 'matchId') برای تعادل بار بین گره ها استفاده کنید.
8) پیکربندی تولید
8. 1 NGINX - وب سوکت
nginx map $http_upgrade $connection_upgrade { default upgrade; '' close; }
server {
listen 443 ssl http2;
server_name ws. example. com;
location /ws {
proxy_set_header Host $host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_http_version 1. 1;
proxy_read_timeout 75s; # increase for long sessions proxy_send_timeout 15s;
proxy_pass http://ws-backend;
}
}
8. 2 NGINX - SSE (مهم برای غیر فعال کردن بافر)
nginx location /events {
proxy_http_version 1. 1;
proxy_set_header Connection "";
proxy_buffering off; # is critical for proxy_cache off threads;
chunked_transfer_encoding on;
proxy_read_timeout 60m;
proxy_pass http://sse-backend;
}
8. 3 Kubernetes (ورودی حاشیه نویسی، NGINX ورود)
yaml metadata:
annotations:
nginx. ingress. kubernetes. io/proxy-read-timeout: "3600"
nginx. ingress. kubernetes. io/proxy-send-timeout: "3600"
nginx. ingress. kubernetes. io/enable-websocket: "true"
nginx. ingress. kubernetes. io/proxy-buffering: "off" # для SSE
9) مثال کد
9. 1 مشتری SSE (مرورگر)
js const es = new EventSource("/events? channel=odds", { withCredentials: true });
es. addEventListener("message", (e) => {
const data = JSON. parse(e. data);
renderOdds(data);
});
es. addEventListener("error", () => {
//EventSource will reconnect itself; can be shown spinner
});
9. 2 سرور SSE (گره. JS/اکسپرس)
js app. get('/events', (req, res) => {
res. writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
});
res. write ('retry: 3000\n\n') ;//3s backoff to client
const sub = subscribe(req. query. channel, (event) => {
res. write(`id: ${event. id}\n`);
res. write(`event: message\n`);
res. write(`data: ${JSON. stringify(event. payload)}\n\n`);
});
req. on('close', () => sub. unsubscribe());
});
9. 3 مشتری WebSocket (مرورگر)
js const ws = new WebSocket("wss://ws. example. com/ws");
ws. onopen = () => ws. send(JSON. stringify({ type: "join", room: "chat-1" }));
ws. onmessage = (m) => handle(JSON. parse(m. data));
ws. onclose = () => scheduleReconnect();
10) امنیت و محدود کردن
Rate limiting per-connection and per-user: میزان پیام های ورودی (WS) و میزان جریان خروجی (WS/SSE) را محدود می کند.
سهمیه بر اساس طول عمر اتصال و کل ترافیک.
محدودیت اندازه پیام и حداکثر پیام/ثانیه.
فیلترهای WAF/bot در مرحله دست دادن ؛ حفاظت در برابر سیل اتصال (بسیاری از اتصالات کوتاه).
جداسازی فضای مستاجر/نام: استخرهای منابع فردی.
11) قابلیت مشاهده
معیارها:- 'connections _ active', 'connections _ new _ total', 'bytes _ in/out',
- 'messages _ in/out _ total', 'رها شده _ messages _ total',
- 'reconnects _ total', 'latency _ delivery _ ms {p50, p95, p99}'.
- سیاهههای مربوط: IP/UA، userId/tenantId، دلیل بسته شدن ('close _ code')، مدت زمان.
- ردیابی: رویدادهای مرتبط با فرمان اصلی (شناسه های همبستگی) ؛ برای WS، استفاده از «مجازی» دهانه بوچ.
12) تفاوت های ظریف عملیاتی
خاتمه TLS نزدیک به مشتری (CDN/لبه).
چرخش فعال اتصالات (برازنده) در طول تخلیه: به پرچم «اتصال مجدد».
شاردینگ بر روی کلید به طور مساوی توزیع «گرم» کانال.
عکس های فوری وضعیت برای مشترکین دیر (عکس فوری + دلتا).
آخرین مقدار کش (به خصوص SSE) - برای یک مشتری سرد مفید است.
13) ضد الگوهای
جریان تکه های باینری بزرگ از طریق SSE یا JSON بیش از WS - استفاده از HTTP دانلود و لینک در پیام.
مجوز فقط در زمان اتصال و عدم بررسی مجدد برای جلسات طولانی.
جهانی چسبنده بی نیاز → عدم تعادل و گره های داغ.
قطع وقت از کار افتاده/محدودیت → اتصالات یخ زده خوردن تا استخر.
بافر پروکسی SSE/CDN → «زمان واقعی» دقیقه تاخیر می شود.
عدم توالی/جبران → پس از اتصال مجدد، مشتری یکپارچگی داده ها را از دست می دهد.
14) چک لیست پیاده سازی
- WS (دو طرفه) یا SSE (یک طرفه) انتخاب شده است.
- زمان بندی پیکربندی شده، keepalive و اتصال مجدد (عقب + jitter).
- دنباله/افست طراحی شده و (برای SSE) 'id '/' Last-Event-ID'.
- اندازه/سرعت/اتصالات/سهمیه، حفاظت از DoS تعریف شده است.
- پیکربندی پروکسی/ورودی: ارتقا، proxy_buffering خاموش (SSE)، خواندن/ارسال زمان.
- پوسته پوسته شدن: میخانه/کارگزار زیر، دروازه فن، چسبنده تنها در صورت نیاز.
- احراز هویت: انتقال رمز امن، چرخش بدون شکستن.
- قابلیت مشاهده: معیارها، سیاهههای مربوط، ردیابی ؛ داشبورد و هشدارها
- طرح انتشار: اتصالات تخلیه برازنده، سیگنال مشتری برای اتصال مجدد.
- روز بازی: شکست شبکه، قطره گره، بیش از حد کارگزار، RTT های طولانی.
15) سوالات متداول
آیا می توان SSE را از طریق CDN ذخیره کرد ؟
معمولا نه: این یک جریان شخصی است. برای کانال های عمومی - احتمالا با TTL کوتاه و تحویل chunked، اما آسان است برای شکستن «زمان واقعی».
آیا WebSocket در بالای HTTP/2/3 کار می کند ؟
مرورگر WS با HTTP/1 شروع می شود. 1-ارتقاء ؛ RFC 8441 برای h2 وجود دارد، پشتیبانی در پروکسی/سرور به طور جداگانه مورد نیاز است. با h3 - در حال حرکت ؛ برای جریان، h3 دارای WebTransport است، اما API متفاوت است.
gRPC در مقابل WS برای مرورگر ؟
یک مرورگر تمیز gRPC را نمی گوید ؛ نیاز به gRPC-وب از طریق نماینده. برای رابط های کاربری تعاملی، WS + REST اغلب ساده تر است.
16) مجموع
WebSocket - هنگامی که شما نیاز به گفت و گو در زمان واقعی و یک کانال دو طرفه جمع و جور.
SSE - هنگامی که شما نیاز به یک فشار ساده و قابل اعتماد از سرور به مشتری، حداقل پیچیدگی و اتصال مجدد خودکار.
موفقیت در فروش زمان بندی و محدودیت های صحیح، بازیابی از افست، pub/sub fan-out، تنظیمات پروکسی صحیح و قابلیت مشاهده واضح است.