MySQL plante de temps à autre avec l'erreur «Erreur fatale: impossible d'allouer de la mémoire pour le pool de mémoire tampon»


40

Ajoutée au montage, 2013-05-29: Comme il s’agit d’une longue question et discussion, voici un bref résumé de la question et de la solution. J'ai eu des problèmes avec MySQL et Apache sur un petit serveur Linux (1 Go de mémoire). Apache demandait toujours plus de mémoire et, par conséquent, l'OS tue toujours MySQL pour le récupérer. La solution consistait à remplacer Apache par Lighttpd. Après cela, l’utilisation de la mémoire sur le serveur est complètement stable depuis plusieurs mois et je n’ai eu aucun plantage. fin de montage

Je suis un administrateur système débutant pour un petit serveur virtuel. La fonction principale du serveur est d’exécuter le logiciel de système de gestion de cours Moodle à code source ouvert , écrit en PHP. Il s'appuie sur une base de données, en l'occurrence MySQL, et un serveur Web, en l'occurrence Apache.

Le serveur exécute la version 5.8 (finale) 64 bits de CentOS avec 1 Go de mémoire et 200 Go de disque, version 2.6.18-308.8.2.el5xen du noyau. La version de MySQL est Ver 14.14 Distrib 5.5.25, pour Linux (x86_64) en utilisant readline 5.1.

Je ne pense pas que le logiciel Moodle utilise beaucoup MySQL. Actuellement, environ dix enseignants seulement y ont accès. Lorsque je dump et que je compresse avec bzip2 toute la base de données, la taille du dump obtenu est inférieure à 1 Mo.

J'ai mis en place le système il y a quelques mois. Le serveur Apache a été stable pendant tout ce temps, mais MySQL est tombé en panne plusieurs fois. J'ai essayé de connaître la configuration optimale du Web et, la dernière fois que j'ai modifié le /etc/my.cnffichier, j'ai utilisé le fichier /usr/share/doc/mysql55-server-5.5.25/my-large.cnffourni avec MySQL à titre d'exemple. Le fichier indique qu'il est destiné aux systèmes de 512 Mo de mémoire. Je pensais donc que l'utilisation de ses paramètres de configuration liés à la mémoire serait sans danger pour ce système. (J'avais précédemment configuré les paramètres liés à la mémoire de MySQL avec des nombres beaucoup plus petits, et je pensais que cela aurait pu provoquer des plantages. Bien que les plantages se produisent encore, le système est au moins plus rapide maintenant.) Voici le contenu actuel de /etc/my.cnf:

# /etc/my.cfg

# The main and only MySQL configuration file on [WEBSITE ADDRESS REDACTED].
# Last updated 2012-09-23 by Teemu Leisti.

# Most of the memory settings are set to be the same as the example setting file
# /usr/share/doc/mysql55-server-5.5.25/my-large.cnf, which is meant for systems
# with 512M of memory.  This server currently has twice that, i.e. 1G of memory,
# which should make these settings safe.


[client]
default_character_set           = utf8
port                            = 3306
socket                          = /var/lib/mysql/mysql.sock

[mysqld]
character_set_filesystem        = utf8
character_set_server            = utf8
datadir                         = /var/lib/mysql
innodb_additional_mem_pool_size = 20M
innodb_buffer_pool_size         = 256M # You can set .._buffer_pool_size up to
                                       # 50..80% of RAM, but beware of setting
                                       # memory usage too high
innodb_data_file_path           = ibdata1:10M:autoextend
innodb_data_home_dir            = /var/lib/mysql
innodb_flush_log_at_trx_commit  = 1
innodb_lock_wait_timeout        = 50
innodb_log_buffer_size          = 8M
innodb_log_file_size            = 64M # Set .._log_file_size to 25% of buffer
                                      # pool size
innodb_log_group_home_dir       = /var/lib/mysql
interactive_timeout             = 60
key_buffer_size                 = 256M
long_query_time                 = 10
max_allowed_packet              = 1M
max_connections                 = 30
port                            = 3306
query_cache_limit               = 2M # see http://emergent.urbanpug.com/?p=61
query_cache_size                = 16M
read_buffer_size                = 1M
read_rnd_buffer_size            = 4M
skip_networking                 # Only local processes need to use MySQL
skip_symbolic_links             # Disabling symbolic_links is recommended to
                                # prevent assorted security risks
slow_query_log_file             = /var/log/mysql-slow-queries.log
socket                          = /var/lib/mysql/mysql.sock
sort_buffer_size                = 1M
table_open_cache                = 256
thread_cache_size               = 8
thread_concurrency              = 2 #    = number of CPUs * 2
user                            = mysql
wait_timeout                    = 10

[mysqld_safe]
log_error                       = /var/log/mysqld.log
open_files_limit                = 4096
pid_file                        = /var/run/mysqld/mysqld.pid

[mysqldump]
quick
max_allowed_packet              = 16M

[mysql]
no-auto-rehash
# Remove the next comment character if you are not familiar with SQL
safe-updates

[myisamchk]
key_buffer_size                 = 128M
sort_buffer_size                = 128M
read_buffer                     = 2M
write_buffer                    = 2M

[mysqlhotcopy]
interactive-timeout

Comme vous pouvez le constater dans la configuration, celle-ci utilise le moteur InnoDB et ne traite que les demandes de localhost. En plus de l'administrateur système (moi), Moodle est le seul utilisateur de MySQL.

Lorsque MySQL plante, les informations suivantes sont invariablement écrites dans le fichier journal /var/log/mysqld.log(à l'exception des horodatages, bien sûr):

120926 08:00:51 mysqld_safe Number of processes running now: 0
120926 08:00:51 mysqld_safe mysqld restarted
120926  8:00:53 [Note] Plugin 'FEDERATED' is disabled.
120926  8:00:53 InnoDB: The InnoDB memory heap is disabled
120926  8:00:53 InnoDB: Mutexes and rw_locks use GCC atomic builtins
120926  8:00:53 InnoDB: Compressed tables use zlib 1.2.3
120926  8:00:53 InnoDB: Using Linux native AIO
120926  8:00:53 InnoDB: Initializing buffer pool, size = 256.0M
InnoDB: mmap(274726912 bytes) failed; errno 12
120926  8:00:53 InnoDB: Completed initialization of buffer pool
120926  8:00:53 InnoDB: Fatal error: cannot allocate memory for the buffer pool
120926  8:00:53 [ERROR] Plugin 'InnoDB' init function returned error.
120926  8:00:53 [ERROR] Plugin 'InnoDB' registration as a STORAGE ENGINE failed.
120926  8:00:53 [ERROR] Unknown/unsupported storage engine: InnoDB
120926  8:00:53 [ERROR] Aborting

120926  8:00:53 [Note] /usr/libexec/mysqld: Shutdown complete

120926 08:00:53 mysqld_safe mysqld from pid file /var/run/mysqld/mysqld.pid ended

Parfois , je peux redémarrer MySQL en commandant service mysqld restart, mais parfois cette commande échoue avec cette sortie: mysqld dead but subsys locked. Dans ces cas, la seule chose à laquelle j'ai pu penser pour remédier à la situation est de redémarrer le serveur, après quoi MySQL peut être redémarré. Dans ces cas, la sortie ressemble à ceci:

120926 11:43:48 mysqld_safe Starting mysqld daemon with databases from /var/lib/mysql
120926 11:43:48 [Note] Plugin 'FEDERATED' is disabled.
120926 11:43:48 InnoDB: The InnoDB memory heap is disabled
120926 11:43:48 InnoDB: Mutexes and rw_locks use GCC atomic builtins
120926 11:43:48 InnoDB: Compressed tables use zlib 1.2.3
120926 11:43:48 InnoDB: Using Linux native AIO
120926 11:43:48 InnoDB: Initializing buffer pool, size = 256.0M
120926 11:43:48 InnoDB: Completed initialization of buffer pool
120926 11:43:48 InnoDB: highest supported file format is Barracuda.
InnoDB: The log sequence number in ibdata files does not match
InnoDB: the log sequence number in the ib_logfiles!
120926 11:43:48  InnoDB: Database was not shut down normally!
InnoDB: Starting crash recovery.
InnoDB: Reading tablespace information from the .ibd files...
InnoDB: Restoring possible half-written data pages from the doublewrite
InnoDB: buffer...
120926 11:43:51  InnoDB: Waiting for the background threads to start
120926 11:43:52 InnoDB: 1.1.8 started; log sequence number 466807107
120926 11:43:52 [Note] Event Scheduler: Loaded 0 events
120926 11:43:52 [Note] /usr/libexec/mysqld: ready for connections.
Version: '5.5.25'  socket: '/var/lib/mysql/mysql.sock'  port: 0  MySQL Community Server (GPL)

Voici ce que la commande free -maffiche actuellement:

# free -m
             total       used       free     shared    buffers     cached
Mem:          1024        869        154          0         70        153
-/+ buffers/cache:        644        379
Swap:            0          0          0

Habituellement, la colonne "libre" se situe entre 50 et 100 Mo.

La sortie de la commande ulimit -a:

# ulimit -a
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 8192
max locked memory       (kbytes, -l) 32
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 10240
cpu time               (seconds, -t) unlimited
max user processes              (-u) 8192
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

Je n'ai modifié aucun des fichiers de paramètres ou de codes de Moodle, à l'exception de celui /var/www/html/moodle/config.phpqui ressemble à ceci (les lignes de commentaire sont supprimées pour économiser de l'espace):

<?php
unset($CFG);  // Ignore this line
global $CFG;  // This is necessary here for PHPUnit execution
$CFG = new stdClass();
$CFG->dbtype    = 'mysqli';           // 'pgsql', 'mysqli', 'mssql', 'sqlsrv' or 'oci'
$CFG->dblibrary = 'native';           // 'native' only at the moment
$CFG->dbhost    = 'localhost';        // eg 'localhost' or 'db.isp.com' or IP
$CFG->dbname    = 'moodle';           // database name, eg moodle
$CFG->dbuser    = 'moodleuser';       // your database username
$CFG->dbpass    = '[REDACTED]';       // your database password
$CFG->prefix    = 'moodle_';          // prefix to use for all table names
$CFG->dboptions = array(
    'dbpersist' => false,       // should persistent database connections be
                                //  used? set to 'false' for the most stable
                                //  setting, 'true' can improve performance
                                //  sometimes
    'dbsocket'  => true,        // should connection via UNIX socket be used?
                                //  if you set it to 'true' or custom path
                                //  here set dbhost to 'localhost',
                                //  (please note mysql is always using socket
                                //  if dbhost is 'localhost' - if you need
                                //  local port connection use '127.0.0.1')
    'dbport'    => '',          // the TCP port number to use when connecting
                                //  to the server. keep empty string for the
                                //  default port
);
$CFG->passwordsaltmain = '[REDACTED]';
$CFG->wwwroot   = 'http://[REDACTED]';
$CFG->dataroot  = '/var/moodledata';
$CFG->directorypermissions = 02777;
$CFG->admin = 'admin';
date_default_timezone_set('Europe/Helsinki');
$CFG->disableupdatenotifications = true;
require_once(dirname(__FILE__) . '/lib/setup.php'); // Do not edit

(Cependant, j'ai installé deux plugins Moodle, le module d'assistance et le bloc , mais je ne vois pas comment ils pourraient être impliqués dans ce problème.)

Même après avoir mis /etc/my.cnfà jour son état il y a une semaine, MySQL s'est écrasé plusieurs fois avec les symptômes indiqués ci-dessus. En tant que débutant en administration de base de données, et après avoir passé beaucoup de temps sur Google à propos de ce problème, je ne sais plus quoi faire. Aucune suggestion? Devrais-je publier plus de données de configuration?

Ajout sur édition:

Le contenu du fichier /var/log/messages.1est:

Sep 23 04:02:18 [machine name] syslogd 1.4.1: restart.
Sep 26 08:00:51 [machine name] kernel: mysqld invoked oom-killer: gfp_mask=0x201d2, order=0, oomkilladj=0
Sep 26 08:00:51 [machine name] kernel:
Sep 26 08:00:51 [machine name] kernel: Call Trace:
Sep 26 08:00:51 [machine name] kernel:  [<ffffffff802c1bd5>] out_of_memory+0x8b/0x203
Sep 26 08:00:51 [machine name] kernel:  [<ffffffff8020fa49>] __alloc_pages+0x27f/0x308
Sep 26 08:00:51 [machine name] kernel:  [<ffffffff802139c9>] __do_page_cache_readahead+0xc8/0x1af
Sep 26 08:00:51 [machine name] kernel:  [<ffffffff8021423a>] filemap_nopage+0x14c/0x360
Sep 26 08:00:51 [machine name] kernel:  [<ffffffff80208e9d>] __handle_mm_fault+0x444/0x144f
Sep 26 08:00:51 [machine name] kernel:  [<ffffffff80263929>] _spin_lock_irqsave+0x9/0x14
Sep 26 08:00:51 [machine name] kernel:  [<ffffffff8023f468>] lock_timer_base+0x1b/0x3c
Sep 26 08:00:51 [machine name] kernel:  [<ffffffff80266d94>] do_page_fault+0xf72/0x131b
Sep 26 08:00:51 [machine name] kernel:  [<ffffffff802e5f4f>] sys_io_getevents+0x311/0x359
Sep 26 08:00:51 [machine name] kernel:  [<ffffffff802e4e56>] timeout_func+0x0/0x10
Sep 26 08:00:51 [machine name] kernel:  [<ffffffff8025f82b>] error_exit+0x0/0x6e
Sep 26 08:00:51 [machine name] kernel:
Sep 26 08:00:51 [machine name] kernel: Mem-info:
Sep 26 08:00:51 [machine name] kernel: DMA per-cpu:
Sep 26 08:00:51 [machine name] kernel: cpu 0 hot: high 0, batch 1 used:0
Sep 26 08:00:51 [machine name] kernel: cpu 0 cold: high 0, batch 1 used:0
Sep 26 08:00:51 [machine name] kernel: DMA32 per-cpu:
Sep 26 08:00:51 [machine name] kernel: cpu 0 hot: high 186, batch 31 used:117
Sep 26 08:00:51 [machine name] kernel: cpu 0 cold: high 62, batch 15 used:53
Sep 26 08:00:51 [machine name] kernel: Normal per-cpu: empty
Sep 26 08:00:51 [machine name] kernel: HighMem per-cpu: empty
Sep 26 08:00:51 [machine name] kernel: Free pages:        7256kB (0kB HighMem)
Sep 26 08:00:51 [machine name] kernel: Active:241649 inactive:0 dirty:0 writeback:0 unstable:0 free:1814 slab:4104 mapped-file:1153 mapped-anon:240592 pagetables:3298
Sep 26 08:00:51 [machine name] kernel: DMA free:3268kB min:32kB low:40kB high:48kB active:0kB inactive:0kB present:9068kB pages_scanned:0 all_unreclaimable? yes
Sep 26 08:00:51 [machine name] kernel: lowmem_reserve[]: 0 994 994 994
Sep 26 08:00:51 [machine name] kernel: DMA32 free:3988kB min:4016kB low:5020kB high:6024kB active:966596kB inactive:0kB present:1018080kB pages_scanned:6327262 all_unreclaimable? yes
Sep 26 08:00:52 [machine name] kernel: lowmem_reserve[]: 0 0 0 0
Sep 26 08:00:52 [machine name] kernel: Normal free:0kB min:0kB low:0kB high:0kB active:0kB inactive:0kB present:0kB pages_scanned:0 all_unreclaimable? no
Sep 26 08:00:52 [machine name] kernel: lowmem_reserve[]: 0 0 0 0
Sep 26 08:00:52 [machine name] kernel: HighMem free:0kB min:128kB low:128kB high:128kB active:0kB inactive:0kB present:0kB pages_scanned:0 all_unreclaimable? no
Sep 26 08:00:52 [machine name] kernel: lowmem_reserve[]: 0 0 0 0
Sep 26 08:00:52 [machine name] kernel: DMA: 1*4kB 2*8kB 1*16kB 1*32kB 2*64kB 2*128kB 1*256kB 1*512kB 2*1024kB 0*2048kB 0*4096kB = 3268kB
Sep 26 08:00:52 [machine name] kernel: DMA32: 17*4kB 2*8kB 2*16kB 1*32kB 0*64kB 0*128kB 1*256kB 1*512kB 1*1024kB 1*2048kB 0*4096kB = 3988kB
Sep 26 08:00:52 [machine name] kernel: Normal: empty
Sep 26 08:00:52 [machine name] kernel: HighMem: empty
Sep 26 08:00:52 [machine name] kernel: 1214 pagecache pages
Sep 26 08:00:52 [machine name] kernel: Swap cache: add 0, delete 0, find 0/0, race 0+0
Sep 26 08:00:52 [machine name] kernel: Free swap  = 0kB
Sep 26 08:00:52 [machine name] kernel: Total swap = 0kB
Sep 26 08:00:52 [machine name] kernel: Free swap:            0kB
Sep 26 08:00:52 [machine name] kernel: 262144 pages of RAM
Sep 26 08:00:52 [machine name] kernel: 8320 reserved pages
Sep 26 08:00:52 [machine name] kernel: 22510 pages shared
Sep 26 08:00:52 [machine name] kernel: 0 pages swap cached
Sep 26 08:00:52 [machine name] kernel: Out of memory: Killed process 1371, UID 27, (mysqld).

puis les lignes liées au redémarrage à 11h42.

Ajout sur l'édition n ° 2:

J'ai essayé de commenter la réponse de Michael, mais je n'aimais pas beaucoup les commentaires, alors je réponds ici.

Merci pour votre réponse, Michael. Je viens de modifier ma question pour inclure le contenu du journal système de la machine au moment du blocage. (CentOS semble appeler son journal système /var/log/messages.)

Oui, les journaux MySQL et système semblent presque identiques à ceux de la question que vous avez liée. Et maintenant que vous en parlez, il est évident que le mysql restartedmessage signifie que MySQL est déjà tombé en panne. Le journal système indique que c'est oom_killerce qui est arrivé au processus. Dans votre réponse précédente, vous écrivez: "Première hypothèse: les processus enfants apache sont complètement fous." Il me semble qu'Apache est le suspect évident ici aussi.

Un peu plus tôt, j’avais découvert l’article Optimisation de MySQL et d’Apache pour une utilisation réduite de la mémoire, première partie . Pour la configuration d'Apache, l'auteur recommande: "Tout d'abord, Apache. Mon premier énoncé est, si vous pouvez l'éviter, essayez. Lighttpd et thttpd sont tous deux de très bons serveurs Web sans fioritures, et vous pouvez exécuter lighttpd avec PHP. Même si Si vous exploitez un site à volume élevé, vous pouvez sérieusement gagner en performance en transmettant du contenu statique (images et fichiers javascript, généralement) à un serveur HTTPd ultra-rapide et léger, tel que Lighttpd. "

Je pense suivre les conseils de l'auteur et je suis d'accord avec mon client pour que je remplace Apache par Lighttpd le week-end prochain sur le serveur. J'espère que ça va résoudre les problèmes. L'utilisation de deux serveurs virtuels est probablement impossible.

Je n'avais pas pensé qu'utiliser deux serveurs open-source matures stables, tels que MySQL et Apache, sur la même machine, avec une quantité de mémoire raisonnable, serait aussi gênant.

Réponses:


36

S'il vous plaît examiner ma réponse à cette question récente . Je crois que les circonstances sont identiques.

Ne modifiez pas votre configuration MySQL à ce stade, car MySQL n’est pas le problème, c’est seulement un symptôme du problème ... c’est que vous semblez avoir un système avec une petite quantité de mémoire et un espace d’échange nul.

Votre serveur ne plante pas "parce que" la mémoire ne peut pas être allouée pour le pool de mémoire tampon. Votre serveur tombe en panne ... et ne peut ensuite pas redémarrer par la suite en raison de l'indisponibilité de la mémoire système. Toute la mémoire configurée pour le pool de mémoire tampon InnoDB est demandée par le système au démarrage de mysql.

Quand vous voyez ce message de log ...

120926 08:00:51 mysqld_safe Number of processes running now: 0

... votre serveur est déjà mort. S'il n'a rien enregistré avant cela, il ne va rien enregistrer du premier crash. Les journaux suivants sont postérieurs à la tentative automatique de redémarrage.

Vérifiez votre syslog et vous devriez trouver des messages indiquant que le noyau est allé chercher des processus à tuer en raison d'une insuffisance de mémoire.

L’étape 1 consisterait probablement à ajouter de l’espace de swap et / ou à allouer de la RAM, si possible.

Si cela n'est pas possible, vous pouvez réellement envisager de réduire la taille de votre configuration innodb-buffer-pool. (Je n'aurais jamais cru m'entendre dire ça.) Tant que votre base de données est petite et votre trafic léger, vous n'aurez peut-être pas besoin d'un pool de mémoire tampon aussi volumineux ... et puisque la mémoire du pool de mémoire tampon InnoDB est entièrement allouée au démarrage, que cela soit nécessaire ou non, cela libérerait une partie de vos ressources. la mémoire du système pour tout ce qui l'exige. (La recommandation de 75% à 80% de la RAM totale pour dimensionner le pool de mémoire tampon n'est vraie que si l'ensemble du serveur est dédié à MySQL.)

L'étape 2 consistera à examiner le modèle de forking d'Apache et ce que vous devrez peut-être faire différemment dans la configuration pour l'empêcher de surcharger votre serveur. Il est fort probable qu'une augmentation incontrôlée de la quantité ou de la mémoire requise par les processus enfants Apache déclenche une cascade d'événements, ce qui a pour conséquence que le noyau tue MySQL afin d'éviter un crash complet du serveur.

En fonction de votre flexibilité, vous pouvez même envisager deux machines virtuelles distinctes pour Apache et MySQL.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.