شکست در راه‌اندازی OpenVPN غالباً به شکل شکایتی درباره منابع همراه با پیشنهادی خیرخواهانه برای بالا بردن یک محدودیت می‌آید، و این پیشنهاد تنها حدود نیمی از مواقع کار می‌کند. پشت این شکست‌ها دو شمارنده بی‌ارتباط ایستاده‌اند. یکی محدودیت هسته بر تعداد کارهایی است که یک شناسه کاربر واقعی مالک آن‌هاست و هنگام اجرای فرآیند به ارث می‌رسد. دیگری بودجه‌ای از cgroup است که مدیر سرویس آن را بر یک واحد و هر چیزی که از آن منشعب می‌شود اعمال می‌کند. خواندن مقدار مؤثر هر یک، برای واحدی که واقعاً اجرا می‌شود، از یک حدس کم‌هزینه‌تر است.

دو شمارنده، دو پرسش

LimitNPROC همان RLIMIT_NPROC زیر نامی از systemd است و واحد حسابداری آن شناسه کاربر واقعی است. هر فرآیندی که آن کاربر مالک آن است در برابر همان مجموع شمرده می‌شود، از جمله کاری که واحدهای دیگر، یک نشست ورود یا یک کار زمان‌بند آغاز کرده‌اند. بنابراین این محدودیت حتی وقتی درون یک واحد سرویس تنظیم می‌شود سقفی برای هر سرویس نیست، و سرویسی که برای هر کلاینت یک کمک‌کننده منشعب می‌کند با هر چیز دیگری که زیر آن حساب اجرا می‌شود رقابت می‌کند. یک کار cron پرمشغله زیر همان کاربر می‌تواند یک واحد VPN را از خطی عبور دهد که خودش هرگز به‌تنهایی از آن نگذشته است.

TasksMax مالک دیگری دارد: کنترل‌کننده pids روی cgroup واحد، که کارها را می‌شمارد نه فرآیندها. رشته‌ها نیز کار هستند، پس برنامه‌ای که تک‌رشته‌ای به نظر می‌رسد اما مجموعه‌ای از کارگران دارد می‌تواند بودجه‌ای مصرف کند که در نگاه اول بسیار بزرگ‌تر از تعداد فرآیندهایش به نظر می‌رسد. EffectiveTasksMax گزارش می‌دهد سلسله‌مراتب cgroup پس از آنکه برش‌های والد حرف خود را زدند در واقع چه چیزی را مجاز می‌داند.

چرا استثنای root پاسخ را تغییر می‌دهد

هسته RLIMIT_NPROC را بر فرآیندی که CAP_SYS_RESOURCE یا CAP_SYS_ADMIN دارد اعمال نمی‌کند، و به همین دلیل واحدی که بدون واگذاری امتیازها به‌عنوان root اجرا می‌شود عملاً با آن تنظیم بی‌حد است. همین استثنای یگانه توصیه‌های متناقضی را توضیح می‌دهد که مردم رد و بدل می‌کنند: بالا بردن LimitNPROC استقراری را که امتیازها را واگذار کرده تعمیر می‌کند و برای استقراری که امتیازها را نگه داشته هیچ کاری نمی‌کند. پیش از نسبت دادن امتیاز یا سرزنش به آن تنظیم، User= و اینکه برنامه پس از راه‌اندازی هویت خود را عوض می‌کند یا نه را بررسی کنید. واحدی که امتیازها را دارد و بعداً به حسابی بدون امتیاز تغییر می‌کند، در همان لحظه تغییر دوباره زیر محدودیت می‌رود، و همین خط زمانی شکست را نیز ارزش خواندن می‌دهد.

مرحله شکست آن را باریک‌تر می‌کند. امتناع در هنگام آماده‌سازی اجرا، خطای انشعاب که خود برنامه گزارش می‌کند و رد شدن ایجاد کار درون cgroup خطوط journal متفاوتی تولید می‌کنند، و تنها یکی از آن‌ها با بودجه‌ای بزرگ‌تر پاسخ داده می‌شود.

مقادیر مؤثر را بخوانید، نه مقادیر پوسته را

ulimit -u یک پوسته تعاملی همان پوسته را توصیف می‌کند. توصیف نمی‌کند که مدیر سرویس چه چیزی به برنامه داده است و درباره حسابداری cgroup چیزی نمی‌گوید. به‌جای آن از خود واحد بپرسید، با نام نمونه‌ای که روی میزبان وجود دارد نه مثالی از یک راهنما.

systemctl show [email protected] -p User -p LimitNPROC -p TasksCurrent -p TasksMax -p EffectiveTasksMax
cat /proc/$(systemctl show -p MainPID --value [email protected])/limits | grep -i processes

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

اندازه اصلاح را تعیین کنید و آن را زیر بار اثبات کنید

عددی را از بار کاری انتخاب کنید نه از متن خطا. فرآیندهایی را که برنامه برای هر کلاینت متصل یا هر فراخوانی کمک‌کننده آغاز می‌کند بشمارید، در هم‌روندی‌ای که انتظار می‌رود استقرار تحمل کند ضرب کنید، حاشیه‌ای برای نشست‌های مدیریتی بیفزایید و سپس آن عدد را با دو مقدار مؤثر مقایسه کنید. یک بازنویسی محلی از نوع drop-in تغییر را قابل بازبینی نگه می‌دارد و از ارتقاهای بسته جان سالم به در می‌برد، در حالی که ویرایش یک فایل واحد ارائه‌شده تغییر را تا زمانی که به‌روزرسانی بعدی جایگزینش کند پنهان می‌کند. حساب‌وکتاب را کنار بازنویسی بنویسید، زیرا نفر بعدی که آن را بالا یا پایین می‌برد به فرض‌ها نیاز دارد نه به عدد نهایی.

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

sudo systemctl daemon-reload
sudo systemctl restart [email protected]
systemctl show [email protected] -p TasksCurrent -p EffectiveTasksMax
sudo journalctl -u [email protected] -b --no-pager | tail -n 20

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

مقالات مرتبط