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

Disturber

Disturber تونلی آزمایشی برای شبیه‌سازی شرایط نامطلوب شبکه در یک chain از WaterWall است. بدون نیاز به ابزار خارجی می‌تواند قطع اتصال، از دست رفتن payload، خرابی داده، تکرار، جابه‌جایی ترتیب، تأخیر و dead-hang ایجاد کند.

از این نود برای stress test تونل‌هایی استفاده کنید که باید روی مسیرهای ناپایدار تاب بیاورند؛ مانند mux، TCP-over-UDP، HTTP، TLS، packet transport، منطق اتصال مجدد و تونل‌های سفارشی.

هشدار

Disturber عمداً ترافیک را مختل می‌کند. برای تست، debug و سنجش پایداری مناسب است، نه عبور عادی ترافیک در محیط production.

جایگاه رایج

حالت ساده عبوری:

TesterClient -> Disturber -> TesterServer

در کنار transport مورد آزمایش:

TesterClient -> TunnelUnderTest -> Disturber -> PeerUnderTest -> TesterServer

یک تونل در هر دو جهت مسیر:

TesterClient -> Disturber -> TunnelClient -> ... -> TunnelServer -> Disturber -> TesterServer

Disturber socket جداگانه‌ای ندارد. به next نیاز دارد و معمولاً در میانه یک chain از نوع stream یا packet قرار می‌گیرد.

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

  • تا زمانی که اختلالی از نوع بستن اتصال فعال نشود، callbackهای lifecycle را در همان جهت عبور می‌دهد.
  • می‌تواند lineهای عادی را هنگام init فوراً ببندد.
  • می‌تواند lineهای عادی را هنگام payload forwarding ببندد.
  • می‌تواند payload را دور بیندازد یا یک نسخه اضافه از آن بسازد.
  • می‌تواند بایت‌های payload را خراب کند.
  • می‌تواند یک payload را نگه دارد و بعداً آزاد کند تا رسیدن داده خارج از ترتیب شبیه‌سازی شود.
  • می‌تواند payload را برای مدتی تصادفی در بازه تعیین‌شده به تأخیر بیندازد.
  • می‌تواند یک جهت را وارد حالت dead-hang کند تا payloadها در سکوت دور ریخته شوند.
  • در packet lineها، به‌جای آزاد کردن packet line مربوط به worker از dead-hang استفاده می‌کند و قواعد lifetime آن را حفظ می‌کند.

مقدار پیش‌فرض همه فیلدهای chance برابر 0 است. بنابراین، به‌جز تنظیم پیش‌فرض جهت، Disturber بدون تنظیم خاص مانند نودی شفاف و عبوری رفتار می‌کند.

نمونه تنظیم

تنظیم کامل:

{
"name": "disturber",
"type": "Disturber",
"settings": {
"disturb-upstream": true,
"disturb-downstream": true,
"chance_instant_close": 5,
"chance_middle_close": 2,
"chance_payload_corruption": 3,
"chance_payload_loss": 10,
"chance_payload_duplication": 2,
"chance_payload_out_of_order": 4,
"chance_payload_delay": 15,
"chance_connection_deadhang": 1,
"delay_min_ms": 50,
"delay_max_ms": 300
},
"next": "next-node"
}

فقط از دست رفتن packet:

{
"name": "loss",
"type": "Disturber",
"settings": {
"disturb-upstream": true,
"disturb-downstream": false,
"chance_payload_loss": 100
},
"next": "receiver"
}

فیلدهای لازم

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

فیلدنوعتوضیح
namestringنام دلخواه نود که باید در فایل پیکربندی یکتا باشد.
typestringباید دقیقاً "Disturber" باشد.
nextstringبرای استفاده عملی لازم است. نود بعدی ترافیک upstream را می‌گیرد.

settings اختیاری است. اگر آن را ننویسید، همه chanceها مقدار پیش‌فرض خواهند داشت.

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

کنترل جهت‌ها:

گزینهنوعپیش‌فرضتوضیح
disturb-upstreambooleantrueاعمال اختلال روی init و payload در جهت upstream.
disturb-downstreambooleanfalseاعمال اختلال روی init و payload در جهت downstream.

فیلدهای chance:

گزینهنوعپیش‌فرضتوضیح
chance_instant_closeدرصد integer0احتمال بستن مسیر هنگام رسیدن init در جهت فعال.
chance_middle_closeدرصد integer0احتمال بستن هنگام مدیریت payload جهت فعال.
chance_payload_corruptionدرصد integer0احتمال تغییر دادن بایت‌های payload پیش از ارسال.
chance_payload_lossدرصد integer0احتمال دور انداختن payload فعلی.
chance_payload_duplicationدرصد integer0احتمال ساخت یک کپی اضافه از payload.
chance_payload_out_of_orderدرصد integer0احتمال نگه داشتن payload فعلی و آزاد کردن آن در حوالی payload بعدی.
chance_payload_delayدرصد integer0احتمال به تأخیر انداختن payload فعلی.
chance_connection_deadhangدرصد integer0احتمال قرار دادن جهت در dead-hang mode.

فیلدهای delay:

گزینهنوعپیش‌فرضتوضیح
delay_min_msinteger0کمترین تأخیر هنگام فعال شدن delay برای payload. مقادیر منفی به 0 محدود می‌شوند.
delay_max_msinteger0بیشترین تأخیر هنگام فعال شدن delay برای payload. مقادیر کمتر از delay_min_ms به همان مقدار محدود می‌شوند.

احتمال‌ها با roll100 تفسیر می‌شوند: مقادیر <= 0 هرگز رخ نمی‌دهند، مقادیر >= 100 همیشه رخ می‌دهند و مقادیر 1 تا 99 درصد احتمال را نشان می‌دهند.

رفتار جهت‌ها

به‌طور پیش‌فرض فقط مسیر upstream مختل می‌شود:

{
"disturb-upstream": true,
"disturb-downstream": false
}

اگر می‌خواهید مسیر پاسخ نیز مختل شود، disturb-downstream را true کنید. برای ایجاد اختلال فقط در downstream، مقدار disturb-upstream را false بگذارید.

اگر اختلال در یک جهت غیرفعال باشد، payload همان جهت بی‌واسطه عبور می‌کند:

جهتcallback forwarding
upstream payloadtunnelNextUpStreamPayload
downstream payloadtunnelPrevDownStreamPayload

Est، Pause و Resume در هر دو جهت به‌صورت عادی عبور داده می‌شوند.

پردازش Payload

برای هر payload در جهتی که اختلال روی آن فعال است، Disturber موارد زیر را به ترتیب بررسی می‌کند:

  1. اگر جهت از قبل وارد dead-hang شده باشد، payload دور ریخته می‌شود.
  2. chance_middle_close
  3. chance_payload_loss
  4. chance_payload_duplication
  5. chance_payload_corruption
  6. آزاد کردن payload نگه‌داشته‌شده برای ایجاد ترتیب نادرست
  7. chance_payload_out_of_order
  8. chance_payload_delay
  9. chance_connection_deadhang
  10. ارسال عادی

بعضی بررسی‌ها pipeline را همان‌جا متوقف می‌کنند. برای مثال، در payload loss بافر دور ریخته می‌شود و callback برمی‌گردد. Duplication می‌تواند با بررسی‌های بعدی ترکیب شود، زیرا پیش از ادامه pipeline یک بافر اضافه می‌سازد.

جزئیات Disturbance

Instant Close

وقتی init از upstream برسد و disturb-upstream فعال باشد، chance_instant_close ممکن است به‌جای فرستادن init به next، سمت قبلی را ببندد.

وقتی init از downstream برسد و disturb-downstream فعال باشد، chance_instant_close ممکن است به‌جای فرستادن init به نود قبلی، سمت next را ببندد.

Middle Close

وقتی chance_middle_close روی یک line عادی رخ دهد، payload فعلی دور ریخته می‌شود، state محلی Disturber برای line از بین می‌رود و هر دو جهت finish می‌شوند.

Payload Loss

وقتی chance_payload_loss رخ دهد، بافر payload فعلی برای استفاده مجدد برگردانده می‌شود و داده عبور نمی‌کند.

Duplication

وقتی chance_payload_duplication رخ دهد، Disturber یک کپی از بافر می‌سازد و ارسال آن را در همان جهت زمان‌بندی می‌کند. بررسی‌های بعدی همچنان می‌توانند payload اصلی را تغییر دهند.

Corruption

وقتی chance_payload_corruption رخ دهد، چند بایت تصادفی از payload فعلی با XOR تغییر می‌کنند. برای payloadهای غیرخالی، پیاده‌سازی حدود ده درصد داده را خراب می‌کند و دست‌کم یک بایت تغییر می‌یابد.

Out-of-Order Delivery

Disturber برای هر line برای هر جهت حداکثر یک payload نگه می‌دارد.

وقتی out-of-order رخ دهد و payload نگه‌داشته‌شده‌ای وجود نداشته باشد، payload فعلی ذخیره می‌شود و فوراً عبور نمی‌کند. با رسیدن payload بعدی، داده نگه‌داشته‌شده در حوالی آن آزاد می‌شود تا یک جابه‌جایی ساده در ترتیب ایجاد شود.

اگر state مربوط به line در حالی از بین برود که payloadی هنوز نگه داشته شده است، بافر آن برای استفاده مجدد برگردانده می‌شود.

Delay

وقتی chance_payload_delay رخ دهد، تأخیری تصادفی میان delay_min_ms و delay_max_ms انتخاب می‌شود. سپس ارسال payload روی همان line برای زمان بعد برنامه‌ریزی می‌شود.

Dead-Hang

وقتی chance_connection_deadhang رخ دهد، جهت مورد نظر dead-hung علامت می‌خورد. Payload فعلی دور ریخته می‌شود، ساختار line باقی می‌ماند و payloadهای بعدی در همان جهت بی‌سروصدا حذف می‌شوند.

این حالت یک اتصال را شبیه‌سازی می‌کند که هنوز زنده به نظر می‌رسد اما پیشرفتی نمی‌کند.

رفتار packet-line

Disturber قواعد packet line را در نظر می‌گیرد.

برای lineهای اتصال عادی، اختلال‌هایی که اتصال را می‌بندند می‌توانند Finish بفرستند و state مخصوص آن line را در تونل از بین ببرند. اما Disturber در runtime، packet line مربوط به worker را آزاد نمی‌کند. در عوض، instant-close و middle-close جهت آسیب‌دیده را dead-hung می‌کنند و بدون فراخوانی lineDestroy() ادامه می‌دهند.

به این ترتیب هم قواعد lifetime مربوط به packet line در WaterWall حفظ می‌شود و هم می‌توان سناریوهای packet loss و blackhole را آزمایش کرد.

نکته‌ها

  • ترکیب چند chance با مقدار بالا می‌تواند ترافیک بسیار آشفته‌ای بسازد.
  • مقدار chance_payload_duplication = 100 برای تست پروتکل‌های مقاوم در برابر داده تکراری مفید است، اما می‌تواند حجم ترافیک را به‌سرعت چند برابر کند.
  • رفتارهای delay و out-of-order از callbackهای زمان‌بندی‌شده استفاده می‌کنند و می‌توانند باگ‌های re-entrancy و lifetime را در تونل‌های اطراف آشکار کنند.
  • این نود framing اضافه نمی‌کند و required_padding_left = 0 دارد.
  • در حال حاضر callback مربوط به API فقط پیام API را می‌گیرد و بافرش را برای استفاده مجدد برمی‌گرداند؛ امکان تنظیم در runtime وجود ندارد.