اگر روی یک سرور دو یا چندپردازندهای دیتابیس یا برنامهای با مصرف بالای حافظه اجرا کرده باشید، ممکن است با یک سؤال عجیب روبهرو شده باشید: چرا با وجود افزایش تعداد هستهها و مقدار رم، عملکرد سرور آنقدر که انتظار داشتیم بهتر نشده است؟ پاسخ این سؤال گاهی به معماری NUMA برمیگردد. در سرورهای چندسوکته، افزایش منابع سختافزاری لزوماً به معنی افزایش خطی کارایی نیست؛ چون نحوهی ارتباط پردازندهها با حافظه هم روی سرعت پردازش اثر میگذارد. برای اینکه ببینیم numa چیست و چرا اهمیت دارد، ابتدا باید ساختار ارتباط CPU و حافظه را کمی دقیقتر بررسی کنیم.
numa چیست؟
NUMA مخفف Non-Uniform Memory Access و به معنی «دسترسی غیریکنواخت به حافظه» است. در این معماری، هر پردازنده یا سوکت پردازنده به بخشی از حافظه که در نزدیکی خودش قرار دارد دسترسی سریعتری دارد. این بخش را حافظهی محلی یا Local Memory مینامند. همان پردازنده میتواند به حافظهی متصل به پردازندهی دیگری هم دسترسی داشته باشد، اما این کار کمی زمان بیشتری میبرد؛ چون درخواست باید از مسیر ارتباطی میان دو سوکت عبور کند.
اصل ماجرا همین تفاوت است: زمان دسترسی همهی هستهها به تمام بخشهای حافظه یکسان نیست. وقتی یک هسته از حافظهی محلی نود خودش استفاده میکند، داده سریعتر در اختیارش قرار میگیرد. اما اگر داده در حافظهی نود دیگری باشد، دسترسی با تأخیر بیشتری انجام میشود.
بنابراین، در معماری NUMA با یک فضای حافظهی کاملاً یکدست روبهرو نیستیم، بلکه حافظه میان چند نود تقسیم شده و هر بخش به یک پردازنده نزدیکتر است.
چرا NUMA به وجود آمد؟
پیش از numa، بسیاری از سیستمهای چندپردازندهای از معماری UMA یا Uniform Memory Access استفاده میکردند. در این مدل، پردازندهها از یک مسیر مشترک به حافظه دسترسی داشتند.
وقتی تعداد پردازندهها و هستهها محدود بود، این ساختار مشکل جدیای ایجاد نمیکرد، اما با افزایش تعداد هستهها، پردازندههای بیشتری باید از همان مسیر مشترک برای دسترسی به حافظه استفاده میکردند. در نتیجه، این مسیر بهتدریج به یک گلوگاه تبدیل میشد.
NUMA برای حل همین مشکل شکل گرفت. بهجای اینکه تمام پردازندهها به یک حافظهی مرکزی متکی باشند، حافظه میان پردازندهها تقسیم شد و هر بخش در نزدیکی یک سوکت قرار گرفت. به این ترتیب، بخش زیادی از درخواستهای حافظه بهصورت محلی انجام میشود و لازم نیست همهی پردازندهها برای دسترسی به رم از یک مسیر مشترک عبور کنند. نتیجهی این تغییر، مقیاسپذیری بهتر در سرورهای چندپردازندهای است.
numa چطور کار میکند؟
برای درک نحوه کارکرد NUMA، باید با دو مفهوم اصلی آشنا شویم: نود numa و تفاوت دسترسی محلی با دسترسی از راه دور.
نودهای NUMA و حافظهی محلی
در معماری NUMA، هر پردازنده به همراه حافظهای که مستقیماً به آن متصل است، یک NUMA Node یا نود NUMA را تشکیل میدهد. برای مثال، یک سرور دوسوکته معمولاً دو نود numa دارد و در یک سرور چهارسوکته نیز ممکن است چهار نود وجود داشته باشد.
سیستمعامل این توپولوژی را میشناسد و هنگام اجرای پردازشها تلاش میکند حافظهی موردنیاز هر پردازش را تا حد ممکن از همان نودی تأمین کند که پردازش روی هستههای آن اجرا میشود. این کار باعث میشود دسترسی به حافظه سریعتر انجام شود و رفتوآمد داده بین نودها کاهش پیدا کند.
دسترسی محلی در برابر دسترسی از راه دور
وقتی یک هسته به حافظهی متعلق به نود خودش دسترسی پیدا میکند، با Local Access یا دسترسی محلی روبهرو هستیم. این سریعترین حالت دسترسی به حافظه در numa است. اما اگر پردازش روی هستهای از یک نود اجرا شود و دادهی موردنیاز آن در حافظهی نود دیگری قرار گرفته باشد، درخواست باید از مسیر ارتباطی میان سوکتها عبور کند. در پردازندههای مختلف، فناوریهایی مانند Intel UPI یا AMD Infinity Fabric این ارتباط را برقرار میکنند.
به این نوع دسترسی Remote Access گفته میشود. دسترسی از راه دور نسبت به دسترسی محلی تأخیر بیشتری دارد و همین تفاوت، دلیل استفاده از عبارت «دسترسی غیریکنواخت» در نام NUMA است.
تفاوت NUMA و UMA
تفاوت اصلی NUMA و UMA به نحوهی ارتباط پردازندهها با حافظه برمیگردد که در جدول زیر قابل مشاهده است:
| ویژگی | UMA | NUMA |
| نحوه اتصال به حافظه | پردازندهها از مسیر مشترک به حافظه دسترسی دارند | هر پردازنده به حافظه محلی خودش متصل است |
| زمان دسترسی به حافظه | برای پردازندهها تقریباً یکسان است | بسته به محل حافظه متفاوت است |
| مقیاسپذیری | با افزایش تعداد پردازندهها محدودتر میشود | برای سیستمهای چندسوکته مناسبتر است |
| احتمال ایجاد گلوگاه | مسیر مشترک میتواند به گلوگاه تبدیل شود | بار دسترسی میان نودها توزیع میشود |
| کاربرد رایج | سیستمهای سادهتر یا با تعداد پردازنده کمتر | سرورهای چندسوکته و پرقدرت |
این تفاوت شاید در نگاه اول جزئی به نظر برسد، اما در بارهای کاری سنگین میتواند مستقیماً روی عملکرد سیستم اثر بگذارد.
تأثیر معماری NUMA بر عملکرد سرورها
numa زمانی بهترین نتیجه را میدهد که سیستمعامل و نرمافزارها نسبت به این معماری آگاه باشند یا اصطلاحاً NUMA-aware طراحی شده باشند. در چنین شرایطی، پردازش تا جای ممکن روی هستههایی اجرا میشود که حافظهی موردنیاز آن در همان نود قرار دارد. در نتیجه، تعداد دسترسیهای راه دور کمتر میشود، ترافیک بین سوکتها کاهش پیدا میکند و سرور میتواند از منابع سختافزاری خود مؤثرتر استفاده کند.
این موضوع در بارهای کاری سنگین، مانند دیتابیسهای بزرگ یا محیطهای مجازیسازی، اهمیت بیشتری دارد. بسته به نوع پردازش و ساختار سیستم، اختلاف عملکرد میتواند از چند درصد تا چند ده درصد برسد. مشکل زمانی ایجاد میشود که زمانبند سیستمعامل یا هایپروایزر، توپولوژی NUMA را بهدرستی در نظر نگیرد. فرض کنید پردازشی روی هستههای نود اول اجرا شود، اما بخش زیادی از حافظهی موردنیازش در نود دوم قرار گرفته باشد. در این وضعیت، تعداد زیادی از درخواستها باید از مسیر بین دو نود عبور کنند و همین رفتوآمد اضافی میتواند سرعت پردازش را کاهش دهد. به چنین شرایطی معمولاً NUMA Imbalance یا عدم توازن numa گفته میشود. نرمافزارهای قدیمیتر که بدون توجه به ساختار NUMA طراحی شدهاند، بیشتر در معرض چنین مشکلی قرار دارند.
یک نکتهی مهم درباره ماشینهای مجازی و کانتینرها هم وجود دارد. اگر مقدار حافظهای که به یک ماشین مجازی اختصاص دادهاید از ظرفیت حافظهی یک نود بیشتر باشد، بخشی از رم ناچار از نود دیگری تأمین میشود. در این حالت، افزایش منابع الزاماً به همان نسبت باعث افزایش عملکرد نمیشود.
numa و مجازیسازی سرور
تکنولوژی NUMA در محیطهای مجازیسازی اهمیت بیشتری پیدا میکند؛ چون هایپروایزر باید علاوهبر مدیریت منابع فیزیکی، مشخص کند vCPUها و حافظهی هر ماشین مجازی از کدام نود NUMA تأمین شوند.
هایپروایزرهایی مانند KVM و VMware ESXi روی سرورهای چندسوکته باید این تخصیص را با توجه به توپولوژی سختافزار انجام دهند. اگر vCPUهای یک ماشین مجازی روی یک نود قرار بگیرند، اما حافظهی آن عمدتاً از نود دیگری تأمین شود، بخشی از دسترسیهای حافظه از راه دور انجام خواهد شد و کارایی ماشین مجازی افت میکند.
برای مدیریت بهتر این وضعیت، هایپروایزرهای مدرن از قابلیتی به نام vNUMA استفاده میکنند. vNUMA ساختار numa سرور فیزیکی را تا حدی در اختیار سیستمعامل مهمان قرار میدهد. در نتیجه، Guest OS میتواند تشخیص دهد چند نود در اختیار دارد و پردازشها را متناسب با این ساختار مدیریت کند.
اگر روی یک سرور مجازی برنامهای با مصرف بالای حافظه اجرا میکنید، نحوهی تخصیص منابع NUMA در زیرساخت میتواند روی عملکرد آن اثر بگذارد. همین مسئله گاهی توضیح میدهد چرا دو سرور با مشخصات ظاهراً مشابه، در اجرای یک بار کاری یکسان رفتار متفاوتی دارند.
برای آشنایی بیشتر با روشهای تقسیم منابع سختافزاری، میتوانید مطلب مجازیسازی سرور در بلاگ مبین هاست را نیز بخوانید.
بررسی وضعیت NUMA در لینوکس
برای بررسی وضعیت numa در لینوکس چند ابزار ساده در اختیار دارید. با استفاده از آنها میتوانید تعداد نودها، مقدار حافظه هر نود و نحوهی دسترسی پردازشها به حافظه را بررسی کنید. این دستورات روی بسیاری از سیستمهای مبتنی بر لینوکس، از جمله سرور مجازی لینوکس و سرورهای اختصاصی، قابل استفادهاند. در ادامه به 4 مورد از این دستورها اشاره میکنیم:
۱) بررسی توپولوژی پردازنده
دستور lscpu اطلاعات کلی پردازنده و ساختار تکنولوژی NUMA را نمایش میدهد. در خروجی این دستور میتوانید ببینید سیستم چند نود numa دارد و چه CPUهایی در هر نود قرار گرفتهاند. معمولاً سطرهایی مانند NUMA node0 CPU(s) و NUMA node1 CPU(s) این اطلاعات را نشان میدهند.
۲) مشاهدهی جزئیات حافظهی هر نود
با دستور زیر میتوانید اطلاعات مربوط به نودهای NUMA را ببینید:
numactl --hardware
این دستور مقدار حافظهی هر نود و همچنین Distance میان نودها را نمایش میدهد. مقدار Distance نشان میدهد هزینهی دسترسی از یک نود به نود دیگر چقدر است؛ هرچه این عدد بیشتر باشد، دسترسی از راه دور نسبت به حافظهی محلی هزینهی بیشتری دارد.
۳) اجرای پردازش روی یک نود مشخص
برای آزمایش عملکرد یا کنترل محل اجرای یک برنامه میتوان از numactl استفاده کرد. برای مثال:
numactl --cpunodebind=0 --membind=0 ./app
این دستور برنامه را به هستهها و حافظهی نود صفر محدود میکند. چنین روشی برای تست عملکرد یا اجرای بعضی دیتابیسها و برنامههای حساس به تأخیر کاربرد دارد.
۴) بررسی رفتار حافظه در زمان اجرا
ابزار numastat اطلاعات مفیدی دربارهی نحوهی دسترسی پردازشها به حافظه نشان میدهد. با کمک این ابزار میتوانید بررسی کنید چه مقدار از دسترسیها به حافظهی محلی انجام شده و چه مقدار مربوط به نودهای دیگر بوده است. اگر دسترسیهای Remote به شکل غیرعادی زیاد باشند و همزمان افت عملکرد مشاهده شود، بهتر است تنظیمات numa را دقیقتر بررسی کنید.
چه زمانی باید نگران تنظیمات NUMA باشیم؟
برای بسیاری از وبسایتهای معمولی و برنامههای سبک، numa مسئلهای نیست که لازم باشد دائماً درگیر آن باشید. سیستمعاملهای مدرن در بیشتر مواقع مدیریت قابل قبولی روی توزیع پردازش و حافظه دارند. اهمیت NUMA زمانی بیشتر میشود که با بارهای کاری سنگین سروکار داشته باشید؛ برای مثال دیتابیسهای بزرگی مانند PostgreSQL و MySQL، برنامههای چندنخی با مصرف بالای رم، محیطهای مجازیسازی یا پلتفرمهای محاسباتی سنگین.
در چنین شرایطی، محل اجرای پردازش و حافظهای که در اختیار آن قرار میگیرد میتواند مستقیماً روی زمان پاسخگویی اثر بگذارد. نوع زیرساخت نیز در میزان کنترلی که روی این تنظیمات دارید مؤثر است. برای مثال، در یک سرور اختصاصی ایران با چند سوکت پردازنده میتوانید منابع سختافزاری را با آزادی بیشتری مدیریت کنید و در صورت نیاز پردازشها را روی نودهای مشخص قرار دهید.
برای بارهای کاری سبکتر معمولاً نیازی به تنظیمات پیچیده نیست. همان ابزارهای بررسی NUMA میتوانند نشان دهند که سیستم منابع موجود را به شکل مناسبی مدیریت میکند یا خیر.
جمعبندی
numa برای حل یکی از محدودیتهای مهم سرورهای چندپردازندهای به وجود آمد: اینکه همهی پردازندهها مجبور نباشند برای دسترسی به حافظه از یک مسیر مشترک استفاده کنند. در این معماری، حافظه میان نودها تقسیم میشود و هر پردازنده سریعتر به حافظهی نزدیک به خودش دسترسی دارد. در مقابل، دسترسی به حافظهی نودهای دیگر با تأخیر بیشتری انجام میشود.
این تفاوت در استفادههای معمولی شاید چندان محسوس نباشد، اما در دیتابیسهای بزرگ، مجازیسازی و پردازشهای سنگین اهمیت پیدا میکند. در چنین شرایطی، فقط تعداد هستهها و مقدار رم تعیینکننده نیست؛ اینکه پردازش کجا اجرا میشود و حافظهی موردنیازش در کدام نود قرار دارد هم بخشی از معادلهی عملکرد سرور است.
پرسشهای متداول
NUMA مخفف چیست؟
numa مخفف Non-Uniform Memory Access است که در فارسی به «دسترسی غیریکنواخت به حافظه» ترجمه میشود. این نام به تفاوت زمان دسترسی پردازنده به بخشهای مختلف حافظه اشاره دارد. حافظهای که به همان نود متصل است سریعتر در دسترس قرار میگیرد و دسترسی به حافظهی نودهای دیگر معمولاً تأخیر بیشتری دارد.
آیا numa فقط مخصوص سرورهای چندسوکته است؟
اثر NUMA بیشتر در سیستمهایی دیده میشود که چند نود حافظه دارند و دسترسی پردازنده به همهی بخشهای حافظه هزینهی یکسانی ندارد. در سرورهای چندسوکته این تفاوت معمولاً واضحتر است. در بسیاری از سیستمهای سادهتر یا تکسوکته، کاربر بهندرت با تأثیر numa درگیر میشود و مدیریت منابع بدون نیاز به تنظیم دستی انجام میشود.
چطور بفهمم برنامهام از NUMA تأثیر منفی میگیرد؟
یکی از راهها، اجرای numastat هنگام بار کاری واقعی است. اگر حجم دسترسیهای Remote بالا باشد و همزمان افت کارایی یا افزایش تأخیر مشاهده کنید، ممکن است محل اجرای پردازش و حافظهی آن بهخوبی با یکدیگر هماهنگ نباشند. در چنین شرایطی میتوان با ابزارهایی مانند numactl نحوهی تخصیص CPU و حافظه را آزمایش کرد و دید آیا محدودکردن پردازش به یک نود مشخص باعث بهبود عملکرد میشود یا نه.
آیا میشود numa را غیرفعال کرد؟
در BIOS برخی سرورها تنظیماتی مانند Node Interleaving وجود دارد که نحوهی توزیع حافظه میان نودها را تغییر میدهد. بااینحال، تغییر چنین تنظیماتی همیشه به بهبود عملکرد منجر نمیشود. در بسیاری از بارهای کاری، استفادهی درست از حافظهی محلی یکی از مزیتهای اصلی NUMA است و از بین بردن این مزیت ممکن است نتیجهی معکوس داشته باشد. به همین دلیل، پیش از تغییر تنظیمات BIOS بهتر است رفتار واقعی برنامه و نحوهی استفاده آن از حافظه بررسی شود.




