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

برای رهایی از تجمع چندین مگابایت داده در صف درایورهای سخت‌افزاری بدون افت نرخ ارسال، اریک دومازه از توسعه‌دهندگان هسته لینوکس سازوکار صف‌های کوچک تی‌سی‌پی (TSQ) را معرفی کرد. این سازوکار با اعمال سقف بایت پویا به ازای هر سوکت میان لایه انتقال و صف‌های سیستم مدیریت ترافیک (qdisc)، شیوه ارسال بسته‌ها را در هسته بازتعریف کرد. آشنایی با جزئیات فنی این سازوکار برای معماران سامانه‌های رمزگذاری‌شده و ارتباطات تونلی با کارایی بالا ضروری است.

سازوکار بافربلوت محلی پیش از ابداع TSQ

پیش از نگارش ۳.۶ هسته لینوکس، پشته شبکه داده‌ها را با بیشترین شتاب مجاز بر مبنای پنجره ازدحام (snd_cwnd) به لایه‌های زیرین هدایت می‌کرد. تا زمانی که فضای خالی در بافر ارسال سوکت وجود داشت، لایه انتقال داده‌ها را در قالب ساختارهای sk_buff بسته‌بندی می‌کرد و بی‌درنگ به صف کنترل ترافیک تحویل می‌داد.

در شرایط ارسال انبوه داده، صدها و گاه هزاران بسته ارسال‌نشده در حلقه حافظه درایور کارت شبکه انباشته می‌شدند. یک جریان سریع به تنهایی می‌توانست ۲ تا ۸ مگابایت داده را در صف‌های نرم‌افزاری ذخیره کند تا به نوبت روی کابل شبکه یا فرستنده بی‌سیم ارسال شوند.

این بافرگذاری بی‌رویه سه پیامد نامطلوب فنی به دنبال داشت:

۱. بزرگ‌نمایی زمان رفت‌وبرگشت (RTT): توقف بسته‌ها به مدت ده‌ها تا صدها میلی‌ثانیه در صف‌های محلی، محاسبات زمان رفت‌وبرگشت را مختل کرده و واکنش الگوریتم‌های مدیریت ازدحام را کند می‌ساخت. ۲. انسداد صف هنگام افت بسته: در صورت بروز افت بسته در مسیر شبکه، مگابایت‌ها داده مانده در صف درایور باید ابتدا ارسال می‌شد تا بسته بازارسالی بتواند وارد خط شود. ۳. تضعیف ارتباطات حساس به تأخیر: دستورات بی‌درنگ خط فرمان، پرس‌وجوهای سامانه نام دامنه (DNS) و مکالمات صوتی که از همان پشته شبکه استفاده می‌کردند، پشت بسته‌های حجیم دانلود گرفتار می‌شدند.

اگرچه الگوریتم‌های مدیریت فعال صف (AQM) مانند CoDel و FQ-CoDel برای مهار صف در کارت شبکه توسعه یافتند، اما اگر لایه بالاتر بسته‌ها را به شکل انفجارهای مهارنشدنی تزریق کند، این الگوریتم‌ها توانایی بهینه‌سازی کامل را از دست می‌دهند. به همین دلیل، به سازوکاری تنظیم‌کننده در مرز لایه انتقال نیاز بود.

چگونگی کنترل دقیق ارسال به ازای هر سوکت در TSQ

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

ره‌گیری متغیر sk_wmem_alloc

هر بسته sk_buff که توسط سوکت ایجاد می‌شود، مقدار شمارنده حافظه نوشتن sk->sk_wmem_alloc را افزایش می‌دهد. این شمارنده شامل بار داده، سرایندها و اطلاعات تکمیلی حافظه هسته است. هنگامی که کارت شبکه فیزیکی یا رابط مجازی ارسال قاب را تکمیل می‌کند، وقفه سخت‌افزاری حافظه ساختار را آزاد می‌سازد (kfree_skb) و در نتیجه مقدار این شمارنده کاهش می‌یابد.

پیش از قطعه‌بندی داده‌ها یا ارسال بسته‌های تازه، پشته شبکه بررسی می‌کند که آیا حجم در صف مانده از حد مجاز فراتر رفته است یا خیر:

static bool tcp_small_queue_check(struct sock *sk, const struct sk_buff *skb, unsigned int factor)
{
    unsigned int limit = max(2 * skb->truesize, sk->sk_pacing_shift);
    limit = min_t(unsigned int, limit, sysctl_tcp_limit_output_bytes);
    
    if (atomic_read(&sk->sk_wmem_alloc) > limit) {
        set_bit(TSQ_THROTTLED, &tcp_sk(sk)->tsq_flags);
        return true; /* توقف موقت تزریق بسته */
    }
    return false;
}

چنانچه حافظه از این سقف فراتر رود، هسته پرچم TSQ_THROTTLED را روی سوکت فعال کرده و ارسال بسته‌های بیشتر را موقتاً متوقف می‌سازد. در نتیجه سوکت سهم پردازش خود را واگذار می‌کند تا صف درایور از حد معین فراتر نرود.

بیدارباش سوکت با وقفه سخت‌افزاری

هنگامی که درایور کارت شبکه ارسال قاب را پایان داده و حافظه را با تابع skb_destroy() آزاد می‌کند، هسته پرچم وضعیت را می‌سنجد. اگر سوکت در حالت تعلیق باشد، یک وظیفه سیستمی در پردازنده (tsq_tasklet) پردازشگر tcp_tsq_handler() را فرامی‌خواند.

این تابع پرچم تعلیق را پاک کرده و اجرای tcp_write_xmit() را آغاز می‌کند تا دسته بعدی بسته‌ها به درایور تحویل شوند. از آنجا که این چرخه در کسری از میلی‌ثانیه رخ می‌دهد، پهنای باند خط ارتباطی کاملاً حفظ شده و بافرهای محلی پیوسته در کمترین حجم ممکن باقی می‌مانند.

هم‌افزایی با تنظیم سرعت ارسال (Pacing) و زمان‌بند Sch_FQ

بیشترین بازدهی TSQ زمانی پدیدار می‌شود که در کنار تنظیم پیوسته سرعت ارسال بسته‌ها (packet pacing) و صف‌بندی منصفانه (sch_fq) به کار رود. این شیوه به جای رهاسازی ناگهانی کل پنجره با دریافت تأییدیه، بسته‌ها را به نرمی در طول زمان رفت‌وبرگشت پخش می‌کند.

هسته لینوکس سقف مجاز صف را با توجه به سرعت لحظه‌ای ارسال سوکت تنظیم می‌نماید:

  • در پیوند ۱ گیگابیت بر ثانیه، ترافیک ۱ میلی‌ثانیه حدود ۱۲۵ کیلوبایت صف مجاز ایجاد می‌کند.
  • در پیوند ۱۰۰ مگابیت بر ثانیه، این سقف به شکل خودکار به حدود ۱۲.۵ کیلوبایت کاهش می‌یابد.

بدین ترتیب، صف دقیقاً متناسب با ظرفیت پیوند مقیاس‌پذیر می‌شود. در ترکیب با sch_fq، هر اتصال صف مجازی مستقلی دریافت می‌کند که تنها به اندازه تأمین ظرفیت خط پر می‌شود و نوسان تأخیر میان برنامه‌های موازی از میان می‌رود.

کاربرد در شبکه‌های تونلی و رابط‌های مجازی TUN

بافربلوت محلی در معماری‌های مبتنی بر ارتباطات اختصاصی مجازی آسیب‌های مضاعفی پدید می‌آورد. در پروتکل‌های تونل‌زنی مانند WireGuard و OpenVPN، داده‌های رمزگذاری‌شده پیش از ورود به کارت شبکه واقعی باید از یک دستگاه شبکه مجازی (tun0 یا wg0) عبور نمایند.

پیامدهای پدیده بافرگذاری دولایه

بدون نظارت TSQ، بسته‌ها دچار انباشتگی دوگانه می‌شوند:

۱. تراکم در رابط مجازی: جریان داخلی بسته‌ها را در صف نرم‌افزاری رابط tun به انتظار رمزگذاری رها می‌کند. ۲. تراکم در رابط فیزیکی: سوکت پروتکل خارجی داده‌های رمزگذاری‌شده را در حلقه کارت شبکه انباشته می‌سازد.

این انباشتگی مضاعف می‌تواند تأخیر دوسویه را در زمان جابه‌جایی فایل‌های سنگین از ۲۰ میلی‌ثانیه به بیش از ۳۵۰ میلی‌ثانیه افزایش دهد. بروز افت بسته در مسیر بیرونی نیز سبب اختلال طولانی در ارسال‌های مجدد داخلی می‌شود.

بهینه‌سازی جریان داده در RiceGuard

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

در پیوند با هسته مسیریابی Core L3 VPN و سازوکار انتقال بدون کپی حافظه، بسته‌های مکالمات صوتی و داده‌های وب در چند میکروثانیه از کنار داده‌های حجیم بارگیری عبور کرده و پیوندی پایدار و بدون نوسان تأخیر در اختیار کاربر قرار می‌گیرد.

روش‌های بررسی و تنظیم متغیرهای هسته

مدیران سیستم می‌توانند تنظیمات TSQ را با ابزارهای استاندارد لینوکس ارزیابی و بهینه‌سازی نمایند.

بررسی و تنظیم سقف بایت مجاز

سقف کلی حجم داده‌ای که یک سوکت می‌تواند در صف‌های پایینی نگه دارد، از طریق متغیر هسته تعیین می‌شود:

# مشاهده سقف بایت کنونی (مقدار پیش‌فرض معمولاً ۲۶۲۱۴۴ بایت یا ۲۵۶ کیلوبایت است)
sysctl net.ipv4.tcp_limit_output_bytes

# تنظیم سقف روی ۱۲۸ کیلوبایت برای دروازه‌های نیازمند تأخیر بسیار پایین
sudo sysctl -w "net.ipv4.tcp_limit_output_bytes = 131072"

پایش رفتار با دستور آماری سوکت

ابزار تشخیصی ss داده‌های دقیقی از وضعیت مداخله TSQ روی اتصال‌ها نمایش می‌دهد:

# مشاهده شاخص‌های درونی اتصالات روی درگاه ۴۴۳
ss -tin '( dport = :443 or sport = :443 )'

شاخص‌های اصلی:

  • wmem_alloc: حجم حافظه نگه‌داری‌شده در انتظار خروج از کارت شبکه.
  • tsq: نشان‌دهنده تنظیم نرخ کنونی سوکت توسط صف‌های کوچک تی‌سی‌پی.
  • pacing_rate: نرخ ارسال یکنواخت بسته‌ها بر پایه محاسبات الگوریتم ازدحام.
  • bytes_acked: مجموع داده‌های با موفقیت تأییدشده.

تثبیت پایدار شاخص wmem_alloc زیر ۱۵۰ کیلوبایت در حداکثر توان ارسال، نشانه عملکرد مطلوب سامانه در مهار بافربلوت است.

جمع‌بندی

صف‌های کوچک تی‌سی‌پی یکی از دستاوردهای بنیادین مهندسی پشته شبکه در لینوکس به شمار می‌رود. با مهار حجم بافرها از همان لایه انتقال، مسئله کهنه بافربلوت محلی برای همیشه در سامانه‌های لینوکسی برطرف شد.

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