Mysql utilise lentement la mémoire jusqu'à ce qu'il commence à utiliser le swap

8

J'utilise un serveur de base de données RAM rackspace de 1 Go. Pour une raison quelconque, dans environ 2 jours, l'utilisation de la mémoire passe de l'utilisation de très peu de swap à l'utilisation de 100 Mo. Si je ne redémarre pas sql, il continuera à utiliser plus de swap. (Mon fichier my.cnf est illustré ci-dessous et l'utilisation de la mémoire indiquée ci-dessous)

Quelques antécédents: j'ai environ 50 bases de données actives qui ont le même schéma qui utilisent INNODB pour leurs tables. J'ai quelques bases de données avec peu de trafic qui utilisent MyISAM.

Sur les tables INNODB, je n'utilise PAS de connexions persistantes. J'ai également une fonction de rapport qui crée une table temporaire. (Cela peut être gourmand en ressources, mais cela n'arrive PAS souvent)

J'utilise CENTOS 6.3 et mysql 5.5.28-log

Même si j'utilise le swap, les performances sont toujours assez bonnes. J'ai juste peur que si je ne redémarre pas tous les quelques jours, j'aurai un problème.

Voici mon journal de free -m pendant environ 2 jours: (Le premier enregistrement est juste après un redémarrage de mysql)

12/26 2:08 PM EST
             total       used       free     shared    buffers     cached
Mem:           992        697        295          0         74        362
-/+ buffers/cache:        260        732
Swap:          976         15        961

12/26 4:10 PM EST
[root@php-pos-db ~]# free -m
             total       used       free     shared    buffers     cached
Mem:           992        791        201          0         97        405
-/+ buffers/cache:        287        705
Swap:          976         14        961

12/27 2:52 PM EST
[root@php-pos-db ~]# free -m
             total       used       free     shared    buffers     cached
Mem:           992        947         45          0         55        169
-/+ buffers/cache:        722        270
Swap:          976         34        942

12/28 1:41 PM EST
             total       used       free     shared    buffers     cached
Mem:           992        963         29          0         45        119
-/+ buffers/cache:        797        195
Swap:          976         48        927

12/28 7:24 PM EST
[root@php-pos-db ~]# free -m
             total       used       free     shared    buffers     cached
Mem:           992        957         35          0         41        141
-/+ buffers/cache:        774        218
Swap:          976         90        886

12/28 8:33 PM EST
[root@php-pos-db ~]# free -m
             total       used       free     shared    buffers     cached
Mem:           992        948         44          0         48        130
-/+ buffers/cache:        768        224
Swap:          976         96        880

my.cnf

# The MySQL database server configuration file.
#
# You can copy this to one of:
# - "/etc/mysql/my.cnf" to set global options,
# - "~/.my.cnf" to set user-specific options.
# 
# One can use all long options that the program supports.
# Run program with --help to get a list of available options and with
# --print-defaults to see which it would actually understand and use.
#
# For explanations see
# http://dev.mysql.com/doc/refman/5.1/en/server-system-variables.html
#
# Take care to only add/remove/change a setting if you are comfortable
# doing so! For Rackspace customers, if you have any questions or
# concerns, please contact the MySQL Database Services Team. Be aware
# that some work performed by this team can involve additional billable
# fees.
#
# This file generated for host php-pos-db please modify
# variables if the server is resized from 1016636kB

[mysqld]

### General
user                = mysql
port                = 3306
datadir                         = /var/lib/mysql
tmpdir                          = /tmp
socket                          = /var/lib/mysql/mysql.sock
skip-external-locking           = 1
log_error                       = /var/log/mysqld.log

## This prevents using host-based authentication. That means users must be
## created using an ip-address (ie 'myuser'@'192.168.100.1') or must make
## use of the % wildcard (ie 'myuser'@'%'). The benefit to not using
## host-based authentication is that DNS will not impact MySQL performance.
#skip-name-resolve

## If open-files-limit is set very low, MySQL may increase on its own. Either
## way, increase this if MySQL gives 'too many open files' errors. Setting
## this above 65535 could be unwise (MySQL may crash).
open-files-limit                = 20000

### Cache
thread-cache-size               = 16
table-open-cache                = 4096
table-definition-cache          = 512

## Generally, it is unwise to set the query cache to be larger than 64-128M 
## as the costs associated with maintaining the cache outweigh the performance
## gains. A far superior solution would be to implement memcached, though this
## required modifying the application, among other things.
query-cache-type                = 1
query-cache-size                = 32M
query-cache-limit               = 1M

### Per-thread Buffers
sort-buffer-size                = 1M
read-buffer-size                = 1M
read-rnd-buffer-size            = 2M
join-buffer-size                = 1M

### Temp Tables
tmp-table-size                  = 64M 
max-heap-table-size             = 64M

### Networking
back-log                        = 100
max-connections                 = 50
max-connect-errors              = 10000
max-allowed-packet              = 16M
interactive-timeout             = 600
wait-timeout                    = 180
net_read_timeout        = 30
net_write_timeout       = 30
# This value is the size of the listen queue for incoming TCP/IP connections.
back_log            = 128

#### Storage Engines
## Set this to force MySQL to use a particular engine / table-type
## for new tables. This setting can still be overridden by specifying
## the engine explicitly in the CREATE TABLE statement.
default-storage-engine         = InnoDB

## Makes sure MySQL does not start if InnoDB fails to start. This helps
## prevent ugly silent failures.
innodb                          = FORCE

### MyISAM
## Not sure what to set this to?
## Try running a 'du -sch /var/lib/mysql/*/*.MYI'
## This will give you a good estimate on the size of all the MyISAM indexes.
## (The buffer may not need to set that high, however)
key-buffer-size                 = 2M
## This setting controls the size of the buffer that is allocated when 
## sorting MyISAM indexes during a REPAIR TABLE or when creating indexes 
## with CREATE INDEX or ALTER TABLE.
myisam-sort-buffer-size         = 2M

### InnoDB
## Note: While most settings in MySQL can be set at run-time, many InnoDB
## variables cannot be set at runtime as require restarting MySQL
###
## These settings control how much RAM InnoDB will use. Generally, when using
## mostly InnoDB tables, the innodb-buffer-pool-size should be as large as
## is possible without swapping or starving other processes of RAM. The other 
## two settings usually do not need to be changed, but can help for very large 
## datasets.
innodb-buffer-pool-size         = 285M
innodb-log-buffer-size          = 8M

## Be careful when changing these as they require re-generating the 
## ib-logfile* files, which must be done carefully. Do not change this unless 
## you are familiar with the procedure.
innodb-log-file-size           = 128M
innodb-log-files-in-group      = 2

## This will cause each table to create its own .ibd file
innodb-file-per-table           = 1

## Setting this to 2 will decrease disk I/O but can cause up to a second of
## queries to be lost during a hard outage (i.e. power failures)
# innodb-flush-log-at-trx-commit = 2

### Replication
## Set this to the Server's instance ID in replication environments
server-id                       = 1

#log-bin                        = /var/lib/mysql/bin-log
#relay-log                      = /var/lib/mysql/relay-log
#relay-log-space-limit          = 4G
#expire-logs-days               = 5

## This should be enabled on conventional MySQL slaves
#read-only                      = 1

## This will cause replicated statements on a slave to be written to the slave's binlog
## Enable this on the middle slave of M->S->S configs
#log-slave-updates              = 1

#binlog-format                  = STATEMENT

### Logging
## This option determines the destination for general query log and slow query log output.
## The option value can be given as one or more of the words TABLE, FILE, or NONE.
## NOTE: Table logging takes away 50% of performance and thus is not recommended
##       http://bugs.mysql.com/bug.php?id=30414
## In addition, you cannot backup the contents of these tables properly
## (mysqldump skips these tables by default since they cannot be locked)
#log-output                     = FILE
slow-query-log                 = 1
slow-query-log-file            = /var/lib/mysql/slow-log
long-query-time                = 2
log-queries-not-using-indexes  = 1

[mysqld-safe]
log-error                       = /var/log/mysqld.log

[mysqldump]
max-allowed-packet      = 16M

# * IMPORTANT: Additional settings that can override those from this file!
#   The files must end with '.cnf', otherwise they'll be ignored.
#
!includedir /etc/sysconfig/mysqld-config/
Chris Muench
la source

Réponses:

5

MySQL a l'habitude désagréable d'être heureux de l'échange. Jeremy Cole a mieux abordé cette question dans son blog: http://blog.jcole.us/2012/04/16/a-brief-update-on-numa-and-mysql/ . De ce blog, vous apprenez qu'il y a quelque chose que vous pouvez faire: ajouter à l' numactl --interleave=allintérieur de /etc/init.d/mysql.

SUGGESTIONS

Si le serveur est dédié uniquement à MySQL, veuillez modifier ce qui suit dans /etc/my.cnf:

[mysqld]
innodb_open_files=1000
innodb_flush_method=O_DIRECT
innodb_buffer_pool_size=768M
innodb_log_file_size=192M

Si le serveur est au moins dual-core, ajoutez ces

innodb_buffer_pool_instances=2
innodb_read_io_threads=16
innodb_write_io_threads=16
innodb_io_capacity=2000

Ensuite, connectez-vous à mysql run SET GLOBAL innodb_fast_shutdown = 0;

Ensuite, exécutez ce qui suit dans le système d'exploitation

cd /var/lib/mysql
service mysql stop
mv ib_logfile0 ib_logfile0.bak
mv ib_logfile1 ib_logfile1.bak
service mysql start

Essaie !!!

MISE À JOUR 2012-12-31 08:30 EDT

De votre dernier commentaire

Il a cessé de grimper d'environ 1 Go. J'ai supprimé les bases de données inutilisées et il semble que mysql 5.5 stocke beaucoup de données en mémoire car cela ne s'est pas produit dans 5.0. Mysql a-t-il beaucoup changé?

Oui, MySQL a beaucoup changé. En fait, il existe de nombreux cas où la mise à niveau de MySQL 5.0 vers MySQL 5.5 a entraîné une dégradation des performances. InnoDB 5.5 est désormais équipé pour faire de l'hyperthreading et de l'engagement multicœur.

Percona l'a testé il y a un moment .

Veuillez me lire les précédents articles sur ce sujet

J'ai également écrit à ce sujet dans ServerFault et StackOverflow

RolandoMySQLDBA
la source
Je vais essayer ceci: Quelle est la différence entre innodb_buffer_pool_size et innodb-buffer-pool-size
Chris Muench
innodb_buffer_pool_sizede 768M pourrait repousser la limite sur une machine avec seulement 1 Go de RAM. Il ne reste que 256 Mo pour tout ce qui se passe dans le noyau et l'espace utilisateur en dehors de MySQL, ainsi que tout ce qui se passe dans MySQL en dehors du pool de mémoire tampon InnoDB ... Vous devez définir cela sur quelque chose, mais honnêtement, je chercherais à obtenir plus de mémoire ainsi que.
James L
FWIW, NUMA ne devrait pas être un facteur ici: une machine de 1 Go sur Rackspace exécutant CentOS 6.3 sera une machine virtuelle avec un seul nœud NUMA présenté.
James L
@James, car c'est une machine virtuelle, vous avez raison. Le réglage multicœur n'est pas nécessaire et 75% de la RAM sur 1 Go est trop faible. Il a besoin d'au moins 4 Go.
RolandoMySQLDBA
J'ai effectué une mise à niveau vers un serveur rack 2 Go et l'utilisation de la mémoire continue d'augmenter. Nous sommes perplexes sur ce qui se passe. Cela ne s'est PAS produit dans mysql 5.0.96
Chris Muench
0

Outre les très bons conseils donnés par Rolando, vous pouvez, côté système, activer un paramètre sans échange à l' aide de sysctl . Je place habituellement vm.swappiness=10sur la machine MySQL dans /etc/sysctl.conf . Il donne un accès restreint au swap, mais le permet si nécessaire.

La valeur par défaut de vm.swappiness est 60, ce qui est très permissif.

dominix
la source
0

Remarque : j'ai publié cette réponse à une question connexe sur stackoverflow. Cette solution est spécifique à Linux et Systemd, mais en fait, elle peut être adaptée à tout système qui prend correctement en charge les memlockappels et offre la possibilité de le faire pour les processus qui ne restent pas root.

Mise à jour : cette solution pourrait, en fait, ne pas fonctionner aussi bien. Voir note à la fin.

Il existe une classe d'applications dans laquelle vous ne voulez jamais qu'elles s'échangent. Une telle classe est une base de données. Les bases de données utiliseront la mémoire comme caches et tampons pour leurs zones de disque, et cela n'a absolument aucun sens que celles-ci soient jamais échangées. La mémoire particulière peut contenir certaines données pertinentes qui ne sont pas nécessaires pendant une semaine jusqu'au jour où un client le demande. Sans la mise en cache / l'échange, la base de données trouverait simplement l'enregistrement pertinent sur le disque, ce qui serait assez rapide; mais avec l'échange, votre service peut prendre du temps à répondre.

mysqldinclut le code pour utiliser l'appel OS / système memlock. Sous Linux, depuis au moins 2.6.9, cet appel système fonctionnera pour les processus non root qui ont la CAP_IPC_LOCKcapacité [1] . Lors de l'utilisation memlock(), le processus doit toujours fonctionner dans les limites de la LimitMEMLOCKlimite. [2] . L'une des (quelques) bonnes choses systemdest que vous pouvez accorder mysqldces capacités au processus, sans avoir besoin d'un programme spécial. Si vous pouvez également définir les limites comme vous vous en doutez ulimit. Voici un overridefichier mysqldqui fait les étapes requises, y compris quelques autres dont vous pourriez avoir besoin pour un processus tel qu'une base de données:

[Service]
# Prevent mysql from swapping
CapabilityBoundingSet=CAP_IPC_LOCK

# Let mysqld lock all memory to core (don't swap)
LimitMEMLOCK=-1 

# do not kills this process if low on memory
OOMScoreAdjust=-900 

# Use higher io scheduling
IOSchedulingClass=realtime    

Type=simple    
ExecStart=
ExecStart=/usr/sbin/mysqld --memlock $MYSQLD_OPTS

Remarque La communauté standard mysql est actuellement livrée avec Type=forking et ajoute --daemonizel'option au service sur la ExecStartligne. C'est intrinsèquement moins stable que la méthode ci-dessus.

À propos du remplacement des fichiers dans systemd : vous créez un répertoire dans /etc/systemd/system/named mysqld.service.det vous y placez le nouveau fichier (avec le contenu ci-dessus).

MISE À JOUR Je ne suis pas 100% satisfait de cette solution. Après plusieurs jours d'exécution, j'ai remarqué que le processus avait encore d'énormes quantités de swap! En examinant /proc/XXXX/smaps, je note ce qui suit:

  • Le plus gros contributeur de swap provient d'un segment de pile! Au début, cela ne semblait pas si mal, mais après plusieurs jours, il s'élevait à 437 Mo et fluctuait. Cela présente des problèmes de performances évidents. Il indique également une fuite de mémoire basée sur la pile.
  • Il n'y a aucune page verrouillée . Cela indique que l' memlockoption dans MySQL (ou Linux) est cassée. Dans ce cas, cela n'aurait pas beaucoup d'importance car MySQL ne peut pas verrouiller la pile.
Otheus
la source