
به اشتراک بگذارید

به اشتراک بگذارید
خط Out of memory: Killed process … (mariadbd) در journalctl -k یعنی کرنل برای آزاد کردن حافظه، پروسه دیتابیس را کشته است. بهینهسازی MySQL روی سرور کمرم از همین خط شروع میشود: سهم دیتابیس را از رمی حساب کنید که بعد از Nginx و PHP-FPM میماند و سقف اتصالها را به اتصالهای واقعی نزدیک کنید.
innodb_buffer_pool_size: کمتر از درصد سرور فقطدیتابیسmax_connections: نزدیک بیشترین اتصال واقعیsort_buffer_size و join_buffer_size): برگشت به پیشفرضquery_cache_size صفر و query_cache_type خاموش💡 سهم دیتابیس را از رم باقیمانده حساب کنید
رم میان Nginx، PHP-FPM و دیتابیس تقسیم میشود.
✅ پیش از کپی هر my.cnf بپرسید برای چند گیگ رم و کدام موتور نوشته شده.
✅ بافر بزرگتر ایندکس گمشده را جبران نمیکند؛ لاگ کوئری کند پیدایش میکند.
فایل تنظیمات فعلی را کنار این صفحه باز کنید. اگر سرور را با راهنمای نصب وردپرس روی سرور مجازی ساختهاید، فایل اصلی MariaDB روی Ubuntu 24.04 /etc/mysql/mariadb.conf.d/50-server.cnf است و روی MySQL، /etc/mysql/mysql.conf.d/mysqld.cnf. هر اشتباه پایین، خطی از همین فایل است.
📌 اشتباههای my.cnf روی سرور کمرم
◀️ عدد بافر پولی که از سرور دیگری آمده
◀️ سقف اتصالهای همزمان
◀️ لاگ کوئریهای کند
◀️ گزارش MySQLTuner و کش کوئری

اشتباه اول در بهینهسازی MySQL روی سرور کمرم، برداشتن درصدی است که برای سرور فقطدیتابیس نوشته شده. InnoDB کل بافر پول را هنگام راهاندازی رزرو میکند و در ساعت شلوغ، سهم PHP-FPM به OOM killer میرسد.
مرجع InnoDB در MySQL 8.4 عدد ۸۰ درصد را برای سرور اختصاصی دیتابیس آورده و صفحه How MySQL Uses Memory بازه ۵۰ تا ۷۵ درصد را رایج میداند؛ InnoDB حدود ۱۰ درصد بیشتر هم برمیدارد. راهنمای حافظه MariaDB زیر ۴ گیگ رم درصد کمتری پیشنهاد میکند.
این اشتباه گاهی از خود اوبونتو شروع میشود: 50-server.cnf خط #innodb_buffer_pool_size = 8G را کامنتشده دارد. # را بردارید و روی سرور ۲ گیگی، چهار برابر کل رم را خواستهاید.
در MySQL 8.4 این گزینه بافر پول را خودکار میچیند: با ۱ تا ۴ گیگ رم، نصف آن. اما مستند همین گزینه وقتی MySQL منابع را با برنامههای دیگر شریک است استفاده از آن را توصیه نمیکند، یعنی همین سرور وردپرس. MariaDB این متغیر را ندارد؛ در آزمایش ما روی 10.11.14 هم پیدا نشد.
در MySQL 8.4 متغیر innodb_log_file_size منسوخ است و innodb_redo_log_capacity با پیشفرض ۱۰۰ مگابایت جایش نشسته. در MariaDB 10.11 برعکس، innodb_log_file_size با ۹۶ مگابایت متغیر اصلی است و سرور آزمایشی با innodb_redo_log_capacity = 1G بالا نیامد:
[ERROR] mariadbd: unknown variable 'innodb_redo_log_capacity=1G'
[ERROR] Aborting

خود max_connections حافظه رزرو نمیکند، اما سقف مصرف را بالا میبرد؛ پس قدم دوم بهینهسازی MySQL و MariaDB روی سرور کوچک، پایین آوردن همین سقف است. پیشفرض هر دو موتور ۱۵۱ است و عدد ۱۰۰۰ یعنی اجازه بافر جدا برای صدها نشست.
برای تالار عروسیای با ۱۰۰ صندلی، ۵۰۰ کارت دعوت چاپ شده است. هر مهمانی که برسد صندلی میخواهد، شام بخورد یا نخورد. هر اتصال هم استک خودش را میگیرد و برای مرتبسازی یا join، بشقاب جدا؛ تالار با چاپ کارت بزرگ نمیشود.
🧮 حافظه هر نشست از کجا میآید
هر اتصال یک استک (thread_stack) و بافر شبکه (net_buffer_length) دارد؛ بقیه را کوئری میسازد.
• مرتبسازی: یک sort_buffer_size.
• join بدون ایندکس: یک join_buffer_size، گاهی چندتا.
• جدول موقت در حافظه: تا سقف tmp_table_size و max_heap_table_size.
حد بدبینانه = بافرهای سراسری + max_connections × (استک + بافرهای نشست).
بعد از چند روز ترافیک عادی، با sudo mariadb (یا sudo mysql) وارد شوید و بیشترین اتصال همزمان از آخرین راهاندازی را بخوانید:
SHOW GLOBAL STATUS LIKE 'Max_used_connections';
سقف را کمی بالاتر از این عدد بگذارید. اگر عدد خیلی بیشتر از pm.max_children در PHP-FPM بود، اتصالها از جای دیگری هم میآیند.
پیشفرضها از مرجع متغیرهای سرور MySQL 8.4 و مستندات MariaDB آمدهاند؛ ستون MariaDB را روی سرور آزمایشی هم با SELECT @@ خواندیم. مخزن Ubuntu 24.04 خودش MySQL 8.0 میدهد و این مقادیر از 8.0.30 به بعد همیناند.
| متغیر | MySQL 8.4 | MariaDB 10.11 |
|---|---|---|
بافر پول (innodb_buffer_pool_size) | ۱۲۸ مگابایت | ۱۲۸ مگابایت |
سقف اتصال (max_connections) | ۱۵۱ | ۱۵۱ |
بافر مرتبسازی (sort_buffer_size) | ۲۵۶ کیلوبایت | ۲ مگابایت (هشت برابر) |
| لاگ ردو | متغیر innodb_redo_log_capacity، ۱۰۰ مگابایت | متغیر innodb_log_file_size، ۹۶ مگابایت |
| ابزار Performance Schema | روشن | خاموش |
| کش کوئری | از نسخه 8.0 حذف شده | خاموش، با بافر ۱ مگابایت |
| لاگ کوئری کند | خاموش، آستانه ۱۰ ثانیه | خاموش، آستانه ۱۰ ثانیه |
لاگ کوئری کند در MySQL 8.4 و MariaDB 10.11 پیشفرض خاموش است و آستانهاش ۱۰ ثانیه. بدون این لاگ، بهینهسازی MySQL و MariaDB فقط بازی با بافرهاست.
در MariaDB 10.11 نامهای slow_query_log و long_query_time مستعار log_slow_query و log_slow_query_time شدهاند. اول در ترمینال پوشه لاگ را به کاربر mysql بدهید:
sudo mkdir -p /var/log/mysql && sudo chown mysql:mysql /var/log/mysql
بعد این سه خط را زیر بخش [mysqld] در 50-server.cnf بگذارید:
log_slow_query = ON
log_slow_query_file = /var/log/mysql/mariadb-slow.log
log_slow_query_time = 1
slow_query_log = ON
slow_query_log_file = /var/lib/mysql/mysql-slow.log
long_query_time = 1
این سه خط زیر [mysqld] در mysqld.cnf میروند.
ابزار mysqldumpslow و نسخه MariaDB آن، mariadb-dumpslow، کوئریهای مشابه را یکی میکنند؛ -s t بر اساس زمان مرتب میکند و -t تعداد را محدود:
sudo mariadb-dumpslow -s t -t 10 /var/log/mysql/mariadb-slow.log
# MySQL:
sudo mysqldumpslow -s t -t 10 /var/lib/mysql/mysql-slow.log
کوئری بالای فهرست را با EXPLAIN ببینید؛ ستون key خالی و rows بزرگ یعنی ایندکس کم است.

اعتبار این گزارش به عمر سرور از آخرین ریاستارت بستگی دارد: README پروژه MySQLTuner دستکم ۲۴ ساعت uptime میخواهد و اجرا روی سرور تازه ریاستارتشده را بیفایده میداند. این خروجی برای بهینهسازی MySQL و MariaDB فقط نظر دوم است؛ هر پیشنهادش را با مستند متغیر بسنجید.
حالت --nondedicated در همان README برای سروری است که دیتابیس در آن تنها نیست. با sudo اجرا کنید، چون root در MariaDB اوبونتو با unix_socket بدون رمز وارد میشود:
wget https://mysqltuner.pl/ -O mysqltuner.pl
sudo perl mysqltuner.pl --nondedicated
یادداشتهای MySQL 8.0 از حذف کش کوئری میگویند و متغیر ناشناخته در my.cnf سرور را با خطا متوقف میکند؛ پس خطوط query_cache در MySQL 8.4 جایی ندارند.
در MariaDB 10.11 کش هست و خاموش. مرجع متغیرهای MariaDB هشدار میدهد اگر سرور با query_cache_size غیرصفر و غیرپیشفرض بالا بیاید، query_cache_type خودکار ON میشود، حتی با OFF در فایل. سرور آزمایشی با 64M همین را نشان داد. هر دو را صفر بگذارید و کش را در لایه وردپرس بسازید (کش صفحه یا object cache).
کپی از سرور بزرگ (نمونه رایج روی سرور ۲ گیگی با MariaDB 10.11)
[mysqld]
innodb_buffer_pool_size = 8G
max_connections = 1000
sort_buffer_size = 8M
join_buffer_size = 8M
query_cache_type = 0
query_cache_size = 64M
innodb_redo_log_capacity = 1G
نقطه شروع برای سرور کمرم، فقط MariaDB 10.11 (پشتوانه هر عدد یک قاعده مستند است)
[mysqld]
# 60-70% of available RAM
innodb_buffer_pool_size = 512M
# example: a bit above Max_used_connections
max_connections = 60
# sort/join buffers: defaults
query_cache_type = 0
query_cache_size = 0
log_slow_query = ON
log_slow_query_file = /var/log/mysql/mariadb-slow.log
log_slow_query_time = 1
راهنمای حافظه MariaDB برای InnoDB حدود ۶۰ تا ۷۰ درصد رم در دسترس را پیشنهاد میکند، یعنی رم کل منهای سیستمعامل و سرویسهای دیگر. اگر روی سرور ۲ گیگی، سیستمعامل و Nginx و PHP-FPM در ساعت شلوغ حدود ۱٫۲ گیگ بگیرند (با free -m)، حدود ۸۰۰ مگابایت میماند و 512M در همین بازه است. روی MySQL این فایل سرور را بالا نمیآورد: پنج خط آخر را با سه خط بخش MySQL عوض کنید.
🔶 وقتی داده پرکاربرد در رم جا نمیشود
وقتی لاگ کند تمیز است و بافر پول باز از داده پرکاربرد کوچکتر، تنظیم بیشتر جواب نمیدهد. منابع سرور مجازی وبداده را بدون تیکت، خودتان در پنل ارتقا میدهید؛ پیش از آن، حساب رم را با راهنمای انتخاب رم سرور مجازی دوباره بزنید.
⚠️ پیش و پس از ریاستارت
نسخه پشتیبان بگیرید و هر نوبت یکی دو متغیر را عوض کنید.
۱. sudo cp /etc/mysql/mariadb.conf.d/50-server.cnf ~/50-server.cnf.bak
۲. sudo systemctl restart mariadb
۳. sudo journalctl -u mariadb -n 30
روی MySQL اوبونتو، mysqld.cnf و واحد mysql جای اینها مینشینند. اگر سرویس بالا نیامد، خط ERROR اسم متغیر مشکلدار را میگوید.
سرورتان ۱ یا ۲ گیگ رم دارد و فعلاً قصد ارتقا ندارید؟ پیش از ارتقا، اینها را روی همان رم امتحان کنید.
بالا آمدن ممکن است. مستند MySQL 8.4 پیکربندی پیشفرض را برای ماشینی با حدود ۵۱۲ مگابایت رم طراحی کرده؛ MariaDB چنین جملهای ندارد، ولی بافر پول پیشفرضش هم ۱۲۸ مگابایت است. بافر را پیشفرض نگه دارید و max_connections را از Max_used_connections ببندید.
در MySQL 8.4 بله، با SET GLOBAL innodb_buffer_pool_size و عددی مضرب innodb_buffer_pool_chunk_size × innodb_buffer_pool_instances. در MariaDB 10.11 کوچک کردن ممکن است، اما بزرگ کردن فقط تا innodb_buffer_pool_size_max، که در 10.11.12 تا 10.11.16 همان اندازه شروع است؛ روی 10.11.14 اوبونتو افزایش با Warning 1292 رد شد. از 10.11.17 این سقف ۸ ترابایت است. وگرنه عدد را در فایل بنویسید و ریاستارت کنید.
آمار هنوز جمع نشده است. README پروژه دستکم ۲۴ ساعت uptime میخواهد.
در MySQL 8.4 روشن است و حافظه گرفتهشده را تا ریاستارت پس نمیدهد؛ خاموشیاش رم آزاد میکند و پایش را کور. در MariaDB 10.11 از اول خاموش است.
برای SELECT تکراری شاید، اما هر نوشتن روی جدول، کش آن جدول را باطل میکند و قفل مشترکش همزمانی را کم میکند. راهنمای حافظه MariaDB خاموش ماندنش را پیشنهاد میکند.
فایل /etc/mysql/my.cnf لینکی است به تنظیمات MySQL یا MariaDB. دستور my_print_defaults –mariadbd گزینههایی را که MariaDB واقعاً میخواند چاپ میکند.
اول منبع اتصالها را پیدا کنید؛ شاید اتصالی باز میماند. MariaDB یک اتصال اضافه برای کاربر SUPER یا CONNECTION ADMIN نگه میدارد تا بتوانید وارد شوید.
جمعبندی؛ بهینهسازی MySQL روی سرور کمرم یعنی تقسیم درست رم درصدهای سرور اختصاصی روی سرور وردپرس جواب نمیدهد. بافر پول را از رم در دسترس حساب کنید. سقف max_connections را از Max_used_connections دربیاورید و بافرهای هر نشست را پیشفرض نگه دارید، چون در تعداد اتصالها ضرب میشوند. لاگ کند را روشن کنید و MySQLTuner را بعد از ۲۴ ساعت uptime بخوانید. خطوط دو موتور را هم قاطی نکنید، چون MySQL با متغیر ناشناخته بالا نمیآید: کش کوئری در MySQL 8.0 حذف شد و در MariaDB با یک query_cache_size کپیشده بیصدا روشن میشود. اگر باز هم داده پرکاربرد در رم جا نشد، نوبت ارتقای منابع است.
🚀 گام بعد: خود وردپرس
وقتی MariaDB پایدار ماند، سراغ خود سایت بروید: Nginx و PHP-FPM را کنار آن بچینید و وردپرس را نصب کنید.
کدام خط را اول عوض کردید و بعدش mysqld یا mariadbd چند روز بدون پیام OOM دوام آورد؟ اگر هنوز OOM میگیرید، رم سرور و خط innodb_buffer_pool_size را هم بگذارید؛ معمولاً مقصر همان است.