KeepAliveServer
KeepAliveServer بخش سرور KeepAliveClient است. فریمهای keepalive را که از کلاینت و در جهت upstream میرسند decode میکند، payloadهای عادی را به next میفرستد، به فریم ping با pong پاسخ میدهد و payloadهای downstream را در همان قالب فریم قرار میدهد.
این node را فقط بهعنوان peer متناظر KeepAliveClient به کار ببرید. ورودی upstream آن باید فریمشده باشد و بهتنهایی بایتهای معمولی و بدون فریم payload را تشخیص نمیدهد.
KeepAliveServer یک تونل عادی و قابل ترکیب است. socket یا objectای از نوع line_t نمیسازد، line را آزاد نمیکند و timer دورهای ندارد.
جایگاه رایج
جفت مستقیم داخل یک process:
TesterClient -> KeepAliveClient -> KeepAliveServer -> TesterServer
چیدمان TCP روی دو سرور:
client side: TcpListener -> KeepAliveClient -> TcpConnector
server side: TcpListener -> KeepAliveServer -> TcpConnector
هر تونل میان کلاینت و سرور باید بایتهای فریم keepalive را بدون تغییر عبور دهد.
این نود چه میکند؟
- با دریافت
Initدر upstream، state محلی line را مقداردهی اولیه میکند. - بایتهای فریمشده upstream را تا کامل شدن فریمها buffer میکند.
- فریمهای عادی upstream را decode و payload آنها را به
nextمیفرستد. - به فریم ping در upstream، با فرستادن فریم pong در downstream پاسخ میدهد.
- pong frameهای upstream را نادیده میگیرد.
- فریمهای عادی خالی و typeهای ناشناخته را دور میاندازد.
- payloadهای downstream را بهعنوان keepalive frame عادی encode میکند و به node قبلی میفرستد.
- payloadهای downstream بزرگتر از
1 MiBرا به چند frame عادی تقسیم میکند. - state محلی line را از بین میبرد و
Finishرا در همان جهت منتشر میکند.
سرور timer جداگانهای برای keepalive ندارد؛ KeepAliveClient مسئول ساخت pingهای دورهای است.
نمونه تنظیم
{
"name": "ka-server",
"type": "KeepAliveServer",
"settings": {},
"next": "service"
}
سمت کلاینت متناظر:
{
"name": "ka-client",
"type": "KeepAliveClient",
"settings": {
"ping-interval": 60000
},
"next": "transport"
}
فیلدهای اجباری
فیلدهای سطح اصلی:
| فیلد | نوع | توضیح |
|---|---|---|
name | string | نام یکتای node در config. |
type | string | باید دقیقاً "KeepAliveServer" باشد. |
settings | object | اختیاری. پیادهسازی فعلی تنظیم اختصاصی برای سرور ندارد. |
next | string | در استفاده عادی اجباری است. node بعدی payloadهای decodeشده upstream را میگیرد. |
KeepAliveServer باید node قبلی داشته باشد و توسط KeepAliveClient متناظر قابل دسترس باشد.
تنظیمات
KeepAliveServer در حال حاضر تنظیم معنیداری ندارد. زمانبندی keepalive در KeepAliveClient با settings.ping-interval تنظیم میشود.
فرمت Frame
سرور از همان prefix پنجبایتی client استفاده میکند:
| Bytes | فیلد | توضیح |
|---|---|---|
0..3 | body length | عدد صحیح unsigned و 32-bit با ترتیب big-endian. این طول شامل بایت type فریم بهعلاوه بایتهای payload است. |
4 | frame kind | 1 payload عادی، 2 ping، یا 3 pong. |
نوعهای frame:
| Kind | معنی | Body payload |
|---|---|---|
1 | payload عادی | بایتهای payload اصلی WaterWall. |
2 | ping | در ترافیک keepalive عادی خالی است. |
3 | pong | پاسخ خالی به یک ping frame. |
طول body شامل بایت kind هم میشود. هر فریم حداکثر 1 MiB (1,048,576 بایت) payload دارد و حداکثر طول بدنه 1,048,577 است. payloadهای downstream بزرگتر به چند فریم تقسیم میشوند. هر دو peer از همین prefix پنجبایتی استفاده میکنند.
رفتار جهتها
| Incoming callback | رفتار |
|---|---|
upstream Init | buffer خواندن را مقداردهی اولیه میکند و سپس Init را به next میفرستد. |
upstream Payload | بایتها را ورودی فریمشده KeepAliveClient در نظر میگیرد و payloadهای عادی decodeشده را به next میفرستد. |
upstream Est / Pause / Resume | به next فرستاده میشوند. |
upstream Finish | state محلی را از بین میبرد و سپس Finish را به next میفرستد. |
downstream Payload | payload را در یک یا چند فریم عادی encode و به node قبلی ارسال میکند. buffer payloadهای خالی برای استفاده مجدد برمیگردد. |
downstream Est / Pause / Resume | به node قبلی فرستاده میشوند. |
downstream Finish | state محلی را از بین میبرد و سپس Finish را به node قبلی میفرستد. |
downstream Init | غیرفعال؛ رسیدن به این callback بهعنوان chain flow نامعتبر fatal در نظر گرفته میشود. |
پردازش ورودی Framed
بایتهای upstream در یک splice_stream_t جمع میشوند؛ بنابراین ممکن است یک فریم در چند callbackِ payload تکهتکه برسد یا چند فریم در یک callback دریافت شوند.
رفتار decoder محافظهکارانه است:
- وقتی prefix یا body کامل نرسیده، منتظر بایتهای بعدی میماند.
- اگر طول body فریم خارج از بازهٔ
1..1,048,577باشد، line از طریق owner بسته میشود - فریمهای عادی خالی دور ریخته میشوند.
- typeهای ناشناخته فریم دور ریخته میشوند.
- فریمهای کامل ابتدا تخلیه میشوند؛ اگر پس از compaction هزینهٔ تخصیص همچنان بیش از سقف باشد، line بسته میشود
یادداشتهای Buffer و Padding
KeepAliveServer هنگام encode کردن payloadهای downstream، prefix پنجبایتی frame را prepend میکند، بنابراین metadata این node چنین است:
required_padding_left = 5
layer_group = kNodeLayer4
layer_group_next_node = kNodeLayer4
layer_group_prev_node = kNodeLayer4
caller باید padding کافی در سمت چپ برای prefix فراهم کند؛ Debug این پیششرط را assert میکند. محاسبه padding در chain این فضای اعلامشده را رزرو میکند.
نکتههای عملی
- این node را با
KeepAliveClientجفت کنید؛ بهتنهایی مفید نیست. - فریمهای ping و pong داخلی جفت KeepAlive هستند و بهعنوان payload به nodeهای اطراف داده نمیشوند.
- سرور به pingها پاسخ میدهد، اما health سمت client را اندازه نمیگیرد یا pong timeout اعمال نمیکند.
- این node بایتهای payload را رمزنگاری، احراز هویت، فشرده یا بازنویسی نمیکند.
- برای استفادهٔ مطمئن، transport باید بایتهای فریمشده را بین کلاینت و سرور بدون تغییر نگه دارد.
متادیتای نود
metadata برگرفته از کد منبع:
| ویژگی | مقدار |
|---|---|
| node flags | kNodeFlagSupportsSplice |
can_have_prev | true |
can_have_next | true |
layer_group | kNodeLayer4 |
layer_group_prev_node | kNodeLayer4 |
layer_group_next_node | kNodeLayer4 |
required_padding_left | 5 bytes |
پشتیبانی از splice
KeepAliveServer پرچم kNodeFlagSupportsSplice را دارد. framing در تمام طول اتصال ادامه
دارد. decoder از cache پنجبایتی splice_stream_t استفاده میکند و encoder فقط
header پنجبایتی را در padding واقعی سمت چپ مینویسد. بدنهٔ payload میتواند در pipe
باقی بماند. payload بزرگتر از ۱ MiB با عملیات range متناسب با نوع buffer تقسیم میشود. شکست تخصیص pipe یا فشار ظرفیت میتواند fallback کامل به buffer عادی
ایجاد کند. فریمهای کنترلی buffer عادی دارند.
ورودی re-entrant encoder پشت suffix فعال میماند و مجموع آنها به ۸ MiB بایت منطقی و ۱٬۰۲۴ buffer، با احتساب suffix فعال، محدود است. decoder ورودی nested را به ترتیب پردازش میکند؛ بایتهای nested سقف ۸ MiB و هزینهٔ تخصیص باقیمانده سقف ۱۶ MiB دارند. پیش از رد هزینهٔ اضافی، ابتدا compaction به buffer عادی، در صورت کاهش هزینه، امتحان میشود. فریمهای کامل پیش از بررسی هزینهٔ نگهداری تخلیه میشوند. اعتبارسنجی طول فریم تضمین میکند که remainder ناقص، با احتساب header، کوچکتر از ۱ MiB + ۵ بایت باشد. Pause فوری منتقل میشود و پردازش batch همگامِ پذیرفتهشده را قطع نمیکند. Pause و Resume تکراری نیز شفاف منتقل میشوند و Pong آماده منتظر Resume نمیماند. parser ورودی Ping بازگشتی را پشت پاسخ فعال و با همان محدودیتهای ذخیرهسازی نگه میدارد؛ صف مستقلی برای Pong وجود ندارد. framing تا پایان اتصال لازم است؛ بنابراین این node فعال میماند و bypass دائمی نمیشود.
طول بدنهٔ صفر یا بیش از ۱ MiB + ۱، شکست admission یا سرریز ذخیرهسازی، line از نوع borrowed را
از طریق owner میبندد. Finish، فریم ناقص، suffix فعال encoder و صف ورودی re-entrant
را آزاد میکند؛ این node خودش line_t را destroy نمیکند.