MySQL intermitente se bloquea con el error "Error grave: no se puede asignar memoria para el grupo de búferes"

40

Agregado en edición, 29/05/2013: Debido a que esta es una larga pregunta y discusión, aquí hay un breve resumen de la pregunta y la solución. Tuve problemas para ejecutar MySQL y Apache en un pequeño servidor Linux (1 GB de memoria). Apache siguió exigiendo más memoria y, como consecuencia, el sistema operativo siempre eliminó a MySQL para recuperar su memoria. La solución fue reemplazar Apache con Lighttpd. Después de hacer eso, el uso de la memoria en el servidor ha sido completamente estable durante varios meses, y no he tenido fallas de ningún tipo. fin de edición

Soy un administrador de sistema principiante para un pequeño servidor virtual. La función principal del servidor es ejecutar el software del sistema de gestión de cursos Moodle de código abierto, escrito en PHP. Se basa en una base de datos, en este caso MySQL, y un servidor web, en este caso Apache.

El servidor ejecuta CentOS de 64 bits versión 5.8 (Final) con 1 GB de memoria y 200 GB de disco, versión del kernel 2.6.18-308.8.2.el5xen. La versión de MySQL es Ver 14.14 Distrib 5.5.25, para Linux (x86_64) usando readline 5.1.

No creo que el software Moodle sea un gran usuario de MySQL. Actualmente, solo unos diez maestros tienen acceso a él, y cuando vuelco y comprimo con bzip2 toda la base de datos, el tamaño del volcado resultante es inferior a 1 MB.

Configuré el sistema hace unos meses. El servidor Apache se ha mantenido estable todo este tiempo, pero MySQL se ha bloqueado varias veces. Traté de aprender sobre la configuración óptima desde la web, y la última vez que cambié el /etc/my.cnfarchivo, usé el archivo /usr/share/doc/mysql55-server-5.5.25/my-large.cnfque viene con MySQL como ejemplo. El archivo dice que está destinado a sistemas con 512 MB de memoria, por lo que pensé que usar sus parámetros de configuración relacionados con la memoria sería seguro para este sistema. (Antes había configurado los parámetros relacionados con la memoria de MySQL con números mucho más pequeños, y pensé que eso podría haber provocado fallas. Si bien las fallas aún ocurren, el sistema es al menos más rápido ahora). Estos son los contenidos actuales 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

Como puede ver en la configuración, la configuración utiliza el motor InnoDB y solo atiende solicitudes de localhost. Además del administrador del sistema (yo), Moodle es el único usuario de MySQL.

Cuando MySQL falla, lo siguiente se escribe invariablemente en el archivo de registro /var/log/mysqld.log(a excepción de las marcas de tiempo, por supuesto):

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

A veces puedo reiniciar MySQL ordenando service mysqld restart, pero a veces ese comando falla con esta salida: mysqld dead but subsys locked. En estos casos, lo único en lo que he podido pensar para recuperar la situación es reiniciar el servidor, después de lo cual MySQL puede reiniciarse. En estos casos, la salida se ve así:

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)

Esto es lo que el comando free -mgenera actualmente:

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

Por lo general, la columna "gratuita" tiene entre 50 y 100 MB.

La salida del comando 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

No he cambiado ninguno de los archivos de configuración o código de Moodle, excepto el /var/www/html/moodle/config.phpque se ve así (líneas de comentario eliminadas para ahorrar espacio):

<?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

(Sin embargo, he instalado dos complementos de Moodle, el módulo de Asistencia y el bloque , pero no veo cómo podrían estar involucrados con este problema).

Incluso después de actualizar /etc/my.cnfa su estado actual hace una semana, MySQL se ha bloqueado un par de veces con los síntomas mencionados anteriormente. Al ser un principiante en la administración de bases de datos, y después de buscar mucho en Google sobre este problema, no sé qué hacer a continuación. ¿Alguna sugerencia? ¿Debo publicar más datos de configuración?

Adición en edición:

Los contenidos del archivo /var/log/messages.1son:

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).

y luego líneas relacionadas con el reinicio a las 11:42.

Adición en la edición # 2:

Traté de comentar la respuesta de Michael, pero me encontré con el límite de caracteres de los comentarios, así que estoy respondiendo aquí.

Gracias por tu respuesta, Michael. Acabo de editar mi pregunta para incluir el contenido del registro del sistema de la máquina en el momento del bloqueo. (CentOS parece llamar a su registro del sistema /var/log/messages).

Sí, tanto los registros de MySQL como los del sistema parecen casi idénticos a los de la pregunta a la que se vinculó. Y ahora que lo menciona, es obvio que el mysql restartedmensaje significa que MySQL ya se había bloqueado. El registro del sistema indica que es oom_killerlo que consiguió el proceso. En su respuesta anterior, escribe: "Primera aproximación: los procesos secundarios apache se vuelven locos". Me parece que Apache es el sospechoso obvio aquí también.

Anteriormente, encontré el artículo Optimización de MySQL y Apache para un uso de memoria bajo, Parte 1 . Para configurar Apache, el autor recomienda: "En primer lugar, Apache. Mi primera afirmación es, si puede evitarlo, intente hacerlo. Lighttpd y thttpd son muy buenos sin servidores web, y puede ejecutar lighttpd con PHP. Incluso si usted Si ejecuta un sitio de gran volumen, puede obtener un gran rendimiento al transferir contenido estático (imágenes y archivos javascript, por lo general) a un servidor HTTPd ligero y súper rápido, como Lighttpd ".

Estoy pensando en seguir el consejo del autor, y he acordado con mi cliente que el próximo fin de semana, reemplazaré Apache con Lighttpd en el servidor. Espero que eso resuelva los problemas. El uso de dos servidores virtuales probablemente no sea posible.

No había pensado que usar dos servidores maduros de código abierto estables como MySQL y Apache en la misma máquina, con una cantidad razonable de memoria, sería tan problemático.

Teemu Leisti
fuente

Respuestas:

36

Por favor revise mi respuesta a esta pregunta reciente . Creo que las circunstancias son idénticas.

No cambie su configuración de MySQL en este punto, ya que MySQL no es el problema, es solo un síntoma del problema ... que es que parece tener un sistema con una pequeña cantidad de memoria y cero espacio de intercambio.

Su servidor no se bloquea "porque" no se puede asignar memoria para el grupo de búferes. Su servidor se está bloqueando ... y luego no puede reiniciarse posteriormente debido a la falta de memoria del sistema. Toda la memoria configurada para el grupo de búferes InnoDB se solicita del sistema al inicio de mysql.

Cuando vea este mensaje de registro ...

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

... su servidor ya ha muerto. Si no ha registrado nada antes de esto, no registrará nada sobre el primer bloqueo. Los registros posteriores son posteriores al intento automático de reinicio.

Verifique su syslog y debería encontrar mensajes donde el núcleo fue a buscar procesos para matar debido a una condición de falta de memoria extrema.

El paso 1 probablemente sería agregar algo de espacio de intercambio y / o asignar RAM si es posible.

Si eso no es posible, podría considerar disminuir el tamaño del grupo de búferes innodb en su configuración. (Nunca pensé que realmente me oiría decir eso). Mientras su base de datos sea pequeña y su tráfico sea liviano, es posible que no necesite un grupo de búferes tan grande ... y dado que la memoria del Grupo de búferes InnoDB se asigna al inicio, sea necesario o no, esto liberaría parte de su memoria del sistema para lo que sea que lo exija. (La recomendación de 75% a 80% de RAM total para dimensionar el grupo de búferes solo es cierta si todo el servidor está dedicado a MySQL).

El paso 2 será revisar el modelo de bifurcación de Apache y lo que podría necesitar hacer de manera diferente en la configuración para evitar que abrume a su servidor. Es muy probable que el crecimiento incontrolado de la cantidad o los requisitos de memoria de los procesos secundarios de Apache estén iniciando una cascada de eventos, lo que provocará que el kernel mate a MySQL para intentar evitar un bloqueo completo de todo el servidor.

Dependiendo de cuánta flexibilidad tenga, incluso podría considerar dos máquinas virtuales separadas para Apache y MySQL.

Michael - sqlbot
fuente