Измеряем производительность «облачных» дисков — спасаем MySQL

в 14:10, , рубрики: amazon, ebs, IOPS, Блог компании 1С-Битрикс, Веб-разработка, системное администрирование, метки: , , ,

В последнее время в облачных средах и хостингах все чаще стали попадаться «виртуальные» жесткие диски. Техническая служба хостера может заверять, что «виртуальный» диск — быстрый, как десяток рейдов 10 (рейд 100 ;-) ) и держит сотни, а то и тысячи IOPS – однако MySQL заметно для клиентов тормозит. А как это доказать хостеру?

Проблема в том, что измерить «скорость» виртуального жесткого диска изнутри виртуальной машины – непросто, т.к. неясно, что мерить в первую очередь, чем и зачем ;-) А сделать это нужно, чтобы убедить администраторов виртуальной конфигурации, что дело не в приложении и настройках MySQL. И нужно было, как говориться, просто «помыть руки» перед чтением мануала к хранилищу.

В статье я проиллюстрирую простую методику нахождения «точки опрокидывания» производительности виртуального жесткого диска, с использованием доступных в дистрибутивах инструментов – sysbench и iostat. Также мы измерим «точку опрокидывания» известных своей тормознутостью виртуальных дисков EBS от Амазона – как обычных EBS, так и Provisioned IOPS EBS (1000 и 2000 IOPS).

Теория

К черту! Слишком много измерений и букв – последовательное чтение/запись, произвольное чтение/запись, перезаписи, влияние файлового кэша ядра, оптимизация очереди запросов, варианты опций и архитектуры файловой системы… Мы поступим проще – сэмулируем многопоточную нагрузку на виртуальный диск, подобную создаваемой сервером MySQL и посмотрим, как диску, или что за ним в сети скрывается, дышится.

А чтобы не было скучно, добавим к gnu.org немного романтики :-)

Измеряем производительность «облачных» дисков — спасаем MySQL

Как MySQL нагружает диск

Для InnoDB, для типичного веб-приложения, если набор данных не помещается в оперативную память (именно поэтому были изобретены базы данных ;-) ), информация будет, в основном, считываться с диска в произвольном порядке (страницы buffer pool и кластеризованные индексы, хранящиеся на диске), а записываться — последовательно (журналы транзакций и бинарный лог).

Периодически buffer pool из оперативной памяти будет сбрасываться на диск – произвольная запись. Сразу исключаем отсутствие кэша записи и «батарейки» в виртуальном хранилище – оно должно быть, иначе MySQL в режиме ACID (innodb-flush-log-at-trx-commit=1) просто умрет от сожаления.

Важно понять тут, что запросы клиентов MySQL выполняет в параллельных потоках – и диск будет нагружаться, соответственно, несколькими потоками одновременно.

Создаем нагрузку

Начнем с простого EBS-диска амазона. Нагружать виртуальный диск будем инструментом sysbench (в CentOS он доступен пакетах, собрать из исходников несложно):

yum install sysbench
mkdir -p /mount/disk_ebs/mysql/test_folder
cd /mount/disk_ebs/mysql/test_folder
sysbench --test=fileio --file-total-size=16G prepare

Важный момент – создаем суммарный объем тестовых файлов (16G), превышающий как минимум в 2 раза объем оперативной памяти виртуальной машины (не спрашивайте, почему в 2 раза ;-), чем больше — тем лучше). Это нужно для уменьшения влияния файлового кэша операционной системы – при повторном запуске тестовые файлы лучше, поэтому, перегенерить заново (либо создать несколько тестовых папок и переключаться между ними).

Теперь создаем нагрузку в N потоков, эмулируя ~N клиентов сервера СУБД, выполняющих запросы (да я знаю, что внутри СУБД есть несколько служебных потоков, но не будем пока усложнять). Допустим, ожидается, что с БД будут одновременно работать 10 апачей:

sysbench --num-threads=10 --test=fileio --file-test-mode=rndrw --max-time=180 --file-rw-ratio='2' --file-total-size=16G --max-requests=1000000 run

Что измеряем?

Теперь самое интересное. Нам не интересно, какие результаты покажет sysbench – он нам только нагрузку создает. Мы лишь смотрим, как чувствует себя виртуальный диск под нагрузкой:

iostat –xm 10
Device:         rrqm/s   wrqm/s     r/s     w/s    rMB/s    wMB/s avgrq-sz avgqu-sz   await  svctm  %util

xvdm              0.00     0.00  120.50    0.00     2.05     0.00    34.79    10.50   87.47   8.30 100.00

Диск «завален» запросами большую часть процессорного времени, что видно по «%util = 100» — драйвер диска накапливает запросы в очередь и по мере готовности устройства «скармливает» их (некоторые путают этот показатель с пропускной способностью шины к диску, что, конечно, неверно). Тут ясно, если драйвер вынужден ждать почти все время, то диск – загружен под завязку.

Среднее время обработки одного запроса «svctm» — 8.3 ms. Многовато, но нормально для дисков Амазона. Тут нет ничего криминального – обычная физика.

Среднее время ожидания обработки одного запроса «await» — 87.47 ms и средняя длина очереди запросов в драйвере диска «avgqu-sz» – 10.5. Это много, ждать почти 100 ms для обработки одного запроса! Очевидно, как получается эта величина – грубо размер очереди (avgqu-sz) умножается на время обработки одного запроса (svctm).

Итак, мы видим, что всего 10 конкурентных запросов на произвольное чтение/запись (ключи --file-test-mode=rndrw и --file-rw-ratio='2') приводят замедлению работы с виртуальным жестким диском.

Да так, что приходится ждать один запрос почти 100 ms. А если веб-страница создает 200 запросов к диску – сколько времени она будет строиться? 20 секунд?

Интересно, а при каком числе потоков диск Амазона не начинает накапливать очередь и обслуживает запросы быстрее хотя бы 50 ms (лучше вообще меньше 20 ms — субъективно)? Видим, что при 5 потоках. Конечно, это слабый показатель, без софтварного рейда не обойтись …

Device:         rrqm/s   wrqm/s     r/s     w/s    rMB/s    wMB/s avgrq-sz avgqu-sz   await  svctm  %util

xvdm              0.00     0.00  127.50    0.00     2.05     0.00    32.88     5.10   39.78   7.84 100.00

Видим, что размер очереди – 5.1 и время выполнения одного запроса – 39.78.

Тестируем «быстрые» виртуальные диски Амазона

Относительно недавно Амазон анонсировал «быстрые» диски с гарантированным числом IOPS (теория IOPS – обширна, как наша страна, погуглите, en.wikipedia.org/wiki/IOPS). Мы знаем, что простые смертные SATA-диски не держат более 100 IOPS (одновременное чтение и запись), а, к сожалению, также смертные 15k SAS-диски – не более ~200 IOPS. Также известно, что SSD-диски и SAN на других технологиях могут осилить сотни, и даже тысячи IOPS – понятно, что они значительно дороже.

Итак, посмотрим, на каком числе одновременных потоков «быстрые» виртуальные диски Амазона начинают тупить и собирать запросы в очередь. Сломаем козе левую ногу!
Измеряем производительность «облачных» дисков — спасаем MySQL

Диск EBS с 1000 IOPS

Один поток:

Device:         rrqm/s   wrqm/s     r/s     w/s    rMB/s    wMB/s avgrq-sz avgqu-sz   await  svctm  %util

xvdk              0.00     0.00 1084.50    0.00    27.33     0.00    51.61     3.72    3.43   0.91  99.20

Обратите внимание на маленькое время обработки запроса самим виртуальным диском – 0.91 ms. Видимо массив на SSD ;-) Размер очереди ~4, а среднее время одного запроса – 3.43 ms.

20 потоков:

Device:         rrqm/s   wrqm/s     r/s     w/s    rMB/s    wMB/s avgrq-sz avgqu-sz   await  svctm  %util

xvdk              0.00     0.00 1059.50    0.00    26.37     0.00    50.98    55.39   51.97   0.94 100.00

Видим, что при 20 потоках запрос придется ждать ~50 ms из-за образования очереди в 55 запросов.

Диск EBS с 2000 IOPS

20 потоков:

Device:         rrqm/s   wrqm/s     r/s     w/s    rMB/s    wMB/s avgrq-sz avgqu-sz   await  svctm  %util

xvdl              0.00     0.00 1542.50    0.00    36.29     0.00    48.18    33.20   21.29   0.65 100.00

50 потоков:

Device:         rrqm/s   wrqm/s     r/s     w/s    rMB/s    wMB/s avgrq-sz avgqu-sz   await  svctm  %util

xvdl              0.00     0.00 1498.50    0.00    36.63     0.00    50.06    86.17   57.05   0.67 100.00

Итоги измерений

Видим, что EBS-диск с 2000 IOPS показывает примерно такую же latency (~50ms) на 50 потоках, как диск с 1000 IOPS на 20 потоках и обычный EBS диск на 6-7 потоках (видимо у обычных EBS дисков IOPS находится в пределах 200-300).

Что еще случается

Виртуальные жесткие диски нередко дарят сюрпризы. Иногда их просто недонастроили, т.к. не успели дочитать man…

Недавно столкнулся с подобным кейсом, когда при создании многопоточной тестовой нагрузки на пустом MySQL сервере у «большого-дорогого-быстрого-сетевого» виртуального диска скакал показатель svctm от 0.5 до 1 ms в ночное время и от ~10 до 100 ms – в дневное (хотел померить в полнолуние, не дождался). MySQL разумеется – тормозил. Причина была в параллельно использующих сетевое хранилище и незнающих друг о друге проектах, а не настройках MySQL, который пытались сделать виноватым ;-)

Резюме

Используя подручные инструменты, мы довольно быстро определили предел конкурентной многопоточной нагрузки, при котором виртуальный диск начинает накапливать очередь и обслуживать довольно типичные для MySQL запросы за 50 ms и более. Теперь можно предположить, сколько дисков собрать в рейд, чтобы обеспечить latency, допустим, в 10-20 ms при заданном числе клиентов. Понятно, что это приблизительные данные, но они, безусловно, помогут двинуться дальше, особенно если измерить производительность настоящего жесткого диска/рейда и прийти с этими сравнительными данными и бутылкой шампанского к облачному хостеру;-)

В заключение, поздравляю всех с прошедшим праздником, желаю быстрых виртуальных дисков, надежных серверов и точных измерений! Заходите к нам на Битрикс24. Удачи!

Автор: AlexSerbul

Источник


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js