Высокая нагрузка на I/O из-за MariaDB.

Вопрос или проблема

Я использую nginx с php-fpm и mariadb. Иногда страницы загружаются медленно. Проверив munin, я заметил, что среднее время ожидания I/O очень велико, до 8 секунд. В php-slowlog указаны функции mysql как причина, например, mysql_query(). Я пытаюсь настроить сервер mariadb (например, увеличиваю кэш, перемещаю временный каталог с hdd на ramdisk). Но мое I/O случайным образом увеличивается.

enter image description here

Например, в начале графика. Я думал, что решил проблему, но затем время ожидания снова увеличилось без очевидных причин. Когда я перезапускаю mariadb, оно резко уменьшается (вы можете увидеть, как оно падает в конце, я перезапустил mariadb здесь).

Я не очень много использую I/O, пик составляет около 8 МБ/с:

enter image description here

Замечательно то, что соотношение Table_locks_immediate к Table_locks_waited увеличивается. Когда я перезапускаю mariadb, оно составляло 2.5%. Сервер был активен примерно 30 минут, и оно увеличилось до 3.5%. Я также заметил, что когда сервер “подвисает”, количество работающих потоков (Threads_running) высокое (до 30). Когда это число уменьшается, сервер перестает “подвисать”.

Мой my.cnf:

[client]
port        = 3306
socket      = /var/run/mysqld/mysqld.sock

[mysqld_safe]
socket      = /var/run/mysqld/mysqld.sock
nice        = 0

[mysqld]
sync_binlog = 3

user        = mysql
pid-file    = /var/run/mysqld/mysqld.pid
socket      = /var/run/mysqld/mysqld.sock
port        = 3306
basedir     = /usr
datadir     = /var/lib/mysql
#tmpdir     = /tmp
tmpdir      = /var/mysqltmp
lc_messages_dir = /usr/share/mysql
lc_messages = en_US
skip-external-locking
log-bin=/var/mysqltmp/mysql-bin.log
#log=/var/mysqltmp/mysql.log
log-error=/var/mysqltmp/mysql-error.log
log-slow-queries=/var/mysqltmp/mysql-slowquery.log

bind-address        = 127.0.0.1

max_tmp_tables      = 100
max_connections     = 150
connect_timeout     = 5
#wait_timeout            = 600
wait_timeout        = 800
max_allowed_packet  = 16M
thread_cache_size       = 128
#sort_buffer_size        = 4M
sort_buffer_size    = 8M
bulk_insert_buffer_size = 8M
max_heap_table_size     = 128M
tmp_table_size      = 128M
#tmp_table_size          = 64M

# * MyISAM
myisam_recover          = BACKUP
key_buffer_size         = 256M
#open-files-limit   = 2000
table_open_cache    = 1000
myisam_sort_buffer_size = 8M

#concurrent_insert  = 2
#read_buffer_size        = 2M
read_buffer_size    = 4M
#read_rnd_buffer_size    = 1M
read_rnd_buffer_size    = 2M

# * Query Cache Configuration
query_cache_limit       = 256M
query_cache_size        = 256M
# for more write intensive setups, set to DEMAND or OFF
query_cache_type        = ON
#table_cache                    = 400
table_open_cache        = 2000
join_buffer_size        = 4M

# * Logging and Replication
log_warnings        = 2
slow_query_log      = 1
slow_query_log_file = /var/log/mysql/mariadb-slow.log
long_query_time = 1
#log_slow_rate_limit    = 1000
log_slow_verbosity  = query_plan

log_bin         = /var/log/mysql/mariadb-bin
log_bin_index       = /var/log/mysql/mariadb-bin.index
# not fab for performance, but safer
#sync_binlog        = 1
expire_logs_days    = 10
max_binlog_size         = 128M

# * InnoDB
default_storage_engine  = InnoDB
#innodb_log_file_size   = 50M
#innodb_buffer_pool_size    = 256M
innodb_buffer_pool_size = 256M
innodb_log_buffer_size  = 32M
innodb_file_per_table   = 1
innodb_open_files   = 400
innodb_io_capacity  = 400
#innodb_flush_method    = O_DIRECT
innodb_flush_method     = O_DSYNC

[mysqldump]
quick
quote-names
max_allowed_packet  = 16M

[isamchk]
#key_buffer     = 16M
key_buffer             = 32M

!includedir /etc/mysql/conf.d/

Если большинство ваших таблиц используют InnoDB, увеличьте innodb_buffer_pool_size как минимум до размера ваших баз данных или установите 2GB. Если сервер используется только для служб базы данных, установите это значение на ~60% или 70% от общего объема памяти, и ваша база данных полностью уместится в памяти.

Если большинство ваших таблиц используют MyISAM, увеличьте key_buffer_size аналогичным образом.

Для MyISAM установите concurrent_insert на 2.

query_cache_size выше 64MB будет пустой тратой памяти.

Регулярно запускайте mysqlcheck -o -A для улучшения статистики индексов для внутреннего планировщика запросов MySQL.

Избегайте запросов, которые выполняют full_scan.

Уменьшите innodb_io_capacity до 100 или 120, если у вас однодисковая система хранения или простая RAID.

Используйте XFS для преимущества одновременной записи в один файл.

Монтируйте файловую систему с опцией noatime.

Избегайте использования подкачки.

Отключите ненужные журналы.

Я столкнулся с этим после недавнего обновления MariaDB на CentOS 7. В то время я не хотел перезагружать сервер, и это не казалось необходимым.

Сначала я думал, что проблема может быть в недостатке места на диске, так как у меня были похожие проблемы после выполнения запланированного резервного копирования. После проверки эта проблема не подтверждалась: было достаточно оперативной памяти и места на диске, но загрузка сервера с использованием top делала сервер неотзывчивым.

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

Я также попытался увеличить размер innodb_buffer_pool_size и innodb_log_file_size, чтобы посмотреть, поможет ли это. Опять же, загрузка процессора на сервере была очень высокой.

Я в итоге перезапустил сервер и любые дополнительные службы, и все вернулось в норму (< 1) с использованием top.

Ответ или решение

Повышенная нагрузка на ввод/вывод в MariaDB может быть вызвана различными факторами, особенно в контексте серверов, использующих Nginx с PHP-FPM и MariaDB. Ситуация, описанная вами, демонстрирует явные признаки проблемы с производительностью, выражающейся в высокой задержке ввода/вывода. В данной ситуации ключевыми аспектами являются длинное время ожидания ввода/вывода, высокое количество выполняемых потоков и таблицы MyISAM/ InnoDB.

Теория

Повышенная нагрузка на ввод/вывод может быть следствием нескольких основных причин:

  1. Неоптимальная конфигурация базы данных: Многие параметы конфигурации MariaDB влияют на производительность системы. Среди них могу быть параметры инициализации, такие как innodb_buffer_pool_size, key_buffer_size и т.д.

  2. Накопление блокировок и конкуренция за ресурсы: Высокий Ratio Table_locks_immediate к Table_locks_waited указывает на то, что множество соединений пытаются одновременно получить доступ к ресурсам, что приводит к задержкам при блокировке таблиц.

  3. Ограниченная пропускная способность дисковой подсистемы: Даже если средняя загрузка в 8 МБ/с может показаться небольшой, количество операций ввода/вывода в секунду (IOPS) может быть значительным, что приводит к задержкам, особенно если используется один диск или слабый RAID.

  4. Проблемы с конфигурацией операционной системы и окружения: Некоторые настройки ОС или файловой системы могут негативно сказаться на производительности ввода/вывода.

Пример

Ваш текущий файл конфигурации my.cnf имеет различные настройки, которые могут повлиять на производительность системы:

  • innodb_buffer_pool_size установлен на 256M. Если большая часть ваших данных хранится в InnoDB, увеличьте этот параметр хотя бы до 2 ГБ, если позволяет оперативная память сервера. Это позволит базе данных более эффективно использовать память для хранения часто используемых данных.

  • query_cache_size в 256M, что может оказаться избыточным. Часто рекомендуется ограничивать этот параметр до 64MB, чтобы избежать лишнего расхода памяти на хранение редко используемых запросов.

  • innodb_io_capacity в 400 может не соответствовать конфигурации диска. Для одного диска или простого RAID установите его в 100-120, чтобы избежать перегрузки дисковой подсистемы.

Применение

Рекомендации по оптимизации:

  1. Увеличение памяти для буферов: Поднимите innodb_buffer_pool_size и/или key_buffer_size (если используете MyISAM) на 60-70% от общего объема оперативной памяти. Это значительно повысит эффективность обработки данных за счет уменьшения числа операций ввода/вывода и сокращения времени ожидания.

  2. Анализ и оптимизация запросов: Регулярно используйте инструменты мониторинга, чтобы выявлять и оптимизировать медленные или ресурсоемкие запросы. Избегайте использования полных сканирований таблиц.

  3. Управление блокировками: Следите за количеством блокировок и старайтесь оптимизировать запросы, чтобы уменьшить конкуренцию за ресурсы.

  4. Мониторинг и профилактическое обслуживание: Периодически проводите mysqlcheck -o -A для оптимизации индексов и обновления статистики, что, в свою очередь, улучшает работу внутреннего планировщика запросов.

  5. Настройки файловой системы и ОС: Рассмотрите возможность перехода на файловую систему XFS для улучшения многопоточности операций записи и использования опции монтирования noatime для уменьшения нагрузки на файловую систему.

  6. Минимализация ведения логов: Если возможно, отключите ненужные логи для уменьшения нагрузки на ввод/вывод.

  7. Поиск аппаратных ограничений: Убедитесь, что аппаратные составляющие, особенно хранилище, соответствуют нагрузке. Возможны улучшения при переходе на SSD или более высокопроизводительные RAID-массивы.

Заключение

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

Оцените материал
Добавить комментарий

Капча загружается...