اتصال برقرار شد، اما چه کسی آن را پذیرفت؟
کاربری میگوید اتصال به سرویس گاهی کند میشود، در حالی که پردازنده سرور هنوز ظرفیت آزاد دارد. نخستین حدس ممکن است کمبود پهنای باند باشد، اما مسیر پذیرش اتصال چند مرحله دارد و در هر مرحله امکان انتظار وجود دارد. دریافت درخواست اولیه TCP، کاملشدن دستدهی و تحویل اتصال به برنامه یک رویداد واحد نیستند. در لینوکس باید میان اتصالهای هنوز کاملنشده و اتصالهای آمادهای که برنامه آنها را نپذیرفته تفاوت گذاشت. این تفکیک کمک میکند مسئلهای که در صف پذیرش برنامه رخ داده با مشکل مسیر شبکه یا حمله SYN اشتباه نشود.
برنامه معمولاً یک سوکت شنونده ایجاد میکند و با فراخوانی listen آمادگی خود را برای دریافت اتصال اعلام میکند. سپس با accept یا سازوکار معادل، اتصالهای آماده را دریافت میکند. حتی اگر هسته بتواند دستدهی را انجام دهد، برنامه باید به اندازه کافی سریع این اتصالها را بردارد. بنابراین شنونده باز و پاسخگویی شبکه، به معنی ظرفیت نامحدود برای پذیرش کار جدید نیست. فشار ممکن است از حلقه رویداد مسدود، کمبود worker، محدودیت توصیفگر فایل یا فعالیت طولانی در مسیر پذیرش ناشی شود. هر کدام از این علتها به بررسی جداگانه نیاز دارند.
صف درخواستهای نیمهکامل چه کاری میکند؟
پیش از کاملشدن دستدهی، هسته باید اطلاعاتی درباره درخواست اتصال نگه دارد. تعداد این درخواستها و مدت ماندن آنها میتواند تحت تأثیر تأخیر شبکه، از دست رفتن بسته یا رفتار مخرب قرار بگیرد. پارامتر tcp_max_syn_backlog در مستندات لینوکس به ظرفیت مربوط به درخواستهای اتصال یادشده مرتبط است. اما دیدن این نام نباید ما را به این نتیجه برساند که همه مشکلهای اتصال با افزایش آن حل میشوند. ابتدا باید ثابت شود فشار واقعاً در همین مرحله رخ میدهد. اگر دستدهی کامل شده و برنامه accept نمیکند، این پارامتر مسئله اصلی را هدف نمیگیرد.
در یک شبکه با تأخیر زیاد، تعداد بیشتری درخواست ممکن است همزمان در وضعیت میانی باقی بمانند، حتی اگر نرخ درخواست غیرعادی نباشد. در مقابل، موجی از درخواستهایی که هرگز کامل نمیشوند نیز میتواند همین منابع را مصرف کند. تفاوت این دو از نظر پاسخ عملیاتی مهم است. محدودیت یا فیلتر تهاجمی ممکن است کاربران واقعی مسیرهای کند را آسیب بزند. بررسی باید نرخ درخواست، نسبت تکمیل دستدهی، توزیع مبدأ و الگوی زمانی را کنار هم ببیند. شمار خام یک وضعیت TCP بدون زمینه بار و مسیر، برای اعلام حمله یا انتخاب یک مقدار جدید کافی نیست.
صف accept و نقش somaxconn
پس از آمادهشدن اتصال برای تحویل به برنامه، ظرفیت صف پذیرش اهمیت پیدا میکند. برنامه هنگام listen عددی برای backlog درخواست میکند و هسته محدودیتهای خود را اعمال میکند. somaxconn سقفی در این زمینه است، اما مقدار نهایی تنها با تنظیم این سقف مشخص نمیشود؛ درخواست خود برنامه نیز اهمیت دارد. اگر برنامه backlog کوچکی درخواست کند، افزایش سقف سیستم الزاماً آن را بزرگ نمیکند. به همین دلیل باید تنظیمات وبسرور، کتابخانه یا سرویس مقصد را همراه با تنظیم هسته بررسی کرد. این دو لایه نباید مستقل از هم تغییر داده شوند.
صف بزرگتر میتواند جهش کوتاه ترافیک را جذب کند، اما وقتی نرخ ورود برای مدت طولانی از نرخ پذیرش بیشتر باشد، هر صف محدودی سرانجام پر میشود. تفاوت تنها در زمان پرشدن و میزان انتظار کاربران است. در چنین وضعیتی، افزایش backlog ممکن است خطا را موقتاً کم کند ولی تأخیر انتهایی را بالا ببرد. تصمیم باید بر پایه بودجه زمان پاسخ باشد. اگر درخواست پس از چند ثانیه دیگر ارزشی ندارد، نگهداشتن آن در صف طولانی لزوماً خدمت بهتری نیست. کنترل بار و افزایش ظرفیت مؤثر برنامه باید در کنار اندازه صف بررسی شوند.
چرا CPU آزاد گمراهکننده است؟
میانگین استفاده پردازنده میتواند پایین باشد در حالی که یک رشته مسئول پذیرش اتصال متوقف شده است. برنامهای که حلقه رویداد واحد دارد ممکن است با عملیات مسدودکننده یا callback طولانی از accept بازبماند. سرویس دیگری ممکن است منتظر قفل داخلی، دیسک یا پاسخ یک وابستگی باشد. بنابراین معیار کلی CPU برای ردکردن گلوگاه برنامه کافی نیست. باید رفتار threadها، صف کار داخلی و زمان صرفشده در مسیر پذیرش دیده شود. همچنین توزیع بار میان پردازندهها مهم است؛ میانگین پایین روی یک ماشین بزرگ میتواند اشباع یک هسته خاص را پنهان کند.
محدودیت تعداد فایل باز نیز میتواند مسیر پذیرش را مختل کند. هر اتصال منابعی مصرف میکند و برنامه ممکن است پیش از رسیدن به سقف شبکه به محدودیت فرایندی برسد. در این حالت گزارش خطای برنامه و وضعیت توصیفگرها شواهد مهمی هستند. افزایش اندازه صف بدون رفع این محدودیت فقط تعداد بیشتری اتصال منتظر تولید میکند. باید میان محدودیت سیستم، محدودیت واحد سرویس و تنظیم خود برنامه تفاوت گذاشت. اگر تغییری انجام میشود، اثر آن بر مصرف حافظه و تعداد اتصالهای قابل نگهداری نیز باید محاسبه شود تا گلوگاه از یک منبع به منبع دیگر منتقل نشود.
SYN cookies ابزار دفاع است، نه ظرفیت نامحدود
SYN cookies برای شرایط فشار بر صف درخواستهای نیمهکامل طراحی شدهاند و به هسته کمک میکنند بدون نگهداری معمول همه وضعیتهای اولیه، بخشی از مسیر دستدهی را مدیریت کند. مستندات هسته تأکید میکنند که این سازوکار جای تنظیم صحیح ظرفیت برای بار مشروع نیست. فعالبودن آن را نباید به معنی بینیازی از پایش دانست. افزایش رخدادهای مرتبط میتواند نشانه فشار باشد و باید در زمینه سایر شمارندهها تفسیر شود. همچنین رفتار دقیق به نسخه هسته و تنظیمات وابسته است؛ نسخههای مختلف ممکن است در پشتیبانی گزینهها و جزئیات عملکرد تفاوت داشته باشند.
اگر سامانه به طور مداوم به مسیر اضطراری متکی است، باید علت پایدار فشار پیدا شود. ممکن است ظرفیت واقعی شنونده کم باشد، ترافیک نامطلوب وارد شود یا تنظیمی متناسب با مقیاس فعلی نباشد. خاموشکردن یک کنترل دفاعی برای ناپدیدشدن شمارنده هشدار، مشکل را حل نمیکند. از طرف دیگر، اعلام حمله صرفاً بر اساس فعالشدن این مسیر نیز شتابزده است. دادههای شبکه، نرخ تکمیل و تجربه کلاینت باید کنار هم قرار گیرند. هدف عملیات، حفظ دسترسپذیری با کمترین آسیب به درخواست مشروع است، نه فقط صفرکردن یک عدد در داشبورد.
ابزار مشاهده باید مرحله مشکل را روشن کند
ابزاری مانند ss برای مشاهده سوکتها و صفها مفید است، اما معنای ستونها با نوع سوکت و وضعیت آن تغییر میکند. مقادیر یک سوکت LISTEN را نباید همانند شمار بایتهای یک اتصال برقرار تفسیر کرد. پیش از تبدیل خروجی به هشدار، باید معنای دقیق آن در ابزار و هسته مورد استفاده بررسی شود. گرفتن نمونههای پیوسته در زمان بروز مسئله از یک خروجی بعد از حادثه ارزشمندتر است. جهش صف ممکن است تنها چند ثانیه طول بکشد و در بررسی دیرهنگام کاملاً ناپدید شده باشد، در حالی که کاربران خطا را تجربه کردهاند.
شمارندههای TCP و گزارشهای برنامه مکمل این مشاهده هستند. تغییر شمارندههای سرریز یا حذف در بازه زمانی حادثه به پیدا کردن لایه فشار کمک میکند. مقدار تجمعی از زمان راهاندازی به تنهایی نرخ فعلی مشکل را نشان نمیدهد. بهتر است اختلاف دو نمونه با فاصله معلوم محاسبه شود و همزمان نرخ اتصال جدید ثبت شود. اگر چند سرویس روی میزبان وجود دارد، شمارنده سراسری ممکن است مربوط به سرویس دیگری باشد. برای نسبتدادن مشکل باید شواهد در سطح شنونده، فرایند یا مسیر ترافیک نیز جمعآوری شود. مشاهده بدون تفکیک دامنه میتواند اصلاح را به سرویس اشتباه هدایت کند.
از backlog تا صفهای بعدی
پذیرفتهشدن اتصال پایان انتظار نیست. پس از accept، برنامه ممکن است درخواست را در صف worker قرار دهد، برای اتصال پایگاه داده منتظر بماند یا در محدودیت همزمانی یک سرویس بیرونی متوقف شود. بزرگکردن صف TCP ممکن است فقط ازدحام را به صف داخلی منتقل کند. یک نقشه ساده از مراحل درخواست کمک میکند: دستدهی، پذیرش، خواندن درخواست، پردازش و پاسخ. برای هر مرحله باید زمان و ظرفیت تقریبی مشخص باشد. اگر تنها زمان کلی پاسخ دیده شود، تشخیص اینکه تأخیر از شبکه است یا از کار برنامه دشوار خواهد بود.
استفاده از اتصالهای پایدار نیز الگوی فشار را تغییر میدهد. تعداد زیاد درخواست HTTP الزاماً به معنی تعداد زیاد اتصال TCP جدید نیست. در مقابل، کلاینتی که مرتب اتصال را میبندد و دوباره باز میکند، ممکن است بار پذیرش بالایی ایجاد کند حتی اگر حجم داده کم باشد. تحلیل باید نرخ اتصال جدید را از نرخ درخواست جدا کند. تنظیم keepalive، رفتار پراکسی و محدودیتهای کلاینت میتوانند روی این رابطه اثر بگذارند. با این حال طولانیکردن عمر اتصالها نیز منابع مصرف میکند؛ انتخاب مناسب وابسته به الگوی واقعی استفاده و سیاست زمان بیکاری است.
یک آزمایش تغییر قابل اعتماد
فرض کنیم در یک جهش کوتاه ترافیک، صف پذیرش پر میشود و برنامه بعد از چند ثانیه به وضعیت عادی برمیگردد. ابتدا backlog درخواستشده برنامه، سقف سیستم و سرعت accept ثبت میشوند. سپس در محیط آزمون بار مشابه بازتولید میشود و تنها یک متغیر تغییر میکند. معیار موفقیت باید هم کاهش خطا و هم محدودماندن زمان انتظار باشد. اگر فقط تعداد اتصال موفق بیشتر شود اما زمان پاسخ از نیاز سرویس عبور کند، نتیجه کامل نیست. همچنین مصرف حافظه و رفتار برنامه در پایان جهش باید بررسی شود تا انباشت کار پنهان باقی نماند.
برای فشار پایدار، راهحل ممکن است افزایش worker مناسب، اصلاح کد مسدودکننده، توزیع بار یا محدودکردن نرخ ورود باشد. تنظیمات هسته باید از شواهد پیروی کنند و در پیکربندی پایدار ثبت شوند. پیش از انتشار عمومی مقدارهای پیشنهادی نیز باید نسخه هسته و محیط آزمون ذکر شود؛ اعداد آماده برای همه ماشینها وجود ندارند. تفاوت اصلی این است که صف، ظرفیت انتظار را تعریف میکند و برنامه، ظرفیت انجام کار را. وقتی این دو مفهوم جدا اندازهگیری شوند، backlog از یک پارامتر مرموز به ابزاری روشن برای مدیریت جهش اتصال تبدیل میشود و عیبیابی مسیر مشخصی پیدا میکند.