یکی از رایجترین دلایل لگ در سرورهای MTA، ضعیف بودن VPS نیست؛ بلکه Resourceهایی هستند که Lua Code آنها بهینه نوشته نشده است. یک Loop بزرگ، Timer بسیار پرتکرار، Event نامناسب یا ارسال بیش از حد اطلاعات بین Server و Client میتواند مصرف CPU را بالا ببرد و باعث افت عملکرد کل گیممود شود.
در یک سرور شلوغ، حتی یک Resource کوچک که برای هر Player چندین بار در ثانیه عملیات سنگین انجام میدهد میتواند به Bottleneck تبدیل شود. به همین دلیل قبل از ارتقای VPS باید مشخص کنیم کدام Resource و کدام بخش از Script بیشترین فشار را ایجاد میکند.
در این آموزش روش پیدا کردن Resourceهای سنگین، بررسی مصرف CPU، بهینهسازی Timerها و Eventها، مدیریت Elementها، کاهش Loopهای غیرضروری و بهینهسازی ارتباط Client و Server را بررسی میکنیم.
نشانههای Resource بهینهنشده در MTA
- Logic Thread مصرف CPU بالایی دارد.
- با افزایش Playerها لگ شدیدتر میشود.
- بعد از Start یک Resource مصرف CPU ناگهان بالا میرود.
- Resource تعداد زیادی Timer فعال ایجاد میکند.
- Eventهای Server یا Client بسیار پرتکرار هستند.
- تعداد Elementها دائماً افزایش پیدا میکند.
- RAM بهمرور افزایش پیدا میکند.
- Network Traffic غیرعادی بالا میرود.
- Restart یک Resource موقتاً مشکل را برطرف میکند.
- سرور با CPU کلی پایین همچنان Lag دارد.
اول Resource سنگین را پیدا کنید
قبل از تغییر Code باید مشخص شود کدام Resource واقعاً مشکل ایجاد میکند. برای بررسی کلی سرور میتوانید از PerformanceBrowser استفاده کنید.
start performancebrowser
مصرف Logic Thread و Resourceهای فعال را در شرایط عادی ثبت کنید و سپس هنگام بروز Lag دوباره مقایسه کنید.
برای بررسی کامل CPU، RAM، Network و Threadهای MTA مقاله آموزش مانیتورینگ سرور MTA در لینوکس را مطالعه کنید.
تست Resource مشکوک
در محیط Test یا زمان Maintenance میتوانید یک Resource مشکوک را موقتاً متوقف کنید:
stop resource-name
سپس مصرف CPU و وضعیت Logic Thread را بررسی کنید. اگر پس از Stop کردن Resource مصرف بهطور محسوس کاهش پیدا کرد، باید Code همان Resource بررسی شود.
Resource اصلی گیممود را وسط فعالیت سرور Production فقط برای تست متوقف نکنید. عیبیابی را در محیط Test یا Maintenance انجام دهید.
استفاده از getPerformanceStats
MTA تابع getPerformanceStats را برای دریافت اطلاعات Performance ارائه میکند و میتوان از آن برای ساخت ابزارهای Monitoring و بررسی رفتار Resourceها استفاده کرد.
local columns, rows = getPerformanceStats("")
for _, row in ipairs(rows) do
outputDebugString(table.concat(row, " | "))
end
Loopهای بزرگ و پرتکرار را بررسی کنید
اجرای Loop روی Player، Vehicle یا Elementها همیشه مشکل نیست. مشکل زمانی ایجاد میشود که Loop بزرگ چندین بار در ثانیه اجرا شود.
for _, player in ipairs(getElementsByType("player")) do
-- processing
end
در سرورهایی با تعداد Player زیاد، اجرای پرتکرار چنین Loopهایی میتواند مصرف CPU را افزایش دهد.
نتیجه getElementsByType را بیدلیل چند بار نسازید
local players = getElementsByType("player")
for _, player in ipairs(players) do
-- task A
end
for _, player in ipairs(players) do
-- task B
end
Timerهای بسیار کوتاه را بررسی کنید
setTimer(function()
-- heavy processing
end, 50, 0)
این Function تقریباً 20 بار در ثانیه برنامهریزی میشود. اگر داخل آن Loop، Database Query یا پردازش سنگین باشد، CPU میتواند بهسرعت بالا برود.
از Timer صفر میلیثانیه برای Loop دائمی استفاده نکنید
setTimer(function()
-- code
end, 0, 0)
چنین ساختاری میتواند Performance سرور را تحت فشار قرار دهد. Frequency هر Task باید براساس نیاز واقعی گیممود انتخاب شود.
Timerهای Resource را مدیریت کنید
local updateTimer
addEventHandler("onResourceStart", resourceRoot,
function()
updateTimer = setTimer(
function()
-- periodic task
end,
5000,
0
)
end
)
addEventHandler("onResourceStop", resourceRoot,
function()
if isTimer(updateTimer) then
killTimer(updateTimer)
end
end
)
Event Handler را به Element مناسب متصل کنید
اتصال همه Event Handlerها به root همیشه بهترین انتخاب نیست. اگر Event فقط مربوط به یک Element مشخص است، Handler را به همان Element متصل کنید.
local shopMarker = createMarker(
1000,
1000,
10,
"cylinder",
2
)
addEventHandler(
"onMarkerHit",
shopMarker,
function(hitElement)
-- shop logic
end
)
Event سفارشی را بدون نیاز Remote نکنید
addEvent("internalServerEvent", false)
اگر Client نیازی به Trigger کردن Event ندارد، Remote Trigger را فعال نکنید.
اطلاعات ارسالشده از Client را Trust نکنید
Server باید دادههای حساس را Validate کند. Money، Permission، Item و عملیات مدیریتی نباید فقط براساس اطلاعاتی که Client ارسال کرده پذیرفته شوند.
triggerClientEvent را فقط برای Player موردنیاز ارسال کنید
اگر اطلاعات فقط برای یک Player لازم است، آن را برای همه Playerها Broadcast نکنید.
triggerClientEvent(
player,
"updatePlayerUI",
resourceRoot,
data
)
محدودکردن گیرنده Event میتواند Network Traffic و پردازش Clientهای غیرمرتبط را کاهش دهد.
دادههای حجیم را بیدلیل ارسال نکنید
- فقط اطلاعات موردنیاز را ارسال کنید.
- داده تکراری را دوباره نفرستید.
- گیرنده Event را محدود کنید.
- Frequency ارسال Updateها را کنترل کنید.
- برای انتقال حجیم triggerLatentClientEvent را بررسی کنید.
Elementهای بدون استفاده را Destroy کنید
if isElement(tempVehicle) then
destroyElement(tempVehicle)
end
اگر Resource دائماً Vehicle، Object، Marker یا Elementهای دیگر ایجاد کند اما Cleanup انجام نشود، مصرف منابع بهمرور افزایش پیدا میکند.
Tableهای Lua را بدون محدودیت بزرگ نکنید
- Cacheهای بدون Expiration
- Logهای ذخیرهشده در Memory
- اطلاعات Player بعد از Quit
- Vehicleهای حذفشده
- Sessionهای پایانیافته
- Referenceهای قدیمی
داده Player را هنگام Quit پاک کنید
local playerCache = {}
addEventHandler("onPlayerQuit", root,
function()
playerCache[source] = nil
end
)
Database Query داخل Loop را کاهش دهید
اجرای Query برای تکتک Playerها در یک Loop میتواند DB Thread را نیز تحت فشار قرار دهد. در صورت امکان Queryها را Batch کنید یا طراحی Database را تغییر دهید.
برای این بخش مقاله آموزش بهینهسازی MySQL برای سرور MTA را بررسی کنید.
Server-side و Client-side را درست تقسیم کنید
پردازشهای بصری مانند UI و بعضی Effectها میتوانند Client-side باشند، اما Logic حساس، Permission و دادههای مهم باید در Server باقی بمانند.
onClientRender را سبک نگه دارید
onClientRender در هر Frame اجرا میشود. Loop بزرگ، جستوجوی Element، پردازش String سنگین یا محاسبات ثابت داخل آن میتواند FPS Client را کاهش دهد.
- مقادیر ثابت را خارج Render محاسبه کنید.
- فقط Elementهای موردنیاز را بررسی کنید.
- UI پنهان را Render نکنید.
- Calculationهای غیرضروری را Cache کنید.
- از Loopهای بزرگ در هر Frame خودداری کنید.
Debug Code را در Production کنترل کنید
outputDebugString گسترده داخل Loop یا Event پرتکرار میتواند Log زیادی ایجاد کند. Debugهای سنگین را بعد از پایان عیبیابی غیرفعال کنید.
قبل و بعد از Optimization اندازهگیری کنید
- تعداد Player را ثبت کنید.
- Logic Thread را ثبت کنید.
- CPU Process MTA را ثبت کنید.
- Resource مشکوک را مشخص کنید.
- فقط یک تغییر انجام دهید.
- در شرایط مشابه دوباره تست کنید.
- نتیجه قبل و بعد را مقایسه کنید.
جدول Benchmark Resource
| شاخص | قبل | بعد |
|---|---|---|
| Player Count | ثبت شود | ثبت شود |
| Logic Thread | ثبت شود | ثبت شود |
| CPU MTA | ثبت شود | ثبت شود |
| RAM MTA | ثبت شود | ثبت شود |
| Network | ثبت شود | ثبت شود |
| تعداد Timerها | ثبت شود | ثبت شود |
اشتباهات رایج Resourceهای MTA
- Timerهای بسیار کوتاه
- Loop روی تمام Playerها چندین بار در ثانیه
- Query دیتابیس داخل Loop
- Broadcast غیرضروری Event
- ارسال Tableهای حجیم
- اتصال همه Handlerها به root
- ساخت Element بدون Cleanup
- Cache بدون Expiration
- نگه داشتن اطلاعات Player بعد از Quit
- محاسبات سنگین داخل onClientRender
- Debug Log بیش از حد
- Optimization بدون Benchmark
چکلیست بهینهسازی Resourceهای MTA
- Resource پرمصرف شناسایی شده است.
- Logic Thread بررسی شده است.
- Timerهای کوتاه بررسی شدهاند.
- Loopهای بزرگ بررسی شدهاند.
- Event Handlerهای غیرضروری روی root کاهش یافتهاند.
- Event فقط برای گیرندگان موردنیاز ارسال میشود.
- داده حجیم بیدلیل ارسال نمیشود.
- Queryهای دیتابیس داخل Loop بررسی شدهاند.
- Elementهای موقت Destroy میشوند.
- Cacheهای قدیمی پاک میشوند.
- داده Player بعد از Quit پاک میشود.
- onClientRender سبک نگه داشته شده است.
- Debugهای سنگین غیرفعال شدهاند.
- Benchmark قبل و بعد انجام شده است.
جمعبندی
بهینهسازی Resourceهای MTA قبل از هر چیز به اندازهگیری نیاز دارد. افزایش قدرت VPS بدون شناسایی Resource مشکلدار ممکن است فقط هزینه سرور را افزایش دهد و علت اصلی Lag همچنان باقی بماند.
Timerهای پرتکرار، Loopهای بزرگ، Event Handlerهای گسترده، Broadcast غیرضروری، Queryهای دیتابیس، Elementهای بدون Cleanup و Code سنگین Client-side از مهمترین بخشهایی هستند که باید بررسی شوند.
برای تشخیص دقیق Resource و Thread پرمصرف مقاله آموزش مانیتورینگ سرور MTA در لینوکس را ببینید.
اگر DB Thread مشکل اصلی است، مقاله آموزش بهینهسازی MySQL برای سرور MTA را مطالعه کنید.
برای بررسی تخصصی Resourceهای Lua، گیممود و Bottleneckهای سرور نیز میتوانید از خدمات پشتیبانی فنی گیمسرور و راهاندازی و کانفیگ سرور MTA کیمیا گیم استفاده کنید.
پرسشهای متداول
چطور Resource پرمصرف MTA را پیدا کنیم؟
از PerformanceBrowser و Performance Stats استفاده کنید و وضعیت Resourceها را در زمان عادی و زمان Lag مقایسه کنید.
آیا Timer زیاد باعث لگ MTA میشود؟
تعداد Timer بهتنهایی کافی نیست. Interval، حجم پردازش Function و تعداد دفعات اجرای آن اهمیت بیشتری دارند.
چطور مصرف Network Resource را کاهش دهیم؟
Event را فقط برای Playerهای موردنیاز ارسال کنید، داده غیرضروری را حذف کنید و Frequency Updateها را کاهش دهید.
آیا همه پردازشها را به Client منتقل کنیم؟
خیر. پردازشهای بصری میتوانند Client-side باشند، اما Logic حساس و اطلاعات امنیتی باید Server-side باقی بمانند.
