MySQL reserves too much RAM

memoryMySQLvps

I have a cheap VPS with 128Mb RAM and 256Mb burst. MySQL starts and reserves about 110Mb, but uses not more than 20Mb of them. My VPS Control Panel shows, that I use 127Mb (I also running nginx and sphinx), I know, that it shows reserved RAM, but when I reach over 128Mb, my VPS reboots automatically every 4 hours. So I want to force MySQL to reserve less RAM. How can i do that? I did some tweaks with my.conf but it helped not so much.

top output:

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
    1 root      15   0  2156  668  572 S  0.0  0.3   0:00.03 init
11311 root      15   0 11212  356  228 S  0.0  0.1   0:00.00 vzctl
11312 root      18   0  3712 1484 1248 S  0.0  0.6   0:00.01 bash
11347 root      18   0  2284  916  732 R  0.0  0.3   0:00.00 top
13978 root      17  -4  2248  552  344 S  0.0  0.2   0:00.00 udevd
14262 root      15   0  1812  564  472 S  0.0  0.2   0:00.03 syslogd
14293 sphinx    15   0 11816 1172  672 S  0.0  0.4   0:00.07 searchd
14305 root      25   0  7192 1036  636 S  0.0  0.4   0:00.00 sshd
14321 root      25   0  2832  836  668 S  0.0  0.3   0:00.00 xinetd
15389 root      18   0  3708 1300 1132 S  0.0  0.5   0:00.00 mysqld_safe
15441 mysql     15   0  113m  16m 4440 S  0.0  6.4   0:00.15 mysqld
15489 root      21   0 13056 1456  340 S  0.0  0.6   0:00.00 nginx
15490 nginx     18   0 13328 2388  992 S  0.0  0.9   0:00.06 nginx
15507 nginx     25   0 19520 5888 4244 S  0.0  2.2   0:00.00 php-cgi
15508 nginx     18   0 19636 4876 2748 S  0.0  1.9   0:00.12 php-cgi
15509 nginx     15   0 19668 4872 2716 S  0.0  1.9   0:00.11 php-cgi
15518 root      18   0  4492 1116  568 S  0.0  0.4   0:00.01 crond

MySQL tuner:

 >>  MySQLTuner 1.0.1 - Major Hayden <major@mhtx.net>
 >>  Bug reports, feature requests, and downloads at http://mysqltuner.com/
 >>  Run with '--help' for additional options and output filtering
Please enter your MySQL administrative login: root
Please enter your MySQL administrative password:

-------- General Statistics --------------------------------------------------
[--] Skipped version check for MySQLTuner script
[OK] Currently running supported MySQL version 5.0.77
[OK] Operating on 32-bit architecture with less than 2GB RAM

-------- Storage Engine Statistics -------------------------------------------
[--] Status: -Archive -BDB -Federated +InnoDB -ISAM -NDBCluster
[--] Data in InnoDB tables: 1M (Tables: 1)
[OK] Total fragmented tables: 0

-------- Performance Metrics -------------------------------------------------
[--] Up for: 38m 43s (37 q [0.016 qps], 20 conn, TX: 4M, RX: 3K)
[--] Reads / Writes: 100% / 0%
[--] Total buffers: 28.1M global + 832.0K per thread (100 max threads)
[OK] Maximum possible memory usage: 109.4M (42% of installed RAM)
[OK] Slow queries: 0% (0/37)
[OK] Highest usage of available connections: 1% (1/100)
[OK] Key buffer size / total MyISAM indexes: 128.0K/64.0K
[OK] Query cache efficiency: 42.1% (8 cached / 19 selects)
[OK] Query cache prunes per day: 0
[!!] Temporary tables created on disk: 27% (3 on disk / 11 total)
[!!] Thread cache is disabled
[OK] Table cache hit rate: 57% (8 open / 14 opened)
[OK] Open file limit used: 1% (12/1K)
[OK] Table locks acquired immediately: 100% (22 immediate / 22 locks)
[!!] Connections aborted: 10%
[OK] InnoDB data size / buffer pool: 1.5M/8.0M

-------- Recommendations -----------------------------------------------------
General recommendations:
    MySQL started within last 24 hours - recommendations may be inaccurate
    Enable the slow query log to troubleshoot bad queries
    When making adjustments, make tmp_table_size/max_heap_table_size equal
    Reduce your SELECT DISTINCT queries without LIMIT clauses
    Set thread_cache_size to 4 as a starting value
    Your applications are not closing MySQL connections properly
Variables to adjust:
    tmp_table_size (> 32M)
    max_heap_table_size (> 16M)
    thread_cache_size (start at 4)

I think if I do what MySQLtuner says, MySQL will use more RAM.

Best Answer

There are several mechanisms available on Linux to hard-cap the memory available to a process.

On newer systems, you can use cgroups, and if that's available that's probably the best solution. (Use the tools from the libcgroup package to automatically classify the mysql daemon into a memory control group with memory.limit_in_bytes = 64M; or whatever.

On older systems, if the mysql daemon is being started by a script, you could simply use ulimit to restrict the memory available — put a ulimit -v 65536 statement in the script up above where the daemon is actually started.

That said, with modern software, this is really pushing what you can get away with. You may just plain need more RAM than you have. One option might be to switch to SQLite instead of MySQL — then you don't have a separate daemon running at all.