Проблема
Екземпляр MySQL 5.6.20, що працює (здебільшого просто) бази даних із таблицями InnoDB, демонструє періодичні зупинки для всіх операцій оновлення тривалістю 1-4 хвилини, при цьому всі запити INSERT, UPDATE та DELETE залишаються у стані "Запит запиту". Це, очевидно, найбільш прикро. Журнал повільних запитів MySQL реєструє навіть найтривітніші запити з божевільним часом запитів, сотні з них з тією ж міткою часу, що відповідає моменту часу, коли стійло було вирішено:
# Query_time: 101.743589 Lock_time: 0.000437 Rows_sent: 0 Rows_examined: 0
SET timestamp=1409573952;
INSERT INTO sessions (redirect_login2, data, hostname, fk_users_primary, fk_users, id_sessions, timestamp) VALUES (NULL, NULL, '192.168.10.151', NULL, 'anonymous', '64ef367018099de4d4183ffa3bc0848a', '1409573850');
І статистика пристрою показує збільшене, хоча не надмірне навантаження вводу / виводу в цей часовий проміжок (у такому випадку оновлення затримувались 14:17:30 - 14:19:12 відповідно до часових позначок із заяви вище):
# sar -d
[...]
02:15:01 PM DEV tps rd_sec/s wr_sec/s avgrq-sz avgqu-sz await svctm %util
02:16:01 PM dev8-0 41.53 207.43 1227.51 34.55 0.34 8.28 3.89 16.15
02:17:01 PM dev8-0 59.41 137.71 2240.32 40.02 0.39 6.53 4.04 24.00
02:18:01 PM dev8-0 122.08 2816.99 1633.44 36.45 3.84 31.46 1.21 2.88
02:19:01 PM dev8-0 253.29 5559.84 3888.03 37.30 6.61 26.08 1.85 6.73
02:20:01 PM dev8-0 101.74 1391.92 2786.41 41.07 1.69 16.57 3.55 36.17
[...]
# sar
[...]
02:15:01 PM CPU %user %nice %system %iowait %steal %idle
02:16:01 PM all 15.99 0.00 12.49 2.08 0.00 69.44
02:17:01 PM all 13.67 0.00 9.45 3.15 0.00 73.73
02:18:01 PM all 10.64 0.00 6.26 11.65 0.00 71.45
02:19:01 PM all 3.83 0.00 2.42 24.84 0.00 68.91
02:20:01 PM all 20.95 0.00 15.14 6.83 0.00 57.07
Найчастіше я помічаю в журналі mysql повільний тест, що найдавніший зупинення запитів - ВСТАВКА в таблицю з великим результатом (~ 10 М рядків) з первинним ключем VARCHAR та повнотекстовим індексом пошуку:
CREATE TABLE `files` (
`id_files` varchar(32) NOT NULL DEFAULT '',
`filename` varchar(100) NOT NULL DEFAULT '',
`content` text,
PRIMARY KEY (`id_files`),
KEY `filename` (`filename`),
FULLTEXT KEY `content` (`content`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
Подальше дослідження (наприклад, ПОКАЖИТИ СТАТУТ ДВИГАТЕЛЯ) показало, що воно завжди є оновленням таблиці з використанням повнотекстових індексів, що спричиняє затримку. У відповідному розділі "ТРАНЗАКЦІЇ" "ПОКАЗУЙТЕ ДВИГАТЕЛЬНИЙ СТАТУТ ІННОДБА" такі записи, як ці дві для найстаріших запущених транзакцій:
---TRANSACTION 162269409, ACTIVE 122 sec doing SYNC index
6 lock struct(s), heap size 1184, 0 row lock(s), undo log entries 19942
TABLE LOCK table "vw"."FTS_000000000000224a_00000000000036b9_INDEX_1" trx id 162269409 lock mode IX
TABLE LOCK table "vw"."FTS_000000000000224a_00000000000036b9_INDEX_2" trx id 162269409 lock mode IX
TABLE LOCK table "vw"."FTS_000000000000224a_00000000000036b9_INDEX_3" trx id 162269409 lock mode IX
TABLE LOCK table "vw"."FTS_000000000000224a_00000000000036b9_INDEX_4" trx id 162269409 lock mode IX
TABLE LOCK table "vw"."FTS_000000000000224a_00000000000036b9_INDEX_5" trx id 162269409 lock mode IX
TABLE LOCK table "vw"."FTS_000000000000224a_00000000000036b9_INDEX_6" trx id 162269409 lock mode IX
---TRANSACTION 162269408, ACTIVE (PREPARED) 122 sec committing
mysql tables in use 1, locked 1
1 lock struct(s), heap size 360, 0 row lock(s), undo log entries 1
MySQL thread id 165998, OS thread handle 0x7fe0e239c700, query id 91208956 192.168.10.153 root query end
INSERT INTO files (id_files, filename, content) VALUES ('f19e63340fad44841580c0371bc51434', '1237716_File_70380a686effd6b66592bb5eeb3d9b06.doc', '[...]
TABLE LOCK table `vw`.`files` trx id 162269408 lock mode IX
Отже, там відбувається якась велика повна індексована дія ( doing SYNC index), яка зупиняє ВСІ ПІДТВОРЕННІ оновлення до будь-якої таблиці.
З журналів здається, що undo log entriesкількість для doing SYNC indexпросувається до ~ 150 / с, поки не досягне 20 000, після чого виконується операція.
Розмір FTS цієї конкретної таблиці дуже вражає:
# du -c FTS_000000000000224a_00000000000036b9_*
614404 FTS_000000000000224a_00000000000036b9_INDEX_1.ibd
2478084 FTS_000000000000224a_00000000000036b9_INDEX_2.ibd
1576964 FTS_000000000000224a_00000000000036b9_INDEX_3.ibd
1630212 FTS_000000000000224a_00000000000036b9_INDEX_4.ibd
1978372 FTS_000000000000224a_00000000000036b9_INDEX_5.ibd
1159172 FTS_000000000000224a_00000000000036b9_INDEX_6.ibd
9437208 total
хоча ця проблема також викликана таблицями зі значно меншими розмірами даних FTS, як ця:
# du -c FTS_0000000000002467_0000000000003a21_INDEX*
49156 FTS_0000000000002467_0000000000003a21_INDEX_1.ibd
225284 FTS_0000000000002467_0000000000003a21_INDEX_2.ibd
147460 FTS_0000000000002467_0000000000003a21_INDEX_3.ibd
135172 FTS_0000000000002467_0000000000003a21_INDEX_4.ibd
155652 FTS_0000000000002467_0000000000003a21_INDEX_5.ibd
106500 FTS_0000000000002467_0000000000003a21_INDEX_6.ibd
819224 total
Час стійла в цих випадках приблизно однаковий. Я відкрив помилку на bugs.mysql.com, щоб розробники могли вивчити це.
Характер стійлів вперше змусив мене підозрювати, що виникла діяльність з вимивання журналу, і ця стаття Percona щодо питань продуктивності промивання журналу з MySQL 5.5 описує дуже схожі симптоми, але подальші випадки показали, що INSERT працює в єдиній таблиці MyISAM в цій базі даних впливає і стійла, тому це не здається проблемою, що стосується лише InnoDB.
Тим не менш, я вирішив відстежувати значення Log sequence numberта Pages flushed up toз виходів розділу "ЛОГ"SHOW ENGINE INNODB STATUS кожні 10 секунд. Це дійсно схоже на те, що активність промивання триває під час стійла, оскільки розкид між двома значеннями зменшується:
Mon Sep 1 14:17:08 CEST 2014 LSN: 263992263703, Pages flushed: 263973405075, Difference: 18416 K
Mon Sep 1 14:17:19 CEST 2014 LSN: 263992826715, Pages flushed: 263973811282, Difference: 18569 K
Mon Sep 1 14:17:29 CEST 2014 LSN: 263993160647, Pages flushed: 263974544320, Difference: 18180 K
Mon Sep 1 14:17:39 CEST 2014 LSN: 263993539171, Pages flushed: 263974784191, Difference: 18315 K
Mon Sep 1 14:17:49 CEST 2014 LSN: 263993785507, Pages flushed: 263975990474, Difference: 17377 K
Mon Sep 1 14:17:59 CEST 2014 LSN: 263994298172, Pages flushed: 263976855227, Difference: 17034 K
Mon Sep 1 14:18:09 CEST 2014 LSN: 263994670794, Pages flushed: 263978062309, Difference: 16219 K
Mon Sep 1 14:18:19 CEST 2014 LSN: 263995014722, Pages flushed: 263983319652, Difference: 11420 K
Mon Sep 1 14:18:30 CEST 2014 LSN: 263995404674, Pages flushed: 263986138726, Difference: 9048 K
Mon Sep 1 14:18:40 CEST 2014 LSN: 263995718244, Pages flushed: 263988558036, Difference: 6992 K
Mon Sep 1 14:18:50 CEST 2014 LSN: 263996129424, Pages flushed: 263988808179, Difference: 7149 K
Mon Sep 1 14:19:00 CEST 2014 LSN: 263996517064, Pages flushed: 263992009344, Difference: 4402 K
Mon Sep 1 14:19:11 CEST 2014 LSN: 263996979188, Pages flushed: 263993364509, Difference: 3529 K
Mon Sep 1 14:19:21 CEST 2014 LSN: 263998880477, Pages flushed: 263993558842, Difference: 5196 K
Mon Sep 1 14:19:31 CEST 2014 LSN: 264001013381, Pages flushed: 263993568285, Difference: 7270 K
Mon Sep 1 14:19:41 CEST 2014 LSN: 264001933489, Pages flushed: 263993578961, Difference: 8158 K
Mon Sep 1 14:19:51 CEST 2014 LSN: 264004225438, Pages flushed: 263993585459, Difference: 10390 K
А о 14:19:11 спред досяг свого мінімуму, тому, здається, промивна діяльність тут припинилася, просто збігаючись з кінцем стійла. Але ці моменти змусили мене відхилити промивання журналу InnoDB як причину:
- для операції очищення для блокування всіх оновлень бази даних вона повинна бути "синхронною", що означає, що 7/8 простору журналу має бути зайнято
- їй передуватиме "асинхронна" фаза промивання, що починається на
innodb_max_dirty_pages_pctрівні заливки - чого я не бачу - LSN постійно збільшуються навіть під час стійла, тому активність журналу не припиняється повністю
- Вражені також таблиці INISERT таблиці MyISAM
- Потік page_cleaner для адаптивного промивання, здається, виконує свою роботу та очищає журнали, не спричиняючи зупинки запитів DML:

(номери ([Log Sequence Number] - [Pages flushed up to]) / 1024від SHOW ENGINE INNODB STATUS)
Проблема здається дещо полегшеною, встановивши innodb_adaptive_flushing_lwm=1, примушуючи прибиральниць сторінки робити більше роботи, ніж раніше.
error.logНе має записів , які збігаються з прилавків. SHOW INNODB STATUSВитяги приблизно через 24 години роботи виглядають так:
SEMAPHORES
----------
OS WAIT ARRAY INFO: reservation count 789330
OS WAIT ARRAY INFO: signal count 1424848
Mutex spin waits 269678, rounds 3114657, OS waits 65965
RW-shared spins 941620, rounds 20437223, OS waits 442474
RW-excl spins 451007, rounds 13254440, OS waits 215151
Spin rounds per wait: 11.55 mutex, 21.70 RW-shared, 29.39 RW-excl
------------------------
LATEST DETECTED DEADLOCK
------------------------
2014-09-03 10:33:55 7fe0e2e44700
[...]
--------
FILE I/O
--------
[...]
932635 OS file reads, 2117126 OS file writes, 1193633 OS fsyncs
0.00 reads/s, 0 avg bytes/read, 17.00 writes/s, 1.20 fsyncs/s
--------------
ROW OPERATIONS
--------------
0 queries inside InnoDB, 0 queries in queue
0 read views open inside InnoDB
Main thread process no. 54745, id 140604272338688, state: sleeping
Number of rows inserted 528904, updated 1596758, deleted 99860, read 3325217158
5.40 inserts/s, 10.40 updates/s, 0.00 deletes/s, 122969.21 reads/s
Так, так, база даних має тупикові місця, але вони дуже рідкісні ("останні" оброблялися близько 11 годин до того, як статистика була прочитана).
Я спробував відстежувати значення розділу "SEMAPHORES" протягом певного періоду часу, особливо в умовах нормальної роботи та під час стійла (я написав невеликий сценарій, перевіряючи список процесорів сервера MySQL та виконуючи пару діагностичних команд у вихідний журнал у випадку, якщо очевидного стійла). Оскільки цифри були прийняті за різні часові рамки, я нормалізував результати подій / секунду:
normal stall
1h avg 1m avg
OS WAIT ARRAY INFO:
reservation count 5,74 1,00
signal count 24,43 3,17
Mutex spin waits 1,32 5,67
rounds 8,33 25,85
OS waits 0,16 0,43
RW-shared spins 9,52 0,76
rounds 140,73 13,39
OS waits 2,60 0,27
RW-excl spins 6,36 1,08
rounds 178,42 16,51
OS waits 2,38 0,20
Я не зовсім впевнений у тому, що я бачу тут. Більшість цифр зменшилася на порядок - можливо, через припинені операції оновлення, "Mutex спіна чекає" і "Mutex спінових раундів", однак вони збільшилися в 4 рази.
Досліджуючи це далі, список mutexes ( SHOW ENGINE INNODB MUTEX) містить ~ 480 записів мютексу, перелічених як у звичайній роботі, так і під час стійла. Я дав innodb_status_output_locksзмогу побачити, чи не дасть це мені детальніше.
Змінні конфігурації
(Я працював у більшості з них без певного успіху):
mysql> show global variables where variable_name like 'innodb_adaptive_flush%';
+------------------------------+-------+
| Variable_name | Value |
+------------------------------+-------+
| innodb_adaptive_flushing | ON |
| innodb_adaptive_flushing_lwm | 1 |
+------------------------------+-------+
mysql> show global variables where variable_name like 'innodb_max_dirty_pages_pct%';
+--------------------------------+-------+
| Variable_name | Value |
+--------------------------------+-------+
| innodb_max_dirty_pages_pct | 50 |
| innodb_max_dirty_pages_pct_lwm | 10 |
+--------------------------------+-------+
mysql> show global variables where variable_name like 'innodb_log_%';
+-----------------------------+-----------+
| Variable_name | Value |
+-----------------------------+-----------+
| innodb_log_buffer_size | 8388608 |
| innodb_log_compressed_pages | ON |
| innodb_log_file_size | 268435456 |
| innodb_log_files_in_group | 2 |
| innodb_log_group_home_dir | ./ |
+-----------------------------+-----------+
mysql> show global variables where variable_name like 'innodb_double%';
+--------------------+-------+
| Variable_name | Value |
+--------------------+-------+
| innodb_doublewrite | ON |
+--------------------+-------+
mysql> show global variables where variable_name like 'innodb_buffer_pool%';
+-------------------------------------+----------------+
| Variable_name | Value |
+-------------------------------------+----------------+
| innodb_buffer_pool_dump_at_shutdown | OFF |
| innodb_buffer_pool_dump_now | OFF |
| innodb_buffer_pool_filename | ib_buffer_pool |
| innodb_buffer_pool_instances | 8 |
| innodb_buffer_pool_load_abort | OFF |
| innodb_buffer_pool_load_at_startup | OFF |
| innodb_buffer_pool_load_now | OFF |
| innodb_buffer_pool_size | 29360128000 |
+-------------------------------------+----------------+
mysql> show global variables where variable_name like 'innodb_io_capacity%';
+------------------------+-------+
| Variable_name | Value |
+------------------------+-------+
| innodb_io_capacity | 200 |
| innodb_io_capacity_max | 2000 |
+------------------------+-------+
mysql> show global variables where variable_name like 'innodb_lru_scan_depth%';
+-----------------------+-------+
| Variable_name | Value |
+-----------------------+-------+
| innodb_lru_scan_depth | 1024 |
+-----------------------+-------+
Речі вже спробували
- відключення кешу запитів на
SET GLOBAL query_cache_size=0 - зростаючи
innodb_log_buffer_sizeдо 128М - граючи з
innodb_adaptive_flushing,innodb_max_dirty_pages_pctі відповідними_lwmзначеннями (вони були встановлені по замовчуванням до моїх змін) - зростаючий
innodb_io_capacity(2000) таinnodb_io_capacity_max(4000) - налаштування
innodb_flush_log_at_trx_commit = 2 - працює з innodb_flush_method = O_DIRECT (так, ми використовуємо SAN з стійким кешем запису)
- встановлення / sys / block / sda / queue / планувальника на
noopабоdeadline