من خوشحالم که اجرای یک فرمول تبدیل بهبودیافته برای نگاشت اشتراک‌های CPU در cgroup v1 به وزن‌های CPU در cgroup v2 توسط Itamar Holder (Red Hat) اعلام شده است 🚀. این تغییر برای بهبود تخصیص اولویت CPU در بارهای کاری Kubernetes روی سیستم‌هایی که از cgroup v2 استفاده می‌کنند طراحی شده است.

پیش‌زمینه: Kubernetes در ابتدا حول cgroup v1 طراحی شد؛ جایی که تخصیص CPU با cpu.shares (معمولاً به شکل millicpu و مثال 1024m برای 1 CPU) بیان می‌شد. با معرفی cgroup v2، مفهوم cpu.shares جای خود را به cpu.weight داد که بازه‌اش متفاوت است (برای weight از 1 تا 10000 و برای shares بازه‌ای بزرگ‌تر). برای جلوگیری از تغییر معنای اولویت CPU، قبلاً یک فرمول تبدیل خطی بین این دو محدوده پیشنهاد شده بود که مشکلات عملکردی و دانه‌بندی ایجاد کرد.

فرمول تبدیل قبلی (خطی) به این شکل بود که مقادیر cpu.shares را به cpu.weight نگاشت می‌کرد:

[pyaml]
cpu.weight = (1 + ((cpu.shares – 2) * 9999) / 262142)
[/pyaml]

مشکلات اصلی فرمول قدیمی دو مورد بود:

1) کاهش اولویت در برابر فرآیندهای خارج از Kubernetes: در cgroup v1 مقدار پیش‌فرض cpu.shares برای یک کانتینر با درخواست 1 CPU برابر 1024 بود. اما با فرمول خطی بالا، آن کانتینر در cgroup v2 به وزنی کمتر از مقدار پیش‌فرض سیستم منتقل می‌شد که باعث افت اولویت در برابر فرآیندهای سیستمی می‌گردد — مسئله‌ای که در محیط‌هایی با دیمون‌های زیاد یا در شرایط کمبود منابع می‌تواند شدید باشد ⚠️.

مثال عملی از اثر منفی فرمول قدیمی:

[pyaml]
# فرض: cpu.shares = 1024 (درخواست 1 CPU)
# با فرمول قبلی:
cpu.weight ≈ 39 # بسیار کمتر از پیش‌فرض cgroup v2 که معمولاً 100 است
[/pyaml]

2) دانه‌بندی نامناسب برای درخواست‌های کوچک CPU: فرمول خطی مقادیر بسیار کمی برای درخواست‌های مانند 100m تولید می‌کرد که عملاً امکان ایجاد زیرگروه‌های با دانه‌بندی خوب داخل کانتینر را از بین می‌برد و مدیریت دقیق منابع را دشوار می‌ساخت.

مثال دانه‌بندی ضعیف با فرمول قبلی:

[pyaml]
# فرض: درخواست 100m -> در cgroup v1 حدود cpu.shares = 102
# در cgroup v2 (با فرمول قدیمی) وزن به اندازه‌ای کوچک می‌شود:
cpu.weight = 4 # خیلی کم؛ غیرقابل استفاده برای تقسیم‌بندی داخلی
[/pyaml]

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

[pyaml]
cpu.weight = ⌈10^(L^2/612 + 125L/612 – 7/34)⌉
where:
L = log2(cpu.shares)
[/pyaml]

نتایج عملی فرمول جدید:

– یک کانتینر با درخواست 1 CPU (1024m) حالا تقریباً cpu.weight = 102 می‌گیرد، که نزدیک به مقدار پیش‌فرض 100 در cgroup v2 است و نسبت اولویت بین بارهای Kubernetes و فرآیندهای سیستمی را حفظ می‌کند ⚖️.

– دانه‌بندی برای درخواست‌های کوچک به‌طور قابل توجهی بهتر شده است، بنابراین امکان ایجاد زیرگروه‌های دقیق‌تر و توزیع منصفانه‌تر منابع داخل یک کانتینر فراهم می‌شود 🛠️.

پیاده‌سازی و پذیرش: این تغییر در لایه زمان‌اجرای OCI پیاده‌سازی شده و خود Kubernetes آن را مستقیماً اعمال نمی‌کند؛ بنابراین پذیرش عمومی این تبدیل بستگی به به‌روزرسانی runtimes دارد. برای نمونه:

– runc: فعال‌سازی از نسخه 1.3.2
– crun: فعال‌سازی از نسخه 1.23

تأثیر بر ابزارها و استقرارهای موجود: اگر ابزارها یا اسکریپت‌هایی به‌طور مستقیم مقدار cpu.weight را بر اساس فرمول قدیمی محاسبه یا اعتبارسنجی می‌کردند، اکنون ممکن است نیاز به بروزرسانی داشته باشند. مواردی که باید به آنها توجه کنید شامل ابزارهای مدیریت منابع سفارشی، سیستم‌های مانیتورینگ که مقادیر وزن خاص را انتظار دارند، و برنامه‌هایی است که به‌صورت برنامه‌نویسی وزن CPU را تنظیم یا بررسی می‌کنند.

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

برای جزئیات فنی عمیق‌تر، مثال‌ها و بحث‌های انتخاب این فرمول، می‌توانید به GitHub و KEPهای مرتبط مراجعه کنید: شماره 131216، KEP-2254، و مستندات مدیریت منابع Kubernetes. اگر علاقه‌مند به مشارکت هستید، گروه‌های مدیریت منابع در اکوسیستم Kubernetes همیشه از دیدگاه‌های مختلف و مشارکت‌های جدید استقبال می‌کنند — همکاری شما می‌تواند به بهبود این تبدیل و تجربه عملی در تولید کمک کند 🤝.