پرش به مطلب اصلی

ConnectionFisherClient

ConnectionFisherClient بخش کلاینت ConnectionFisherServer است. برای هر line ورودی، چند child line را هم‌زمان به سمت next باز می‌کند و probe پنج‌بایتی FISH? را روی هرکدام می‌فرستد. نخستین child line که پاسخ معتبر FISH! بگیرد انتخاب می‌شود و بقیه بسته می‌شوند.

این node زمانی کاربرد دارد که مسیر خروجی پایدار نیست یا می‌خواهید چند اتصال را هم‌زمان امتحان کنید و اولین مسیری را انتخاب کنید که رسیدن به ConnectionFisherServer متناظر را تأیید می‌کند.

جایگاه رایج​

چیدمان سادهٔ TCP:

TcpListener -> ConnectionFisherClient -> TcpConnector
TcpListener -> ConnectionFisherServer -> TcpConnector

همراه با تونل‌های stream دیگر در میانه مسیر:

TesterClient -> ConnectionFisherClient -> MuxClient -> MuxServer -> ConnectionFisherServer -> TesterServer

کلاینت و سرور باید دو سر یک مسیر منطقی stream باشند. هر تونل میانی باید بایت‌های ثابت probe را بدون تغییر عبور دهد.

این نود چه می‌کند؟​

  • مقدار settings.simultaneous-tries-perline را می‌خواند.
  • با هر Init در جهت upstream روی main line، به تعداد تنظیم‌شده child line داخلی می‌سازد.
  • upstream Init را روی هر child line به next می‌فرستد.
  • probe ثابت FISH? را روی هر child line می‌فرستد.
  • منتظر پاسخ ثابت FISH! می‌ماند.
  • تا زمان انتخاب یک child، payloadِ upstream روی main line را در صف نگه می‌دارد.
  • اولین child که پاسخ معتبر دریافت کند را انتخاب می‌کند.
  • همه child line‌های انتخاب‌نشده را می‌بندد.
  • payload‌های upstream صف‌شده را به ترتیب برای child انتخاب‌شده می‌فرستد.
  • payload‌های downstream از child انتخاب‌شده را به main line برمی‌گرداند.

ConnectionFisherClient یک تونل میانی stream است. مستقیماً socket یا packet line نمی‌سازد.

نمونه تنظیم​

{
"name": "fisher-client",
"type": "ConnectionFisherClient",
"settings": {
"simultaneous-tries-perline": 3
},
"next": "tcp-out"
}

سمت سرور متناظر:

{
"name": "fisher-server",
"type": "ConnectionFisherServer",
"next": "service"
}

فیلدهای اجباری​

فیلدهای سطح اصلی:

فیلدنوعتوضیح
namestringنام یکتای node در config.
typestringباید دقیقاً "ConnectionFisherClient" باشد.
nextstringاجباری. node stream بعدی که child line‌های نامزد را می‌گیرد.

ConnectionFisherClient باید node قبلی نیز داشته باشد؛ این node ابتدا یا انتهای chain نیست.

تنظیمات اختیاری​

گزینهنوعپیش‌فرضتوضیح
simultaneous-tries-perlineinteger >= 12تعداد child line‌های نامزد که برای هر main line ورودی ساخته می‌شوند.

settings می‌تواند حذف شود. مقادیر کمتر از 1 رد می‌شوند.

تبادل Probe​

probe مقدار ثابتی دارد و secret قابل تنظیمی برای آن وجود ندارد:

جهتBytesمعنی
کلاینت به سرورFISH?بلافاصله پس از Init در upstream، روی هر child line فرستاده می‌شود.
سرور به کلاینتFISH!پاسخ الزامی ConnectionFisherServer.

این markerها فقط نشان می‌دهند که child line به ConnectionFisherServer متناظر رسیده است؛ هیچ احراز هویت، رمزنگاری یا تضمین صحتی برای ترافیک فراهم نمی‌کنند.

مدل Line​

ConnectionFisherClient از دو نوع line استفاده می‌کند:

Lineهدف
main lineline ورودی اصلی از node قبلی که در سمت previous باقی می‌ماند.
child linesline‌های نامزد داخلی که کلاینت می‌سازد و فقط به سمت next می‌روند.

main line هیچ‌گاه مستقیم به next فرستاده نمی‌شود و child line‌ها نیز هرگز به سمت prev نمی‌روند. پس از انتخاب یک child، تونل payload و callback‌های Est، Pause، Resume و Finish را به‌صورت دستی میان main line و child منتخب جابه‌جا می‌کند.

جریان انتخاب​

برای هر upstream Init روی main line:

  1. state مربوط به main line مقداردهی اولیه می‌شود.
  2. حداکثر simultaneous-tries-perline child روی همان worker ساخته می‌شود؛ انتخاب هم‌زمان تلاش تازه را متوقف می‌کند.
  3. هر child line به سمت next مقداردهی اولیه می‌شود.
  4. هر child پس از Init و با مجوز transport، FISH? می‌فرستد.
  5. اگر هنوز برنده‌ای به‌صورت هم‌زمان انتخاب نشده باشد، timeout انتخاب 5000 ms زمان‌بندی می‌شود.
  6. تا مشخص شدن child برنده، payloadِ upstream روی main line در صف می‌ماند.
  7. اولین child که FISH! دریافت کند، child انتخاب‌شده می‌شود.
  8. child line‌های بازنده بسته می‌شوند.
  9. بایت‌های همراه FISH! پیش از پاسخ‌های جدید ناشی از داده برنامه به node قبلی فرستاده می‌شوند.
  10. صف upstream به‌ترتیب و فقط تا وقتی transport Pause نکرده برای child منتخب تخلیه می‌شود.

اگر هیچ child پیش از timeout معتبر شناخته نشود، main line بسته می‌شود.

محدودیت‌ها و Buffer​

محدودیتمقداررفتار
Selection timeout5000 msاگر child‌ای انتخاب نشود، main line بسته می‌شود.
Pending upstream payload2 MiBاگر payload صف‌شده از این حد بگذرد، main line بسته می‌شود.
پاسخ ناقص child4 bytesپاسخ کامل پنج‌بایتی بی‌درنگ اعتبارسنجی می‌شود.
بدنه همراه پاسخ / ترتیب انتخاب2 MiBبایت‌های marker از سقف داده برنامه کم نمی‌کنند.
تعداد bufferهای pending upstream1,024ورودی TCP خالی entry اشغال نمی‌کند.
required_padding_left0node header پروتکل را به buffer‌های موجود اضافه نمی‌کند.

برای probeِ FISH? یک buffer کوچک جداگانه گرفته می‌شود. payload کاربر در همان buffer‌های WaterWall در صف می‌ماند یا ارسال می‌شود.

رفتار Lifecycle​

قبل از انتخاب:

  • payload upstream از main line در صف قرار می‌گیرد
  • payload downstream از child به‌عنوان داده handshake در نظر گرفته می‌شود
  • اولین Est transport از child عضو معتبر، مستقل از انتخاب و پیش از FISH!، یک بار به main line فرستاده می‌شود.
  • child‌ای که از Init با transport از قبل برقرار برگردد، همان اعلان یک‌باره را ایجاد می‌کند.
  • فشار transport child پیش از انتخاب ذخیره می‌شود؛ اولین payload نگهداری‌شده مستقل از انتخاب، مبدأ main را Pause می‌کند

بعد از انتخاب:

  • payloadِ upstream روی main line با tunnelNextUpStreamPayload به child منتخب فرستاده می‌شود.
  • payloadِ downstream روی child منتخب با tunnelPrevDownStreamPayload به node قبلی می‌رود.
  • انتخاب و تکمیل handshake هیچ Est دیگری ایجاد نمی‌کنند.
  • Pause و resume فقط میان child منتخب و main line جابه‌جا می‌شوند.

اگر child منتخب بسته شود، main line نیز بسته می‌شود. اگر همه child‌ها پیش از انتخاب برنده بسته شوند، main line هم بسته خواهد شد.

صف upstream برنامه با پذیرش transactional به 2 MiB و 1,024 buffer محدود می‌ماند. پس از ثبت اولین payload در FIFO، Pause مبدأ برنامه منتشر می‌شود. این دلیل با فشار transport child منتخب جمع می‌شود؛ Resume یک child دیگر یا صرف انتخاب، آن را آزاد نمی‌کند. probe و پاسخ FISH همچنان اجازه پیشرفت دارند، چون این توقف فقط به مبدأ برنامه اعمال می‌شود. تخلیه پس از انتخاب یا Resume یک تولیدکننده مستقل است: Pause آن را متوقف می‌کند و ورودی re-entrant پشت داده قدیمی قرار می‌گیرد. Pause پاسخ main پیش از انتخاب ذخیره و پس از handshake به child منتخب اعمال می‌شود تا پاسخ FISH! را متوقف نکند. بایت‌های همراه FISH! پیش از پاسخ‌های جدید ناشی از داده برنامه ارسال می‌شوند؛ صف موقت برای حفظ ترتیب downstream نیز سقف 2 MiB دارد. انتخاب هم‌زمان ایجاد تلاش‌های تازه را متوقف می‌کند و timeout غیرضروری ایجاد نمی‌شود.

نکته‌ها​

  • با ConnectionFisherServer متناظر استفاده کنید.
  • برای chain‌های stream طراحی شده است، نه packet-line.
  • افزایش simultaneous-tries-perline تعداد و بار اتصال‌ها را نیز بالا می‌برد.
  • probe ثابت و عمومی است؛ در مسیرهایی که به امنیت نیاز دارند از TLS یا node‌های رمزنگاری، احراز هویت و مسیریابی استفاده کنید.
  • upstream Est و downstream Init برای این node غیرفعال هستند.

پشتیبانی از splice و بازنشستگی state راه‌اندازی​

هر دو node، buffer عادی و payload موجود در pipe خصوصی را می‌پذیرند. هر delivery که وارد parsing handshake یا ترتیب‌دهی هنگام انتخاب child شود، با sbufEnsureOrdinary() کامل به buffer عادی تبدیل می‌شود. FIFO برنامه buffer را بدون خواندن محتوا نگه می‌دارد. marker کامل پنج‌بایتی می‌تواند تا 2 MiB داده برنامه همراه داشته باشد؛ marker از سقف داده برنامه کم نمی‌کند و marker ناقص حداکثر چهار بایت دارد.

پس از راه‌اندازی و تخلیه FIFO، client فضای handshake و صف خالی را آزاد می‌کند، اما نگاشت main به child منتخب و کنترل جریان endpoint برای payload، فشار و Finish باقی می‌ماند. server پس از اتمام Init سمت backend و replay، همه state خط را آزاد و صفر می‌کند و روی همان line برای همیشه bypass می‌شود. payload آماده بدون inspection، materialization یا سقف backlog راه‌اندازی عبور می‌کند. server همچنان backend را با نخستین payload برنامه مقداردهی می‌کند؛ childهای بازنده اتصال backend نمی‌سازند. برای TCP آماده، ترجیح خواندن عادی ثبت نمی‌شود.

متادیتای نود​

metadata برگرفته از کد منبع:

ویژگیمقدار
node flagskNodeFlagSupportsSplice
can_have_prevtrue
can_have_nexttrue
layer_groupkNodeLayer4
layer_group_prev_nodekNodeLayer4
layer_group_next_nodekNodeLayer4
required_padding_left0 bytes