MySQL ne libère pas de mémoire

8

MySQL semble vouloir garder une table entière dans le cache (taille de la table = ~ 20 Go) après que de grandes insertions ou des instructions select y aient été effectuées. En ce moment, mon pool de mémoire tampon innodb est de 20 Go. La RAM totale est de 32 Go. Je fournirai une utilisation de la mémoire et une sortie du statut innodb ainsi qu'une sortie de mysqltuner. Ça me rend dingue depuis quelques jours. Aidez-moi! J'apprécie tout commentaire et s'il vous plaît laissez-moi savoir si vous avez besoin de plus d'informations.

De plus, l'exécution d'un «FLUSH TABLES» ne fait que les fermer et les rouvrir en mémoire. Du moins, je pense que c'est ce qui se passe. Voici l'état actuel de la mémoire innodb avant d'effectuer un tas d'insertions:

----------------------
BUFFER POOL AND MEMORY
----------------------
Total memory allocated 21978152960; in additional pool allocated 0
Dictionary memory allocated 6006471
Buffer pool size   1310719
Free buffers       347984
Database pages     936740
Old database pages 345808
Modified db pages  0
Pending reads 0
Pending writes: LRU 0, flush list 0, single page 0
Pages made young 78031, not young 0
0.00 youngs/s, 0.00 non-youngs/s
Pages read 551887, created 384853, written 4733512
0.00 reads/s, 0.00 creates/s, 0.00 writes/s
No buffer pool page gets since the last printout
Pages read ahead 0.00/s, evicted without access 0.00/s, Random read ahead 0.00/s
LRU len: 936740, unzip_LRU len: 0
I/O sum[0]:cur[0], unzip sum[0]:cur[0]

pourcentage d'utilisation de la mémoire mysqld: 60,9%

% d'utilisation de la mémoire mysqld après les insertions (enregistrements de 1 mil): 63,3%

puis après plus d'inserts (records 3 mil): 70,2%

ne devrait-il pas plafonner à environ 62,5% ? (20/32 Go) de RAM total?

sortie du haut triant mon utilisation MEM:

top - 14:30:56 up 23:25,  3 users,  load average: 3.63, 2.31, 1.91
Tasks: 208 total,   4 running, 204 sleeping,   0 stopped,   0 zombie
Cpu(s): 96.0%us,  3.0%sy,  0.0%ni,  0.0%id,  1.0%wa,  0.0%hi,  0.0%si,  0.0%st
Mem:  28821396k total, 28609868k used,   211528k free,   138696k buffers
Swap: 33554428k total,    30256k used, 33524172k free,  1208184k cached

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
 1228 mysql     20   0 25.1g  19g 5512 S   31 70.2  62:01.10 mysqld

voici la sortie de la mémoire innodb après que ces insertions ont été effectuées:

----------------------
BUFFER POOL AND MEMORY
----------------------
Total memory allocated 21978152960; in additional pool allocated 0
Dictionary memory allocated 6006471
Buffer pool size   1310719
Free buffers       271419
Database pages     1011886
Old database pages 373510
Modified db pages  4262
Pending reads 1
Pending writes: LRU 0, flush list 0, single page 0
Pages made young 82521, not young 0
7.08 youngs/s, 0.00 non-youngs/s
Pages read 585218, created 426667, written 5192189
24.08 reads/s, 53.08 creates/s, 1135.07 writes/s
Buffer pool hit rate 1000 / 1000, young-making rate 0 / 1000 not 0 / 1000
Pages read ahead 0.00/s, evicted without access 0.00/s, Random read ahead 0.00/s
LRU len: 1011886, unzip_LRU len: 0
I/O sum[0]:cur[266], unzip sum[0]:cur[0]

Selon l'état innodb, la mémoire totale allouée est la même - mais mon système d'exploitation (Virtual Ubuntu Server 12.04) signale plus d'utilisation de la mémoire que cela. L'utilisation de la mémoire reste la même et je la définis ici comme le service MySQL ne «libérant» pas de mémoire. Aucune suggestion?

sortie de mysqltuner.pl:

-------- Storage Engine Statistics -------------------------------------------
[--] Status: +ARCHIVE +BLACKHOLE +CSV -FEDERATED +InnoDB +MRG_MYISAM
[--] Data in MyISAM tables: 226M (Tables: 287)
[--] Data in InnoDB tables: 33G (Tables: 1000)
[--] Data in PERFORMANCE_SCHEMA tables: 0B (Tables: 17)
[--] Data in MEMORY tables: 0B (Tables: 1)
[!!] Total fragmented tables: 959

-------- Security Recommendations  -------------------------------------------
[OK] All database users have passwords assigned

-------- Performance Metrics -------------------------------------------------
[--] Up for: 23h 14m 27s (1M q [14.603 qps], 6K conn, TX: 16B, RX: 1B)
[--] Reads / Writes: 46% / 54%
[--] Total buffers: 22.2G global + 2.7M per thread (151 max threads)
[OK] Maximum possible memory usage: 22.6G (82% of installed RAM)
[OK] Slow queries: 0% (6/1M)
[OK] Highest usage of available connections: 6% (10/151)
[OK] Key buffer size / total MyISAM indexes: 2.0G/58.7M
[OK] Key buffer hit rate: 100.0% (216M cached / 38K reads)
[OK] Query cache efficiency: 81.2% (799K cached / 984K selects)
[!!] Query cache prunes per day: 5561
[OK] Sorts requiring temporary tables: 4% (819 temp sorts / 16K sorts)
[!!] Temporary tables created on disk: 27% (6K on disk / 22K total)
[OK] Thread cache hit rate: 99% (11 created / 6K connections)
[!!] Table cache hit rate: 0% (97 open / 10K opened)
[OK] Open file limit used: 12% (129/1K)
[OK] Table locks acquired immediately: 99% (433K immediate / 433K locks)
[!!] InnoDB  buffer pool / data size: 20.0G/33.6G
[OK] InnoDB log waits: 0
-------- Recommendations -----------------------------------------------------
General recommendations:
    Run OPTIMIZE TABLE to defragment tables for better performance
    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
    Increase table_cache gradually to avoid file descriptor limits
    Read this before increasing table_cache over 64: http://bit.ly/1mi7c4C
Variables to adjust:
    query_cache_size (> 128M)
    tmp_table_size (> 128M)
    max_heap_table_size (> 16M)
    table_cache (> 431)
    innodb_buffer_pool_size (>= 33G)
cherner
la source

Réponses:

8

Tout d'abord, jetez un œil à l'architecture InnoDB (gracieuseté de Percona CTP Vadim Tkachenko)

Architecture InnoDB

InnoDB

Votre statut pour le pool de tampons indique

Taille du pool de tampons 1310719

C'est votre taille de tampon dans les pages. Chaque page fait 16K . Cela s'avère 20G - 16K.

Veuillez noter ce qui suit: Vous avez poussé les données dans le pool de tampons InnoDB. Qu'est ce qui a changé ?

Buffer pool size   1310719 
Free buffers       271419 (It was 347984)
Database pages     1011886 (Is was 936740)
Old database pages 373510 (It was 345808)
Modified db pages  4262 (It was 0)

Notez également la différence entre la taille du pool de mémoire tampon dans les pages.

1310719 (taille du pool de tampons) - 1011886 (pages de base de données) = 298833

C'est 298833 pages InnoDB. Combien d'espace est-ce ???

mysql> select FORMAT(((1310719  - 1011886) * 16384) / power(1024,3),3) SpaceUsed;
+-----------+
| SpaceUsed |
+-----------+
| 4.560     |
+-----------+

C'est 4,56 Go. Cet espace est utilisé pour la section d'insertion de tampon du pool de tampons InnoDB (alias Change Buffer) . Ceci est utilisé pour atténuer les modifications apportées aux index non uniques dans le fichier d'espace disque logique système (que tous ont appris à connaître ibdata1).

Le moteur de stockage InnoDB gère les composants internes du pool de tampons. Par conséquent, InnoDB ne dépassera jamais 62,5% de la RAM. De plus, la RAM du Buffer Pool n'est jamais restituée.

D'O IS VIENNENT LES 70,2% DE RAM?

Regardez en arrière à la sortie de mysqltuner.plces lignes

[OK] Maximum possible memory usage: 22.6G (82% of installed RAM)
Key buffer size / total MyISAM indexes: 2.0G/58.7M
[--] Total buffers: 22.2G global + 2.7M per thread (151 max threads)

mysqld a trois façons principales d'allouer de la RAM

Tout petit pic dans les connexions DB augmentera la RAM au-delà du seuil de 62,5% que vous voyez pour InnoDB.

MyISAM (note latérale)

Ce qui attire mon attention, c'est

Key buffer size / total MyISAM indexes: 2.0G/58.7M

Puisque vous avez si peu d'index pour MyISAM. Vous pouvez définir le key_buffer_size à 64M.

Vous n'avez pas besoin de redémarrer mysql pour cela. Il suffit de courir

SET GLOBAL ket_buffer_size = 1024 * 1024 * 64;

Ensuite, modifiez ceci dans my.cnf

[mysqld]
key_Buffer_size = 64M

Cela donnera à l'OS 2 Go de RAM. Votre VM vous aimera tout simplement pour ça !!!

Essaie !!!

CAVEAT

L'exécution FLUSH TABLESsur des tables InnoDB ferme simplement les fichiers contre les .ibdfichiers. Cela ne poussera pas vraiment les changements directement. Les changements doivent migrer à travers les tuyaux d'InnoDB. C'est pourquoi vous voyez le pic Modified db pages. Les 4262 pages modifiées (66,59 Mo) sont vidées lorsque InnoDB planifie son vidage.

RolandoMySQLDBA
la source
merci beaucoup pour l'analyse approfondie. Cela a beaucoup plus de sens maintenant - il est donc vrai que le pool de tampons innodb restera à l'utilisation maximale de la mémoire au fil du temps (20 Go)? Et la mémoire totale que mysqld utilisera jamais est de 82% ??
cherner
C'est un oui aux deux questions
RolandoMySQLDBA
@RolandoMySQLDBA, Si je comprends bien, MySQL ne libère pas la mémoire et c'est ce que c'est. Non?
Malus
1
@MalusJan Ma réponse ne concerne pas la libération de mémoire. Ma réponse concerne la quantité de RAM utilisée pour les moteurs de stockage et les connexions DB. Parfois, les connexions DB persistantes qui ne sont pas correctement fermées peuvent contenir de la RAM allouée. Les caches pour les tampons du moteur de stockage peuvent être redimensionnés dynamiquement pour MyISAM (MySQL 5.x +) et InnoDB (MySQL 5.7+). Les caches pour les connexions DB peuvent être redimensionnés dynamiquement pour les nouvelles connexions entrantes (pas les connexions actuellement ouvertes). La mémoire non libérée est due à des bugs de fuite de mémoire dans mysqld.
RolandoMySQLDBA
@RolandoMySQLDBA. Sur le serveur, nous avons plus de 10 bases de données et nous devons créer des vidages tous les jours et chacun mysqldumpprendre de la mémoire et ne pas les libérer. Donc, après tout le vidage, environ 80% du ram est occupé par le processus mysql. Avez-vous une solution pour cela? Merci
Malus
0

J'ai rencontré un genre de problème similaire. Question: utilisez-vous la configuration de la mémoire partagée? (THP et partagé) Si oui, désactivez les pages immenses et laissez MySQL gérer la mémoire et continuer à la surveiller. Vérifiez également le nombre de processus parallèles exécutés sur le serveur, y compris les processus en mode veille. Si vous utilisez une configuration de mémoire partagée, vous avez besoin de plus de mémoire pour ce serveur.

Raja Naveed
la source