علت بالا رفتن CPU steal time در سرور مجازی
شاخص steal time نشان میدهد پردازنده شما به دلیل فعالیت همسایهها در سرور فیزیکی معطل مانده است. با دستور vmstat و ستون st تشخیص دهید مشکل از بار کاری شماست یا همسایه پرمصرف.
معنای واقعی CPU steal time
شاخص CPU steal time، سهمی از زمان است که vCPU شما آمادهٔ اجرا بوده و هیچ منبعی برای انتظار نداشته، اما هایپروایزر (hypervisor)، هستهٔ فیزیکی را به یک guest دیگر اختصاص داده است. در این حالت، پردازش در صف قرار گرفته و هسته در جای دیگری مشغول بوده است. لینوکس این چرخهها را بهطور جداگانه محاسبه کرده و آنها را به عنوان st گزارش میدهد؛ این همان روشی است که تفاوت بین «سرور من مشغول است» و «سرور من منتظر نوبت خود است» را مشخص میکند.
همین تفاوت، دلیل اصلی وجود این شمارنده است. زمانی که پردازشهای شما روی CPU صرف میکنند، به عنوان us (کاربر) یا sy (سیستم) گزارش میشود. زمانی که یک تسک به دلیل انتظار برای حافظه جانبی مسدود شده، به عنوان wa (I/O wait) گزارش میشود. یک vCPU که آمادهٔ اجراست، در صف اجرا قرار دارد، هیچ عملیات I/O معلقی ندارد، اما همچنان اجرا نمیشود، به عنوان st گزارش میشود. هیچ چیزی در داخل سرور شما نمیتواند این وضعیت را تغییر دهد، زیرا تصمیمگیری برای زمانبندی (scheduling) یک لایه پایینتر از شما، یعنی در سطح host انجام میشود.
این موضوع مستقیماً از نحوه اشتراکگذاری یک ماشین فیزیکی توسط VPS بین چندین guest ناشی میشود. دلیل معمول این اتفاق، یک همسایه است: guest دیگری روی همان node با بار کاری سنگین در حال اجراست و host هستهها را بین شما تقسیم میکند. دلیل دومی هم وجود دارد که اغلب نادیده گرفته میشود. بسیاری از ارائهدهندگان، سقف مصرف vCPU اشتراکی را به کسری از یک هسته فیزیکی محدود میکنند و در بسیاری از هایپروایزرها، این محدودیت اعمالشده، در داخل guest به عنوان steal محاسبه میشود. بنابراین، مقدار بالای st به شما میگوید که هسته در اختیار شما قرار نگرفته است. این شاخص همیشه نمیگوید چه کسی آن را اشغال کرده است.
منشأ عدد steal
هسته سیستمعامل شما نمیتواند steal را بهتنهایی اندازهگیری کند، زیرا دیدی نسبت به میزبان (host) ندارد. هایپروایزر این اطلاعات را به آن اعلام میکند. در KVM، میزبان یک شمارنده برای هر vCPU در صفحهای که با مهمان (guest) به اشتراک گذاشته شده مینویسد و مهمان آن را جمع میزند، مشروط بر اینکه هسته با CONFIG_PARAVIRT_TIME_ACCOUNTING کامپایل شده باشد؛ قابلیتی که در تمام هستههای توزیعهای استاندارد فعال است. Xen نیز همین اطلاعات را از طریق ناحیه runstate گزارش میدهد. مجموع این مقادیر دقیقاً در یک نقطه به فضای کاربری (userspace) میرسد:
head -1 /proc/statآن خط cpu شامل ده شمارنده است که بر حسب تیکهای USER_HZ از زمان بوت محاسبه شدهاند و به این ترتیب هستند: user، nice، system، idle، iowait، irq، softirq، steal، guest، guest_nice. مقدار steal هشتمین عدد بعد از برچسب است. تمام ابزارهای زیر، یعنی vmstat، top، mpstat و هر Prometheus exporter، همان فیلد را میخوانند و دو نمونهبرداری را به درصد تبدیل میکنند.
یک پیامد از بقیه مهمتر است. اگر هایپروایزر هرگز این شمارنده را صادر نکند، فیلد برای همیشه روی صفر باقی میماند و تمام ابزارهای مبتنی بر آن، در حالی که میزبان تحت فشار شدید است، وضعیت آرام 0.0 را گزارش میدهند. KVM و Xen این مقدار را صادر میکنند. مهمانها در VMware و Hyper-V معمولاً عدد صفر مطلق را گزارش میدهند. پیش از اعتماد به عدد صفر، پلتفرم را بررسی کنید:
systemd-detect-virtاین دستور نام پلتفرم را چاپ میکند، مانند kvm، xen، vmware یا microsoft، و در سختافزار فیزیکی (bare metal) مقدار none را نشان میدهد. داخل یک کانتینر، این دستور به جای آن، runtime مورد استفاده مانند lxc، docker یا podman را گزارش میدهد که اطلاعاتی درباره کانتینر به شما میدهد، نه ماشینی که زیر آن قرار دارد. در kvm، عدد صفر گواه واقعی بر این است که میزبان منابع کافی در اختیار شما قرار داده است. در پلتفرمی که هرگز این فیلد را پر نمیکند، صفر هیچ ارزشی ندارد و برای تشخیص رقابت بر سر منابع (contention)، باید زمانبندی اجرای کارهای واقعی را ملاک قرار داد.
چگونه میتوانم CPU steal time را در یک VPS بررسی کنم؟
vmstat از بسته procps میآید. این ابزار تقریباً در تمام ایمیجهای VPS اوبونتو و دبیان موجود است، اما در برخی ایمیجهای حداقلی کانتینر وجود ندارد؛ بنابراین پیش از استفاده، آن را نصب کنید.
sudo apt-get update
sudo apt-get install -y procps
vmstat --version
vmstat 1 5vmstat --version خطی مانند vmstat from procps-ng 4.0.4 را چاپ میکند. اگر این خروجی نمایش داده شد، ابزار نصب است و شما در حال خواندن شمارندههای واقعی هستید. vmstat 1 5 سپس 5 نمونه با فاصله زمانی یک ثانیه تهیه میکند.
procs -----------memory---------- ---swap-- -----io---- -system-- -------cpu-------
r b swpd free buff cache si so bi bo in cs us sy id wa st gu
1 0 0 3216484 98304 1284360 0 0 4 18 62 110 3 1 96 0 0 0
2 0 0 3216232 98304 1284360 0 0 0 0 248 431 6 2 84 0 8 0ستون st را در بلوک cpu در سمت راست پیدا کنید. نسخههای فعلی procps-ng یک ستون gu برای زمان KVM guest بعد از آن چاپ میکنند، بنابراین st به جای آخرین ستون، دومین ستون از سمت راست است. ستون را بر اساس نام سربرگ آن بخوانید، زیرا این موقعیت در نسخههای مختلف تغییر کرده است.
دو عادت باعث میشود خوانش شما دقیق باقی بماند. اولین خط داده، میانگین از زمان بوت است، بنابراین آن را نادیده بگیرید و خطوط بعدی را بخوانید. همچنین یک نمونه، اندازهگیری محسوب نمیشود، زیرا steal به صورت ناگهانی رخ میدهد: vmstat 1 60 را اجرا کنید و یک دقیقه کامل آن را مشاهده کنید تا بتوانید نتیجهگیری کنید.
top همان عدد را در خط خلاصه %Cpu(s) خود، در فیلد مشخصشده با st گزارش میدهد:
%Cpu(s): 6.2 us, 2.1 sy, 0.0 ni, 83.9 id, 0.0 wa, 0.0 hi, 0.3 si, 7.5 stبرای جزئیات هر هسته، sysstat را اضافه کنید:
sudo apt-get install -y sysstat
mpstat -P ALL 1 5mpstat یک ردیف برای هر CPU با ستون %steal چاپ میکند که نشان میدهد آیا تمام vCPUها تحت تأثیر قرار گرفتهاند یا فقط یکی از آنها. برای تاریخچهای که یک تیکت پشتیبانی به آن نیاز دارد، به جای خواندن از روی صفحه، نمونهها را ذخیره کنید:
date -u | tee -a ~/steal.log
mpstat -P ALL 1 5 | tee -a ~/steal.logآن را از طریق cron در ساعاتی که مشکوک هستید اجرا کنید. این فایل تفاوت بین گفتنِ «دیشب کند بود» به ارائهدهنده خدمات و نشان دادن دقیقِ آن ده دقیقه به آنهاست.
اعداد steal به چه معنا هستند؟
- یک
0.0ثابت. وضعیت سالم است، یا پلتفرم اصلاً steal را گزارش نمیکند. پیش از اطمینان، باsystemd-detect-virtبررسی کنید. - جهشهای چند درصدی که چند ثانیه طول میکشند. در هر نود اشتراکی عادی است. ممکن است بیلد یکی از همسایهها شروع شده باشد یا میزبان در حال اجرای بکآپهای خود باشد.
- 1 تا 5 درصد پایدار در پلنهای اشتراکی. مورد انتظار است. قیمت پرداختی شما، بازتابدهنده همین CPU اشتراکی است.
- 5 تا 10 درصد پایدار. کندی محسوسی که میتوانید اندازهگیری کنید. شروع به ثبت شواهد کنید و ساعات مشابه را در طول چند روز مقایسه کنید.
- بالای 10 درصد برای ساعتهای متوالی. نود برای حجم کاری شما بیش از حد شلوغ (oversubscribed) است. این سطحی است که ارسال تیکت پشتیبانی یا جابهجایی سرور را توجیه میکند.
این بازهها را به عنوان یک راهنمای خواندن در نظر بگیرید، نه یک مشخصات فنی؛ چرا که هیچ ارائهدهندهای در پلنهای اشتراکی تضمینی برای میزان steal ارائه نمیدهد. آنها را با آنچه اجرا میکنید بسنجید. یک پردازش دستهای (batch job) شبانه میتواند 15 درصد steal را تحمل کند و کسی متوجه نشود. اما یک سرویس حساس به تأخیر، بسیار پیش از آنکه میانگین اعداد نگرانکننده به نظر برسند، تأثیر آن را در p99 نشان میدهد؛ به همین دلیل است که بارهای کاری حساس به تأخیر مانند رباتهای معاملهگر باید روی هستههای اختصاصی اجرا شوند.
هزینه steal time برای شما چقدر است؟
محاسبه آن کوتاه است. اگر کسری از زمان CPU شما به میزان s گرفته شود، کاری که به مقدار ثابتی از CPU نیاز دارد، 1 / (1 - s) برابر بیشتر زمان میبرد. برای کاری که به 60 ثانیه زمان CPU نیاز دارد:
The data behind this chart
[
{
"steal_percent": 0,
"wall_clock_seconds": "60.0"
},
{
"steal_percent": 3,
"wall_clock_seconds": "61.9"
},
{
"steal_percent": 8,
"wall_clock_seconds": "65.2"
},
{
"steal_percent": 15,
"wall_clock_seconds": "70.6"
},
{
"steal_percent": 25,
"wall_clock_seconds": "80.0"
},
{
"steal_percent": 40,
"wall_clock_seconds": "100.0"
}
]در 3 درصد، که یک مقدار معمول در پلنهای اشتراکی است، آن کار به جای 60.0 ثانیه، 61.9 ثانیه زمان میبرد. هیچکس برای این مورد تیکت پشتیبانی باز نمیکند. در 8 درصد، این زمان 65.2 ثانیه است. در 40 درصد، همان کار به 100.0 ثانیه نیاز دارد و صفی که قبلاً تخلیه میشد، شروع به رشد میکند.
اینها مقادیر محاسبهشده هستند، نه اندازهگیریشده. این مدل فرض میکند که یک thread قابل اجرا وجود دارد و steal بهطور یکنواخت در طول بازه زمانی پخش شده است. سرویسهای واقعی اغلب بدتر از این منحنی عمل میکنند، زیرا یک slice دزدیدهشده در میانه یک درخواست قرار میگیرد و تأخیر آن دوباره توسط تمام مواردی که منتظر آن درخواست هستند، پرداخت میشود. برای بهدست آوردن عدد واقعی خودتان به جای استفاده از یک فرمول، در طول یک ساعت خلوت و دوباره در یک ساعت شلوغ، بنچمارک VPS را انجام دهید و st را برای هر دو بازه ثبت کنید.
آیا این steal است یا مسئلهای دیگر؟
تشخیص steal از سایر علائم ممکن است دشوار باشد. شمارندهها را با هم و در یک خط vmstat بخوانید.
stبالا است در حالی کهrوusپایین میمانند: میزبان (host) هسته پردازشی را در اختیار شما نمیگذارد. این همان steal است.rبسیار بالاتر از تعداد vCPU شما است، باusبالا وstنزدیک به صفر: شما حجم کاری بیش از توان پردازندههای خود اجرا میکنید.rرا با خروجیnprocمقایسه کنید. این oversubscription توسط خود شماست، نه یک همسایه.waبالا است در حالی کهstنزدیک به صفر است: وظایف (tasks) در بخش ذخیرهسازی مسدود شدهاند که مشکلی متفاوت با راهحلی متفاوت است.- میانگین بار (load average) بالا است در حالی که
stوusهر دو پایین هستند: شاخص بار، وظایف غیرقابلوقفه (uninterruptible) را نیز میشمارد، بنابراین این وضعیت معمولاً به یک دستگاه گیرکرده یا یک mount شبکه معلق اشاره دارد تا به CPU.
طرحهای burstable شایسته توجه ویژهای هستند. این طرحها به شما یک موجودی اعتبار میدهند که هنگام بیکاری افزایش و هنگام فعالیت کاهش مییابد؛ وقتی اعتبار تمام شود، ارائهدهنده شما را در نرخ پایه محدود میکند. در برخی پلتفرمها، این محدودیت (throttle) به عنوان steal گزارش میشود. در برخی دیگر، این موضوع از داخل سیستم قابل مشاهده نیست و شما صرفاً چرخههای کمتری در ثانیه دریافت میکنید. پیش از آنکه نتیجه بگیرید همسایهای مقصر است، توضیحات طرح خود را مطالعه کنید.
چرا یک کانتینر زمان steal را گزارش نمیکند
زمان Steal ویژگی یک ماشین مجازی است، نه یک کانتینر که درون آن اجرا میشود. یک کانتینر Docker روی VPS شما، /proc میزبان را به اشتراک میگذارد، بنابراین مقدار st که از داخل آن خوانده میشود، همان steal مربوط به VPS است که مورد نیاز شماست. مجازیسازی مبتنی بر کانتینر که بهعنوان VPS فروخته میشود، رفتار متفاوتی دارد. با وجود lxcfs، مقدار /proc/stat در داخل کانتینر از روی حسابرسی cgroup سنتز میشود و مقدار steal بهطور ساختاری صفر است. یک پشتهٔ مانیتورینگ که فقط از داخل کانتینر داده جمعآوری میکند، ممکن است یک نمودار صاف و صفر را نشان دهد، در حالی که ماشین فیزیکی زیرین در حال کمبود منابع است.
در داخل یک کانتینر، شمارندهای که معنای مشابهی دارد، CPU quota throttling است. در cgroup v2:
cat /sys/fs/cgroup/cpu.statمقدار nr_throttled تعداد دورههای اعمال محدودیتی را میشمارد که در آن گروه به سقف سهمیه CPU خود رسیده است و throttled_usec مجموع زمانی است که پردازش در حالت فریز (frozen) سپری کرده است. افزایش nr_throttled به این معنی است که پردازش شما آمادهٔ اجرا بوده اما اجرا نشده است؛ این همان تجربهای است که در steal وجود دارد، اما دلیل آن محدودیتی است که خودتان تعیین کردهاید. پیش از مقصر دانستن میزبان، محدودیتهای خود را بررسی کنید، بهویژه اگر سرویسهای خود را در Docker روی یک VPS با محدودیتهای CPU در فایل compose اجرا میکنید. مجازیسازی لایهای، یک مکان دیگر برای هدر رفتن زمان اضافه میکند، زیرا یک ماشین مجازی درون VPS شما، علاوه بر تأخیر زمانبندی خودش، هزینهٔ steal مربوط به VPS شما را نیز میپردازد. اگر مجازیسازی تو در تو روی یک VPS اجرا میکنید، این نکته را در نظر داشته باشید.
در صورت تداوم steal چه باید کرد
هیچ تنظیمی در داخل guest نمیتواند مشکل steal را برطرف کند، زیرا زمانبندی (scheduler) که این تصمیم را میگیرد، خارج از guest اجرا میشود. چهار اقدام عملی وجود دارد.
ابتدا شواهد را جمعآوری کنید. زمانها را به UTC ثبت کنید، مدتزمان هر رویداد، میزان تکرار آن و اینکه آیا mpstat نشان میدهد که فقط یک vCPU تحت تأثیر قرار گرفته یا همه آنها، مشخص کنید. یک هفته نمونهبرداری ثبتشده، ارزشمندتر از یک اسکرینشات است.
با استفاده از آن دادهها یک تیکت باز کنید. دو سؤال مستقیم بپرسید: آیا این node در این بازههای زمانی بیش از حد اشتراکگذاری (oversubscribed) شده است و آیا امکان انتقال instance من وجود دارد؟ خروجی vmstat و زمانهای دقیق را در تیکت قرار دهید. ارائهدهندگان خدمات بر اساس یک بازه زمانی قابلتکرار اقدام میکنند و تیکتی که فقط بگوید سرور کند است، با درخواستی برای ارائه مستندات پاسخ داده میشود. اینکه چه مقدار از این کار را میتوانید به ارائهدهنده بسپارید، یکی از تفاوتهای عملی بین یک VPS مدیریتشده و مدیریتنشده است.
درخواست مهاجرت (migration) کنید. انتقال یک guest به یک node با بار کمتر، کاری روتین برای ارائهدهنده است و معمولاً تنها به یک reboot کوتاه نیاز دارد. این راهکاری است که هزینهای ندارد و موارد رایجی را که در آن یک node بهطور اتفاقی چندین همسایه پرمصرف را همزمان میزبانی میکند، حل میکند.
با پرداخت هزینه، contention را حذف کنید. یک طرح dedicated vCPU، هستههای فیزیکی را برای instance شما رزرو میکند، بنابراین شمارنده روی صفر میماند. این کار هزینه ماهانه بیشتری دارد و پاسخ صادقانهای برای workloadهایی است که نمیتوانند نوسان را تحمل کنند. اگر این کار کافی نیست یا میخواهید پهنای باند حافظه را نیز بهطور اختصاصی در اختیار داشته باشید، گام بعدی استفاده از یک سرور اختصاصی بهجای VPS است.
در مدتی که منتظر هر یک از این اقدامات هستید، آسیب ناشی از steal را کاهش دهید. تعداد worker threadهای کمتری نسبت به vCPUهای خود اجرا کنید، زیرا threadهایی که نمیتوانند هسته دریافت کنند، فقط باعث افزایش context switch میشوند. کارهای دستهای (batch work) را به ساعاتی منتقل کنید که node خلوت است؛ این موضوع را لاگهای خودتان به شما نشان میدهند. سپس دوباره با همان دستور و در همان ساعات اندازهگیری کنید تا بتوانید بهجای حدس زدن، بگویید که آیا تغییرات مؤثر بوده است یا خیر.
FAQ
مقدار عادی CPU steal time در یک VPS چقدر است؟
در پلنهای اشتراکی، جهشهای کوتاه و مقدار پایدار زیر حدود 5 درصد عادی است، زیرا در CPU اشتراکی، میزبان هستههای فیزیکی را بین مهمانها تقسیم میکند. مقادیر دورقمی پایدار در طول چندین ساعت عادی نیست و ارزش ارسال تیکت پشتیبانی را دارد. در پلنهای با vCPU اختصاصی، مقدار مورد انتظار 0.0 است، بنابراین هر مقدار دیگری در آنجا یک نقص فنی است که باید گزارش شود. این عدد را نسبت به بار کاری خود بسنجید: یک پردازش دستهای (batch job) شبانه میتواند steal را تحمل کند، اما یک API حساس به تأخیر (latency-sensitive) خیر.
آیا پلن بزرگتر مشکل steal time بالا را حل میکند؟
بهتنهایی خیر. vCPUهای بیشتر روی همان نود اشتراکی به معنای رقابت vCPUهای بیشتر برای همان هستههای فیزیکی تحت فشار است و درصد آن میتواند دقیقاً همانجایی که بود باقی بماند. آنچه steal را حذف میکند، تخصیص CPU اختصاصی یا انتقال به نودی با بار کمتر است. سهم بزرگتر از یک ماشین شلوغ، همچنان سهمی از یک ماشین شلوغ است.
چرا VPS من با وجود کندی محسوس، steal time صفر نشان میدهد؟
دو دلیل رایج برای این موضوع وجود دارد. هایپروایزر ممکن است اصلاً این شمارنده را گزارش نکند که در پلتفرمهای VMware و Hyper-V معمول است، بنابراین این فیلد بدون توجه به عملکرد میزبان، روی صفر باقی میماند. دستور systemd-detect-virt را اجرا کنید تا ببینید روی چه پلتفرمی هستید. در غیر این صورت، گلوگاه جای دیگری است: wa را برای بررسی انتظار دیسک (storage waits) چک کنید، r را با nproc برای بررسی بار کاری خود مقایسه کنید و /sys/fs/cgroup/cpu.stat را داخل کانتینرها برای بررسی محدودیت سهمیه (quota throttling) بخوانید.
آیا میتوانم steal time را از داخل سرور خود کاهش دهم؟
شما نمیتوانید زمانبندی (scheduling) میزبان را از داخل مهمان تغییر دهید. فقط میتوانید میزان آسیب آن را کاهش دهید. تعداد تردهای کاری (worker threads) کمتری نسبت به vCPUهای خود اجرا کنید تا کارهای کمتری در صف اجرا منتظر هستهای بمانند که در دسترس نیست. پردازشهای دستهای را به ساعاتی منتقل کنید که نود خلوتتر است. نتایج را کش کنید تا درخواستهای کمتری اصلاً به CPU نیاز داشته باشند. تغییراتی که واقعاً steal را حذف میکنند، یعنی مهاجرت به نودی دیگر یا استفاده از هستههای اختصاصی، در سمت ارائهدهنده خدمات قرار دارند.