Сегодня я проводил тест на своем старом тестовом компьютере с обычными жесткими дисками (без рейда с BBU) и заметил нечто необычное в статистике использования ЦП.
Тест был выполнен так:
sysbench --num-threads=64 --max-requests=0 --max-time=600000 --report-interval=10 --test=oltp --db-driver=mysql --oltp-dist-type=special --oltp-table-size=1000000 --mysql-user=root --mysql-password=password run
А это значит: создать 64 потока и забить базу данных запросами как можно быстрее. Поскольку тест выполнялся на локальном хосте, я ожидал, что эталонный тест полностью насытит систему — будь то использование ЦП или блокировка ввода-вывода этого эталона, поэтому он не тратит много времени на блокировки базы данных, особенно потому, что в этой системе всего 2 сердечники.
Глядя на VMSTAT, я заметил это:
[root@smt1 mysql]# vmstat 10 procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu----- r b swpd free buff cache si so bi bo in cs us sy id wa st 13 0 0 880156 40060 2140824 0 0 12 750 895 1045 32 8 54 6 0 0 0 0 877116 40060 2141312 0 0 0 1783 2185 23112 44 10 41 5 0 15 0 0 872648 40068 2141960 0 0 0 1747 2204 25743 41 11 46 2 0 0 0 0 868056 40068 2142604 0 0 0 1803 2164 26224 40 11 44 5 0 17 1 0 863216 40068 2143160 0 0 0 1875 1948 23020 36 9 50 5 0 0 0 0 858384 40168 2143656 0 0 0 1063 1855 21116 32 9 45 14 0 23 0 0 855848 40176 2144232 0 0 0 1755 2036 23181 36 10 48 6 0 49 0 0 851248 40184 2144648 0 0 0 1679 2313 22832 45 10 40 5 0 10 0 0 846292 40192 2145248 0 0 0 1911 1980 23185 36 9 50 4 0 0 0 0 844260 40196 2145868 0 0 0 1757 2152 26387 39 11 45 5 0 0 3 0 839296 40196 2146520 0 0 0 1439 2104 25096 38 10 50 1 0
Рассматривая последние несколько столбцов, мы имеем ожидание ввода-вывода, как правило, в процентах от одной цифры, когда «простаивающий» процессор находится в диапазоне 40-50%. Вы также можете увидеть это визуально на графике из Percona Cloud Tools.
Таким образом, система должна быть полностью насыщена нагрузкой, но вместо этого у нас 50% простоя процессора, а iowait обычно в однозначных числах?
Запуск SHOW PROCESSLIST может дать нам хорошую идею в этом случае:
mysql> show processlist; +-----+---------------+-----------------+--------+---------+------+----------------+--------------------------------------------------------------------+-----------+---------------+-----------+ | Id | User | Host | db | Command | Time | State | Info | Rows_sent | Rows_examined | Rows_read | +-----+---------------+-----------------+--------+---------+------+----------------+--------------------------------------------------------------------+-----------+---------------+-----------+ | 1 | root | localhost:39624 | NULL | Sleep | 0 | | NULL | 0 | 0 | 0 | | ... | 32 | root | localhost | sbtest | Execute | 0 | NULL | COMMIT | 0 | 0 | 0 | | 33 | root | localhost | sbtest | Execute | 0 | NULL | COMMIT | 0 | 0 | 0 | | 34 | root | localhost | sbtest | Execute | 0 | Sorting result | SELECT c from sbtest where id between 365260 and 365359 order by c | 0 | 0 | 0 | | 35 | root | localhost | sbtest | Execute | 0 | NULL | COMMIT | 0 | 0 | 0 | | 36 | root | localhost | sbtest | Execute | 0 | NULL | COMMIT | 0 | 0 | 0 | | 37 | root | localhost | sbtest | Execute | 0 | NULL | COMMIT | 0 | 0 | 0 | | 38 | root | localhost | sbtest | Execute | 0 | Writing to net | DELETE from sbtest where id=496460 | 0 | 1 | 1 | | 39 | root | localhost | sbtest | Execute | 0 | NULL | COMMIT | 0 | 0 | 0 | ... | 89 | root | localhost | sbtest | Execute | 0 | NULL | COMMIT | 0 | 0 | 0 | | 90 | root | localhost | sbtest | Execute | 0 | NULL | COMMIT | 0 | 0 | 0 | | 91 | root | localhost | sbtest | Execute | 0 | NULL | COMMIT | 0 | 0 | 0 | | 268 | root | localhost | NULL | Query | 0 | NULL | show processlist | 0 | 0 | 0 | +-----+---------------+-----------------+--------+---------+------+----------------+--------------------------------------------------------------------+-----------+---------------+-----------+ 68 rows in set (0.00 sec)
Так что большинство запросов останавливаются на этапе COMMIT. Проверяя настройки мы можем увидеть:
mysql> select @@innodb_flush_log_at_trx_commit; +----------------------------------+ | @@innodb_flush_log_at_trx_commit | +----------------------------------+ | 1 | +----------------------------------+ 1 row in set (0.00 sec)
Это означает, что Percona Server работает в полностью ACID-режиме, что при использовании медленных жестких дисков без BBU означает, что commit вызывает синхронизацию данных на диске, что очень дорого.
Итак, мы выяснили, что на самом деле происходит … но если мы действительно много ждем на диске, почему iowait этого не показывает?
Чтобы ответить на этот вопрос, давайте посмотрим, как на самом деле вычисляется IOwait.
IOwait — это тип простоя (а в более ранних версиях Linux он был включен в простое) — когда у нас есть процесс / поток, который будет запущен, если он не будет ожидать ввода-вывода, мы рассматриваем этот iowait, если он не запускается из-за чего-либо иначе (ожидание на мьютексе, сети и т. д.) считается бездействующим.
Записи в файл журнала Innodb сериализуются — поэтому только один процесс будет выполнять запись в журнал (и синхронизацию), в то время как все остальные, ожидающие возможности фиксации, будут ожидать какой-либо механизм синхронизации, чтобы получить уведомление о завершении фиксации как части групповой коммит.
Что забрать? Возьмите iowait% числа от vmstat / iostat с зерном соли. Возможно, выиграть гораздо больше, чем быстрее подсистемы ввода-вывода (или правильной конфигурации), чем показывают цифры iowait. Рассматривайте iowait% + idle% ЦП как «доступный процессор», который потенциально может быть использован для улучшения подсистемы ввода-вывода и минимизации конфликтов
Чтобы проиллюстрировать это, давайте снова посмотрим на график процессора — теперь, когда я установил innodb_flush_log_at_trx_commit = 2
Как видно из графика, мы восстановили гораздо больше, чем 6-7% времени простоя, которое у нас было — загрузка ЦП пользователя увеличилась до 70%, а idle + iowait теперь составляет 10-15%; пропускная способность системы увеличилась примерно на 60% — гораздо больше, чем позволяло бы «устранение iowait».