Статьи

Подробнее об оптимизации дескрипторов транзакций

Это сообщение от Алексея Копытова из MySQL Performance Blog.

Начиная с нашего первого поста об оптимизации дескрипторов транзакций, представленного в Percona Server 5.5.30-30.2, и продолжения Дмитрия Кравчука, мы получили большое количество вопросов о том, почему результаты тестов в обоих постах выглядят довольно по-разному. Нам также было любопытно, поэтому мы попытались ответить на этот вопрос, повторив тесты для различных комбинаций аппаратных средств и размеров наборов данных, включая те, которые максимально приближены к среде Дмитрия. Короче говоря, результаты вполне соответствуют нашей первоначальной публикации по всем тестовым комбинациям, подробности см. Ниже.

Вот краткое резюме контекста. В первом посте рассматриваются два случая:

  1. одиночные SELECTзапросы делают PRIMARY KEYпросмотры (ака QPs SysBench режима);
  2. те же запросы, выполняемые внутри транзакций с одним оператором ( режим TPS , см. исходное сообщение о том, почему этот случай актуален).

Дмитрий не коснулся дела № 2 и сосредоточился только на деле № 1. Это идеальный вариант для оптимизации транзакций только для чтения в MySQL 5.6, поскольку все SELECTзапросы в AUTOCOMMITрежиме по определению являются транзакциями только для чтения, поэтому сервер создает пустой список транзакций при создании представлений для чтения. Однако более общая оптимизация дескрипторов в Percona Server показала довольно близкие результаты в наших тестах. В тестах Димитри масштабируемость Percona Server находится где-то между MySQL 5.5 и MySQL 5.6.

Чтобы лучше понять различия между результатами, мы повторно запустили тесты на нескольких наших боксах. Вы можете найти подробности настройки / конфигурации в самом конце этого поста.

Оборудование:

Все они представляют собой блоки NUMA, но второй имеет более высокую пропускную способность QPI, а третий обладает еще более высокой скоростью QPI (и, следовательно, более быстрой связью между процессами / узлами).

Полученные результаты:

Прежде всего, мы использовали меньший набор данных для этого раунда тестов, поскольку, как сообщается, Дмитрий использовал 8 таблиц с 1М строк в каждой (около 2,1 ГБ) для своих тестов, в то время как в наших первоначальных тестах мы использовали гораздо большую таблицу, 16 таблиц с 5М Строки каждая (около 23 ГБ). Поэтому имеет смысл проверить, имеет ли значение размер набора данных.

Сначала мы исключили NUMA из уравнения. Мы провели тесты на коробке Dell PowerEdge R720 и различных комбинациях процессоров с набором задач. На следующей диаграмме показано сравнение результатов в конфигурации с одним узлом (слева) и с двумя узлами (справа).

point_select.socket0.16vcpu.vs.socket0.8.socket1.8

Здесь нет ничего удивительного, общая схема согласуется с тем, что мы видели ранее. Обратите внимание, что в конфигурации с одним узлом использовалось 16 потоков (8 ядер на одном сокете x 2 потока на сокет), а во втором — 16 ядер (8 ядер на сокет на узел). Таким образом, этот тест также исключает HT как виновника различия результатов.

Затем мы сравнили результаты по всем 3 блокам, чтобы увидеть, оказывает ли различное оборудование заметное влияние:

point_select_8t1M_hppro2_cisco1_ct720

Все еще не повезло, все соответствует другим тестам. Есть небольшие различия, например, в первых двух случаях производительность Percona Server даже немного опережает MySQL 5.6.10, но ничего неожиданного.

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

Несмотря на то, что оптимизация транзакций только для чтения в MySQL 5.6 практически исключает конфликты на мьютексе, защищающие список транзакций, ее применимость весьма ограничена. А именно, он требует, чтобы список транзакций был либо пустым, либо очень коротким, что в основном подразумевает полностью доступный только для чтения сервер. Как только количество обновлений в базе данных становится нетривиальным, все SELECTзапросы, даже те, которые участвуют в транзакциях только для чтения, начинают страдать от издержек trx_list, создаваемых одновременными обновлениями.

Как только мы отойдем от этой сферической коровы только для чтения и добавим некоторые обновления данных, ограничение транзакций только для чтения станет очевидным.

В следующем тесте sysbench выполняет 9 первичных ключей, SELECTза которыми следует UPDATEинструкция PK в каждом потоке в цикле, что, вероятно, немного ближе к реальной рабочей нагрузке. Это все еще AUTOCOMMITрежим, поэтому SELECTs — это транзакции только для чтения, но это мало помогает, потому что, например, для 1024 одновременных потоков каждый SELECTдолжен сканировать около 100 транзакций обновления, чтобы создать представление для чтения:

point_select1_vs_point_select9_update_pk1

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

Конфигурация сервера:

[mysqld]
user=root
port=3306
innodb_status_file=0
innodb_data_file_path=ibdata1:100M:autoextend
innodb_flush_log_at_trx_commit = 2
innodb_flush_method = O_DIRECT
innodb_log_buffer_size = 16M
innodb_buffer_pool_size = 52G
innodb_log_file_size = 2000M
innodb_log_files_in_group = 2
innodb_file_per_table = true
innodb_read_io_threads = 8
innodb_write_io_threads = 8
innodb_io_capacity = 2000
max_connections=5000
table_open_cache=5000
query_cache_type=OFF
performance_schema=0

разогреть

Для прогрева сервера и загрузки данных и индексов в буферный пул мы используем следующие запросы:

select avg(id) from sbtest$i force key (primary)
select count(*) from sbtest$i WHERE  k like '%0%'

SysBench-0,5 / Lua:

POINT_SELECT QPS тест

sysbench  --num-threads=<1..1024> --test=oltp.lua --oltp_tables_count=8 --oltp-table-size=1000000
--rand-init=on --report-interval=1 --rand-type=uniform --forced-shutdown=1 --max-time=120
--max-requests=0 --percentile=99 --mysql-user=root --mysql-db=sbtest8t1M
--mysql-table-engine=INNODB --mysql-socket=/tmp/mysql.sock
--oltp-point-selects=1 --oltp-simple-ranges=0 --oltp-sum-ranges=0 --oltp-order-ranges=0
--oltp-distinct-ranges=0 --oltp-skip-trx=on --oltp-test-mode=nontrx --oltp-read-only=off --oltp-index-updates=0 --oltp-non-index-updates=0 run

POINT_SELECT + UPDATE QPS test

sysbench  --num-threads=<1..1024> --test=oltp.lua --oltp_tables_count=8 --oltp-table-size=1000000
--rand-init=on --report-interval=1 --rand-type=uniform --forced-shutdown=1 --max-time=120
--max-requests=0 --percentile=99 --mysql-user=root --mysql-db=sbtest8t1M
--mysql-table-engine=INNODB --mysql-socket=/tmp/mysql.sock
--oltp-point-selects=9 --oltp-simple-ranges=0 --oltp-sum-ranges=0 --oltp-order-ranges=0
--oltp-distinct-ranges=0 --oltp-skip-trx=on --oltp-test-mode=nontrx --oltp-read-only=off --oltp-index-updates=1 --oltp-non-index-updates=0 run