MySQL verwendet langsam Speicher, bis Swap verwendet wird

8

Ich verwende einen 1 GB RAM-Rackspace-Datenbankserver. Aus irgendeinem Grund geht die Speichernutzung in etwa 2 Tagen von sehr wenig Swap auf 100 MB über. Wenn ich SQL nicht neu starte, wird weiterhin mehr Swap verwendet. (Meine my.cnf-Datei wird unten angezeigt und die Speichernutzung wird unten angezeigt.)

Einige Hintergrundinformationen: Ich habe ungefähr 50 aktive Datenbanken mit demselben Schema, die INNODB für ihre Tabellen verwenden. Ich habe ein paar Datenbanken mit wenig Verkehr, die MyISAM verwenden.

In den INNODB-Tabellen verwende ich KEINE dauerhaften Verbindungen. Ich habe auch eine Berichtsfunktion, die eine temporäre Tabelle erstellt. (Dies kann ressourcenintensiv sein, kommt aber NICHT oft vor.)

Ich verwende CENTOS 6.3 und MySQL 5.5.28-Log

Obwohl ich Swap verwende, ist die Leistung immer noch ziemlich gut. Ich habe nur Angst, dass ich ein Problem habe, wenn ich nicht alle paar Tage neu starte.

Hier ist mein Protokoll von free -m für ca. 2 Tage: (Der erste Datensatz ist direkt nach einem MySQL-Neustart)

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
quelle

Antworten:

5

MySQL hat die böse Angewohnheit, tauschfreudig zu sein. Jeremy Cole hat dies am besten in seinem Blog angesprochen: http://blog.jcole.us/2012/04/16/a-brief-update-on-numa-and-mysql/ . In diesem Blog erfahren Sie, dass Sie numactl --interleave=allFolgendes tun können: Fügen Sie in /etc/init.d/mysql hinzu.

VORSCHLÄGE

Wenn der Server nur MySQL ausführen soll, ändern Sie Folgendes in /etc/my.cnf:

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

Wenn der Server mindestens Dual-Core ist, fügen Sie diese hinzu

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

Als nächstes melden Sie sich bei MySQL an SET GLOBAL innodb_fast_shutdown = 0;

Führen Sie als Nächstes im Betriebssystem Folgendes aus

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

Versuche es !!!

UPDATE 2012-12-31 08:30 EDT

Aus deinem letzten Kommentar

Es hörte auf, um 1 GB zu klettern. Ich habe nicht verwendete Datenbanken entfernt und es scheint nur, dass MySQL 5.5 viele Daten im Speicher speichert, da dies in 5.0 nicht geschehen ist. Hat sich MySQL sehr verändert?

Ja, MySQL hat sich sehr verändert. In der Tat gibt es viele Fälle, in denen ein Upgrade von MySQL 5.0 auf MySQL 5.5 zu Leistungseinbußen führte. InnoDB 5.5 ist jetzt für Hyperthreading und Multicore-Engagement ausgestattet.

Percona hat dies tatsächlich vor einiger Zeit getestet .

Bitte lesen Sie mir frühere Beiträge zu diesem Thema

Ich habe darüber auch in ServerFault und StackOverflow geschrieben

RolandoMySQLDBA
quelle
Ich werde es versuchen: Was ist der Unterschied zwischen innodb_buffer_pool_size und innodb-buffer-pool-size
Chris Muench
innodb_buffer_pool_sizevon 768M könnte das Limit auf einem Computer mit nur 1 GB RAM überschreiten. Nur noch 256 MB für alles, was außerhalb von MySQL im Kernel und im Benutzerbereich vor sich geht, sowie alles, was in MySQL außerhalb des InnoDB-Pufferpools passiert ... Sie müssen das auf etwas setzen, aber ehrlich gesagt würde ich versuchen, mehr Speicher zu bekommen auch.
James L
FWIW, NUMA sollte hier kein Faktor sein: Ein 1-GB-Computer bei Rackspace unter CentOS 6.3 wird eine VM mit nur einem NUMA-Knoten sein.
James L
@ James, da es sich um eine VM handelt, haben Sie Recht. Multicore-Tuning ist nicht erforderlich und 75% des Arbeitsspeichers bei 1 GB sind zu niedrig. Er braucht mindestens 4 GB.
RolandoMySQLDBA
Ich habe ein Upgrade auf einen 2-GB-Rackspace-Server durchgeführt und die Speichernutzung steigt immer noch. Wir sind ratlos darüber, was passiert. Dies geschah NICHT in MySQL 5.0.96
Chris Muench
0

Abgesehen von den sehr guten Ratschlägen von Rolando können Sie auf der Systemseite mit sysctl eine Einstellung ohne Tausch aktivieren . Normalerweise setze ich vm.swappiness=10auf MySQL-Computer in /etc/sysctl.conf . Es bietet eingeschränkten Zugriff auf den Swap, erlaubt ihn jedoch bei Bedarf.

Der Standardwert von vm.swappiness ist 60, was sehr zulässig ist.

Dominix
quelle
0

Hinweis : Ich habe diese Antwort auf eine verwandte Frage zum Stapelüberlauf gepostet. Diese Lösung ist Linux- und Systemd-spezifisch, kann jedoch an jedes System angepasst werden, das memlockAufrufe ordnungsgemäß unterstützt , und bietet die Möglichkeit, dies für Prozesse zu tun, die nicht root bleiben.

Update : Diese Lösung funktioniert möglicherweise nicht so gut. Siehe Anmerkung am Ende.

Es gibt eine Klasse von Anwendungen, in denen Sie niemals möchten, dass sie ausgetauscht werden. Eine solche Klasse ist eine Datenbank. Datenbanken verwenden Speicher als Caches und Puffer für ihre Festplattenbereiche, und es macht absolut keinen Sinn, dass diese jemals ausgetauscht werden. Der bestimmte Speicher enthält möglicherweise einige relevante Daten, die eine Woche lang nicht benötigt werden, bis ein Kunde eines Tages danach fragt. Ohne das Zwischenspeichern / Austauschen würde die Datenbank einfach den relevanten Datensatz auf der Festplatte finden, was ziemlich schnell wäre; Beim Tauschen kann es jedoch plötzlich lange dauern, bis Ihr Dienst reagiert.

mysqldEnthält Code zur Verwendung des Betriebssystem- / Systemaufrufs memlock. Unter Linux funktioniert dieser Systemaufruf seit mindestens 2.6.9 für Nicht-Root-Prozesse mit der CAP_IPC_LOCKFunktion [1] . Bei der Verwendung memlock()muss der Prozess weiterhin innerhalb der Grenzen des LimitMEMLOCKGrenzwerts arbeiten. [2] . Eines der (wenigen) guten Dinge systemdist, dass Sie dem mysqldProzess diese Funktionen gewähren können, ohne ein spezielles Programm zu benötigen. If kann auch die Grenzwerte so einstellen, wie Sie es erwarten würden ulimit. Hier ist eine overrideDatei mysqld, die die erforderlichen Schritte ausführt, einschließlich einiger anderer, die Sie möglicherweise für einen Prozess wie eine Datenbank benötigen:

[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

Hinweis Die Standard-Community-MySQL wird derzeit mit ausgeliefert Type=forking und erweitert --daemonizeden Dienst in der ExecStartLeitung um die Option . Dies ist von Natur aus weniger stabil als das obige Verfahren.

Informationen zum Überschreiben von Dateien in systemd : Sie erstellen ein Verzeichnis in /etc/systemd/system/named mysqld.service.dund legen die neue Datei (mit dem oben genannten Inhalt) darin ab.

UPDATE Ich bin mit dieser Lösung nicht 100% zufrieden. Nach einigen Tagen Laufzeit bemerkte ich, dass der Prozess immer noch enorme Mengen an Swap hatte! Bei der Prüfung stelle /proc/XXXX/smapsich Folgendes fest:

  • Der größte Swap-Beitrag stammt aus einem Stack-Segment! Anfangs schien das nicht so schlimm zu sein, aber nach einigen Tagen lag es bei 437 MB und schwankte. Dies führt zu offensichtlichen Leistungsproblemen. Es zeigt auch einen stapelbasierten Speicherverlust an.
  • Es gibt keine gesperrten Seiten . Dies zeigt an, dass die memlockOption in MySQL (oder Linux) fehlerhaft ist. In diesem Fall würde es nicht viel ausmachen, da MySQL den Memlock-Stack nicht ausführen kann.
Otheus
quelle