Mysql медленно использует память, пока не начнет использовать своп

8

Я использую 1 ГБ ОЗУ сервера базы данных в стойке. По какой-то причине примерно через 2 дня использование памяти переходит от использования очень маленького свопинга к использованию 100 МБ. Если я не перезапущу sql, он продолжит использовать больше swap. (Мой файл my.cnf показан ниже, а использование памяти показано ниже)

Немного предыстории: у меня около 50 активных баз данных, которые имеют ту же схему, что и INNODB для этих таблиц. У меня есть пара баз данных с небольшим трафиком, которые используют MyISAM.

В таблицах INNODB я НЕ использую постоянные соединения. У меня также есть функция отчетности, которая создает временную таблицу. (Это может быть ресурсоемким, но не часто)

Я использую CENTOS 6.3 и mysql 5.5.28-log

Несмотря на то, что я использую своп, производительность все еще довольно хорошая. Я просто боюсь, что если я не буду перезагружаться каждые несколько дней, у меня будут проблемы.

Вот мой журнал свободного -m около 2 дней: (Первая запись сразу после перезапуска 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/
Крис Мюнх
источник

Ответы:

5

MySQL действительно имеет неприятную привычку быть счастливым свопом. Джереми Коул лучше всего обратился к этому в своем блоге: http://blog.jcole.us/2012/04/16/a-brief-update-on-numa-and-mysql/ . Из этого блога вы узнаете, что есть что-то, что вы можете сделать: Добавить numactl --interleave=allв /etc/init.d/mysql.

SUGGESTIONS

Если Сервер предназначен только для работы с MySQL, измените следующее в /etc/my.cnf:

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

Если сервер хотя бы двухъядерный, добавьте эти

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

Далее, войдите в MySQL запустить SET GLOBAL innodb_fast_shutdown = 0;

Далее запустите следующее в ОС

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

Попробуйте!

ОБНОВЛЕНИЕ 2012-12-31 08:30 ПО ВОСТОЧНОМУ ВРЕМЕНИ

Из вашего последнего комментария

Он перестал подниматься около 1 ГБ. Я удалил неиспользуемые базы данных, и кажется, что MySQL 5.5 хранит много данных в памяти, как это не было в 5.0. MySQL сильно изменился?

Да, MySQL сильно изменился. На самом деле, существует много случаев, когда обновление с MySQL 5.0 до MySQL 5.5 приводило к снижению производительности. InnoDB 5.5 теперь оборудован для гиперпоточности и многоядерного взаимодействия.

Percona действительно проверила это некоторое время назад .

Пожалуйста, прочитайте мне последние сообщения на эту тему

Я также писал об этом в ServerFault и StackOverflow

RolandoMySQLDBA
источник
Я попробую: в чем разница между innodb_buffer_pool_size и innodb-buffer-pool-size
Крис Муенч
innodb_buffer_pool_sizeиз 768M может выдвигать предел на машине только с 1 ГБ оперативной памяти. Только 256M остатка для всего, что происходит в ядре и пользовательском пространстве за пределами MySQL, плюс все, что происходит в MySQL за пределами буферного пула InnoDB ... Вам нужно установить это на что-то, но, честно говоря, я бы хотел получить больше памяти также.
Джеймс Л
Кстати, NUMA не должен быть здесь фактором: 1-гигабайтный компьютер в Rackspace под управлением CentOS 6.3 будет виртуальной машиной с представленным только одним узлом NUMA.
Джеймс Л
@ Джеймс, так как это виртуальная машина, вы правы. Многоядерная настройка не требуется, и 75% ОЗУ на 1 ГБ слишком мало. Ему нужно как минимум 4ГБ.
RolandoMySQLDBA
Я обновил сервер до 2 Гб, и использование памяти все еще растет. Мы находимся в тупике от того, что происходит. Это не произошло в MySQL 5.0.96
Крис Мюнх,
0

Помимо очень хороших советов, данных Роландо, вы можете на системной стороне активировать настройку без свопинга с помощью sysctl . Я обычно устанавливаю vm.swappiness=10на MySQL машину в /etc/sysctl.conf . Это дает ограниченный доступ к свопу, но разрешает его при необходимости.

Значение по умолчанию vm.swappiness - 60, что очень допустимо.

Dominix
источник
0

Примечание : я отправил этот ответ на связанный вопрос по stackoverflow. Это решение предназначено для Linux и Systemd, но фактически может быть адаптировано к любой системе, которая должным образом поддерживает memlockвызовы и предоставляет возможность сделать это для процессов, которые не остаются корневыми.

Обновление : на самом деле это решение может работать не так хорошо. Смотрите примечание в конце.

Существует класс приложений, в которых вы никогда не хотите, чтобы они менялись местами. Одним из таких классов является база данных. Базы данных будут использовать память в качестве кэшей и буферов для своих дисковых областей, и нет абсолютно никакого смысла в том, что они когда-либо будут заменены. Конкретная память может содержать некоторые релевантные данные, которые не нужны в течение недели до одного дня, когда клиент запрашивает их. Без кэширования / обмена база данных просто найдет соответствующую запись на диске, что будет довольно быстро; но при обмене вашему сервису может потребоваться много времени, чтобы ответить.

mysqldвключает в себя код для использования ОС / системного вызова memlock. В Linux, начиная с версии 2.6.9, этот системный вызов будет работать для процессов без полномочий root, которые имеют такую CAP_IPC_LOCKвозможность [1] . При использовании memlock()процесс все равно должен работать в пределах LimitMEMLOCKлимита. [2] . Одна из (немногих) хороших вещей в systemdтом, что вы можете предоставить mysqldпроцессу эти возможности, не требуя специальной программы. Если также можно установить ограничения, как вы ожидаете ulimit. Вот overrideфайл, mysqldкоторый выполняет необходимые шаги, включая несколько других, которые могут вам понадобиться для такого процесса, как база данных:

[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

Примечание. В настоящее время стандартное сообщество mysql поставляется с этой опцией Type=forking и добавляет --daemonizeее в службу на ExecStartлинии. Это по своей природе менее стабильно, чем описанный выше метод.

О переопределении файлов в systemd : вы создаете каталог с /etc/systemd/system/именем mysqld.service.dи помещаете в него новый файл (с указанным выше содержимым).

ОБНОВЛЕНИЕ Я не на 100% доволен этим решением. После нескольких дней работы я заметил, что процесс по-прежнему требует огромного количества перестановок! Изучая /proc/XXXX/smaps, отмечу следующее:

  • Наибольший вклад в своп - это сегмент стека! Сначала это казалось не так уж и плохо, но через несколько дней оно составляло 437 МБ и колебалось. Это создает очевидные проблемы с производительностью. Это также указывает на утечку памяти из стека.
  • Есть ноль заблокированных страниц . Это означает, что memlockопция в MySQL (или Linux) не работает. В этом случае это не будет иметь большого значения, потому что MySQL не может блокировать стеки памяти.
Otheus
источник