Я предпочитаю запускать MySQL с innodb_flush_method = O_DIRECT в большинстве случаев — он гарантирует, что нет никаких накладных расходов на двойную буферизацию, и я могу сохранить ограниченный объем кэша файловой системы, который я обычно имел бы на сервере базы данных для тех вещей, которые необходимо кэшировать — системные файлы, двоичный журнал, FRM-файлы, системные таблицы MySQL MyISAM и т. д. Начиная с MySQL 5.5, MySQL использует асинхронный ввод-вывод, который должен очень эффективно загружать подсистему ввода-вывода, позволяя выдавать много невыполненных запросов, которые могут быть объединены на уровне ОС или RAID-контроллера. поэтому мы должны ожидать, по крайней мере, такую же хорошую производительность от O_DIRECT, как от буферизованного режима? Оказывается, это не всегда так.
Я пришел к этому дублю случайно, поэтому у него не так много науки, но я думаю, что он все еще довольно представительный. У меня есть старый тестовый сервер с жесткими дисками SATA 4 * 7200 об / мин в RAID10. Он имеет 8 ГБ ОЗУ, и я использую Percona Server 5.5.28-29.1, на котором 6 ГБ выделено для innodb_buffer_pool, что при остальной потребности в памяти оставляет примерно 1 ГБ для кэша ОС.
Вот фрагмент кода pt :
# Percona Toolkit System Summary Report ######################
Date | 2013-01-03 22:29:39 UTC (local TZ: EST -0500)
Hostname | smt2
Uptime | 6 days, 6:21, 4 users, load average: 0.00, 0.01, 0.05
System | Supermicro; PDSMi; v0123456789 (Other)
Service Tag | 0123456789
Platform | Linux
Release | Ubuntu 12.04.1 LTS (precise)
Kernel | 3.2.0-35-generic
Architecture | CPU = 64-bit, OS = 64-bit
Threading | NPTL 2.15
SELinux | No SELinux detected
Virtualized | No virtualization detected
# Processor ##################################################
Processors | physical = 1, cores = 2, virtual = 2, hyperthreading = no
Speeds | 2x1200.000
Models | 2xIntel(R) Pentium(R) D CPU 3.00GHz
Caches | 2x2048 KB
У меня есть и старая таблица, которая не была оптимизирована в течение длительного периода времени, поэтому она отражает естественное состояние таблицы, как это было бы в производстве с течением времени:
mysql> show table status like "post_channel" \G
*************************** 1. row ***************************
Name: post_channel
Engine: InnoDB
Version: 10
Row_format: Compact
Rows: 278987416
Avg_row_length: 75
Data_length: 20975714304
Max_data_length: 0
Index_length: 9047113728
Data_free: 6291456
Auto_increment: NULL
Create_time: 2012-12-31 16:24:54
Update_time: NULL
Check_time: NULL
Collation: utf8_general_ci
Checksum: NULL
Create_options:
Comment:
1 row in set (0.02 sec)
Размер таблицы составляет приблизительно 30 ГБ, включая индексы, что намного больше, чем размер пула буферов и доступный кэш ОС. Я запускаю CHECK TABLE для этой таблицы, которая в основном выполняет сканирование данных и индексов, что будет отражать запросы на сканирование больших таблиц и сканирование таблиц, хотя на самом деле это не главное.
Суть в том, что я обнаружил, что в режиме буферизованного ввода-вывода запрос занимал почти половину времени, затрачиваемого на его выполнение в режиме O_DIRECT. Это не может быть объяснено дополнительным кешем, так как 1 ГБ кеша ОС по сравнению с 6 Б пула буферов означает, что от этого мало что получится, и поэтому прирост производительности, скорее всего, будет достигнут за счет того, что операционная система Read Ahead делает вместо этого , Это может быть подтверждено числом innodb_data_reads (значения с интервалом в 100 секунд)
| Innodb_data_reads | 54561 | | Innodb_data_reads | 38277 | | Innodb_data_reads | 25895 | | Innodb_data_reads | 31363 | | Innodb_data_reads | 170816 | | Innodb_data_reads | 207432 | | Innodb_data_reads | 156896 | | Innodb_data_reads | 19059 | | Innodb_data_reads | 16805 |
с числом считываемых данных, превышающим 2000 в секунду — намного больше, чем этот программный RAID может сделать в реальных IOP.
Я начал экспериментировать с другой конфигурацией read_ahead. Percona Server по-прежнему позволяет мне включить Random Read_Ahead, который недоступен в MySQL 5.5 (другая версия добавлена обратно в MySQL 5.6), поэтому я попробовал это, а также отключил все операции чтения вперед. В обоих случаях для данной заданной рабочей нагрузки производительность была наилучшей при включении обоих типов read_ahead, но в буферизованном режиме она оставалась намного лучше. Посмотрите на график:
Это говорит мне о том, что в MySQL IO есть большой неиспользованный потенциал, так как я думаю, что мы должны получать очень близкие числа для буферизованного и небуферизованного ввода-вывода для рабочих нагрузок только для чтения, если что-то небуферизованное производительность должно быть лучше, так как у него меньше накладных расходов с двойной буферизацией а также больше информации, которую MySQL имеет о данных, к которым будут обращаться в следующий раз — в случае полного сканирования таблицы, сканирования индекса и т. д. информация о блоках, которые будут необходимы в дальнейшем, известна заранее с очень высокой вероятностью. Предварительная выборка, основанная на чем-то подобном, может быть очень ценным дополнением.
MySQL 5.6 имеет больше изменений в коде ввода-вывода, включая то, что должно быть значительно улучшено упреждающим чтением, и я проверю его поведение дальше. Давайте посмотрим, если ситуация резко отличается.
Хорошая новость заключается в том, что даже несмотря на то, что преимущества производительности в режиме с буферизацией могут быть существенными для некоторых рабочих нагрузок, такие случаи редки — большинство рабочих нагрузок OLTP действительно работают лучше в режиме O_DIRECT. Контроллер RAID также может иметь существенное значение, так как O_DIRECT применяется только к логике операционной системы, в то время как контроллер RAID может выполнять некоторую форму упреждающего чтения, что делает ненужной помощь опережающего чтения ОС. Что ж, здесь есть над чем поэкспериментировать даже с таким второстепенным предметом — у специалистов по базам данных работа никогда не будет завершена.
