Problem
Eine Instanz von MySQL 5.6.20, die (meistens nur) eine Datenbank mit InnoDB-Tabellen ausführt, zeigt gelegentliche Verzögerungen für alle Aktualisierungsvorgänge für die Dauer von 1 bis 4 Minuten an, wobei alle INSERT-, UPDATE- und DELETE-Abfragen im Status "Abfrageende" verbleiben. Das ist natürlich sehr unglücklich. Das langsame MySQL-Abfrageprotokoll protokolliert selbst die trivialsten Abfragen mit wahnsinnigen Abfragezeiten, von denen Hunderte den gleichen Zeitstempel haben, der dem Zeitpunkt entspricht, zu dem der Stillstand behoben wurde:
# 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');
Die Gerätestatistiken werden erhöht angezeigt, obwohl in diesem Zeitraum keine übermäßige E / A-Belastung aufgetreten ist (in diesem Fall wurden die Aktualisierungen gemäß den Zeitstempeln aus der obigen Anweisung zwischen 14:17:30 und 14:19:12 blockiert):
# 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
In den meisten Fällen stelle ich im langsamen mysql-Protokoll fest, dass die älteste Abfrage ein INSERT in eine große Tabelle (~ 10 M Zeilen) mit einem VARCHAR-Primärschlüssel und einem Volltextsuchindex ist:
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
Weitere Untersuchungen (zB SHOW ENGINE INNODB STATUS) haben gezeigt, dass es sich in der Tat immer um eine Aktualisierung einer Tabelle unter Verwendung von Volltextindizes handelt, die den Stillstand verursacht. Der entsprechende TRANSACTIONS-Abschnitt von "SHOW ENGINE INNODB STATUS" enthält Einträge wie diese beiden für die ältesten ausgeführten Transaktionen:
---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
Es wird also eine schwere Volltextindex-Aktion ausgeführt ( doing SYNC index
) , mit der ALLE FOLGENDEN Aktualisierungen für JEDE Tabelle gestoppt werden.
Aus den Protokollen geht hervor, dass die undo log entries
Zahl doing SYNC index
bei ~ 150 / s voranschreitet, bis sie 20.000 erreicht. Zu diesem Zeitpunkt ist der Vorgang abgeschlossen.
Die FTS-Größe dieser Tabelle ist beeindruckend:
# 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
Obwohl das Problem auch von Tabellen mit einer wesentlich geringeren FTS-Datengröße wie der folgenden ausgelöst wird:
# 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
Auch in diesen Fällen ist die Standzeit in etwa gleich. Ich habe einen Bug auf bugs.mysql.com geöffnet, damit die Entwickler sich darum kümmern können.
Die Art der Stalls hat mich zunächst verdächtigt, dass das Löschen von Protokollen der Schuldige ist. In diesem Percona-Artikel zu Problemen mit der Leistung beim Löschen von Protokollen in MySQL 5.5 werden sehr ähnliche Symptome beschrieben sind ebenfalls vom Stall betroffen, daher scheint dies kein reines InnoDB-Problem zu sein.
Trotzdem habe ich beschlossen, alle 10 Sekunden die Werte der Log sequence number
und Pages flushed up to
von den Ausgaben des Abschnitts "LOG" zu verfolgen SHOW ENGINE INNODB STATUS
. Es sieht tatsächlich so aus, als ob während des Stalls eine Spülaktivität stattfindet, da die Spreizung zwischen den beiden Werten abnimmt:
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
Und um 14:19:11 hat der Spread sein Minimum erreicht, so dass die Spülaktivität hier aufgehört zu haben scheint und nur mit dem Ende des Stalls zusammenfällt. Aufgrund dieser Punkte habe ich das Leeren des InnoDB-Protokolls als Ursache verworfen:
- Damit der Löschvorgang alle Aktualisierungen der Datenbank blockiert, muss er "synchron" sein, dh, 7/8 des Protokollspeicherplatzes müssen belegt sein
- es würde eine "asynchrone" Spülphase ab
innodb_max_dirty_pages_pct
Füllstand vorausgehen - was ich nicht sehe - Die LSNs steigen auch während des Stalls weiter an, sodass die Protokollaktivität nicht vollständig aufhört
- Auch die INSERTs der MyISAM-Tabelle sind betroffen
- Der page_cleaner-Thread für das adaptive Leeren scheint seine Arbeit zu erledigen und die Protokolle zu leeren, ohne dass DML-Abfragen beendet werden:
(Zahlen sind ([Log Sequence Number] - [Pages flushed up to]) / 1024
von SHOW ENGINE INNODB STATUS
)
Das Problem scheint durch das Einstellen etwas gelindert zu werden innodb_adaptive_flushing_lwm=1
, wodurch die Bereinigung der Seite gezwungen wird, mehr Arbeit als zuvor zu leisten.
Der error.log
hat keine Einträge, die mit den Ständen übereinstimmen. SHOW INNODB STATUS
Auszüge nach ca. 24 Betriebsstunden sehen so aus:
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
Ja, die Datenbank hat Deadlocks, aber sie sind sehr selten (das "Neueste" wurde ungefähr 11 Stunden vor dem Lesen der Statistiken behandelt).
Ich habe versucht, die Werte des Abschnitts "SEMAPHORES" über einen bestimmten Zeitraum zu verfolgen, insbesondere in einer normalen Betriebssituation und während eines Stillstands (ich habe ein kleines Skript geschrieben, das die Prozessliste des MySQL-Servers überprüft und für den Fall einige Diagnosebefehle in eine Protokollausgabe eingibt von einem offensichtlichen Stall). Da die Zahlen über verschiedene Zeiträume hinweg aufgenommen wurden, habe ich die Ergebnisse auf Ereignisse / Sekunde normalisiert:
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
Ich bin mir nicht ganz sicher, was ich hier sehe. Die meisten Zahlen sind um eine Größenordnung gesunken - wahrscheinlich aufgrund eingestellter Aktualisierungsvorgänge, "Mutex Spin Waits" und "Mutex Spin Rounds" haben sich jedoch beide um den Faktor 4 erhöht.
Um dies weiter zu untersuchen, enthält die Liste von mutexes ( SHOW ENGINE INNODB MUTEX
) ~ 480 mutex-Einträge, die sowohl im normalen Betrieb als auch während eines Stillstands aufgelistet sind. Ich habe aktiviert, um innodb_status_output_locks
zu sehen, ob es mir mehr Details geben wird.
Konfigurationsvariablen
(Ich habe mit den meisten von ihnen ohne bestimmten Erfolg gebastelt):
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 |
+-----------------------+-------+
Sachen schon ausprobiert
- Deaktivieren des Abfragecaches durch
SET GLOBAL query_cache_size=0
- Erhöhung
innodb_log_buffer_size
auf 128M - das Spiel mit
innodb_adaptive_flushing
,innodb_max_dirty_pages_pct
und die jeweiligen_lwm
Werte (sie auf die Standardwerte gesetzt wurden , um meine Änderungen vor) - ansteigend
innodb_io_capacity
(2000) undinnodb_io_capacity_max
(4000) - Rahmen
innodb_flush_log_at_trx_commit = 2
- Laufen mit innodb_flush_method = O_DIRECT (ja, wir verwenden ein SAN mit einem persistenten Schreibcache)
- Setzen Sie den / sys / block / sda / queue / scheduler auf
noop
oderdeadline
Antworten:
Das gleiche Problem trat auf zwei Servern in den Versionen 5.6.12 und 5.6.16 auf, die unter Windows mit jeweils zwei Slaves ausgeführt wurden. Wir waren fast zwei Monate wie Sie ratlos.
Lösung :
Weitere Informationen zur Variablen finden Sie unter https://dev.mysql.com/doc/refman/5.6/de/replication-options-binary-log.html#sysvar_binlog_order_commits .
Erklärung :
InnoDB-Volltext verwendet einen Cache (standardmäßig 8 MB groß), der Änderungen enthält, die auf den tatsächlichen Volltextindex auf der Festplatte angewendet werden müssen.
Sobald der Cache voll ist, werden einige Transaktionen erstellt, mit denen die im Cache enthaltenen Daten zusammengeführt werden. Dies ist in der Regel eine große Menge an zufälligen E / A-Vorgängen, es sei denn, der gesamte Volltextindex kann in den Cache geladen werden Der Pufferpool ist eine lange und langsame Transaktion.
Wenn binlog_order_commits auf true gesetzt ist, müssen alle Transaktionen mit Einfügungen und Aktualisierungen, die nach der lang laufenden Transaktion fts_sync_index gestartet wurden, warten, bis sie abgeschlossen sind, bevor sie festgeschrieben werden können.
Dies ist nur dann ein Problem, wenn die binäre Protokollierung aktiviert ist
quelle
Lassen Sie mich vielleicht versuchen, das historische Problem beim Löschen von Protokollen und die Funktionsweise des adaptiven Löschens zu beschreiben:
Die Redo-Logs sind ringgepuffert . Sie werden immer nur geschrieben (im normalen Betrieb niemals gelesen) und sorgen für eine Wiederherstellung nach einem Absturz. Ich beschreibe einen Ringpuffer gerne als ähnlich wie die Lauffläche eines Panzers.
InnoDB kann den Protokolldateibereich nicht überschreiben, wenn er Änderungen enthält, die noch nicht auf der Festplatte geändert wurden. Historisch gesehen würde es passieren, dass InnoDB eine bestimmte Menge an Arbeit pro Sekunde versucht (konfiguriert von
innodb_io_capacity
), und wenn dies nicht ausreicht, würden Sie den vollen Protokollspeicher erreichen. Ein Stillstand würde eintreten, wenn eine synchrone Spülung stattfinden müsste, um plötzlich Speicherplatz freizugeben, was normalerweise eine Hintergrundaufgabe ist, die plötzlich in den Vordergrund tritt.Um dieses Problem zu beheben, wurde die adaptive Spülung eingeführt. Wenn 10% (Standard) des Protokollspeicherplatzes belegt sind, wird die Hintergrundarbeit zunehmend aggressiver. Das Ziel ist eher ein plötzlicher Stillstand als ein kurzer Leistungsabfall.
Unabhängig von adaptiver Spülung ist es wichtig , genügend Protokollspeicherbereich für Ihre Arbeit zu haben (
innodb_log_file_size
Werte von 4G sind jetzt ganz sicher), und stellen Sie sicher , dassinnodb_io_capacity
undinnodb_lru_scan_depth
sind auf realistische Werte gesetzt. Die adaptive Spülung von 10%innodb_adaptive_flushing_lwm
ist etwas, in das man sich nicht sehr weit hinein streckt, sondern eher ein Abwehrmechanismus gegen zu wenig Platz.quelle
Nur um InnoDB ein wenig von Konflikten zu entlasten, könnten Sie damit spielen
innodb_purge_threads
.Vor MySQL 5.6 hat der Master-Thread alle Seiten geleert. In MySQL 5.6 kann ein separater Thread damit umgehen. Der Standardwert für
innodb_purge_threads
in MySQL 5.5 war 0 mit einem Maximum von 1. In MySQL 5.6 ist der Standardwert 1 mit einem Maximum von 32.Was macht
innodb_purge_threads
eigentlich die Einstellung ?Ich würde damit beginnen, innodb_purge_threads auf 4 zu setzen und zu prüfen , ob das Leeren der InnoDB-Seite reduziert ist.
UPDATE 2014-09-02 12:33 EDT
Morgan Tocker wies in dem folgenden Kommentar darauf hin, dass der Page Cleaner das Opfer ist und MySQL 5.7 darauf reagieren kann . Ungeachtet dessen ist Ihre Situation in MySQL 5.6.
Ich habe einen zweiten Blick darauf geworfen und festgestellt, dass Sie innodb_max_dirty_pages_pct bei 50 haben.
Der Standardwert für innodb_max_dirty_pages_pct in MySQL 5.5+ ist 75. Wenn Sie diesen Wert verringern, kommt es häufiger zu Verzögerungen beim Leeren. Ich würde drei (3) Dinge tun
my.cnf
UPDATE 03.09.2014 11:06 EDT
Möglicherweise müssen Sie Ihr Spülverhalten ändern
Stellen Sie Folgendes dynamisch ein
Diese Variablen werden gelöscht und flush_time , machen das Löschen aggressiver, indem alle 10 Sekunden geöffnete Datei-Handles für Tabellen geschlossen werden. MyISAM kann definitiv davon profitieren, da es keine Daten zwischenspeichert. Alle Schreibvorgänge in MyISAM-Tabellen erfordern vollständige Tabellensperren, gefolgt von atomaren Schreibvorgängen, und hängen für Festplattenänderungen vom Betriebssystem ab.
Das Löschen von InnoDB auf diese Weise würde einen Neustart von mysql erfordern. Die anzuzeigenden Optionen sind innodb_flush_log_at_trx_commit und innodb_flush_method .
Fügen Sie diese vor dem Neustart hinzu
Bevor Sie diese Route wählen, sollten Sie prüfen, ob Journaling ein Problem darstellt. Ich habe es gesehen coole mysqlperformance-Blog-Post auf O_DIRECT wegen des Kernels gefälscht wurde. In demselben Beitrag wird auch erwähnt, dass MyISAM betroffen ist.
Ich habe über diesen Beitrag schon einmal geschrieben: ib_logfile wurde mit O_SYNC geöffnet, wenn innodb_flush_method = O_DSYNC
Versuche es !!!
quelle
sar -d
Ausgabe aufgefallen ist,await
ist, dass sie sich während eines Stalls fast verzehnfacht, während der Durchsatz sinkt. Halten Sie es für wahrscheinlich, dass es hier Probleme außerhalb von MySQL gibt, zum Beispiel mit dem I / O-Scheduler oder dem Journaling des Dateisystems?SHOW GLOBAL VARIABLES LIKE '%io_threads';