Sorun
InnoDB tabloları olan bir veritabanını (çoğunlukla sadece) çalıştıran bir MySQL 5.6.20 örneği, "Sorgu sonu" durumunda kalan tüm INSERT, UPDATE ve DELETE sorguları ile 1-4 dakika boyunca tüm güncelleme işlemleri için ara sıra tezgahlar sergiliyor. Bu en talihsiz bir durum. MySQL yavaş sorgu günlüğü, en önemsiz sorguları bile çılgın sorgu süreleri ile günlüğe kaydediyor, yüzlerce, duraklamanın çözüldüğü zamana karşılık gelen aynı zaman damgasına sahip:
# 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');
Ve bu zaman çerçevesinde aşırı G / Ç yükü olmamasına rağmen cihaz istatistikleri arttı (bu durumda güncellemeler yukarıdaki ifadeden zaman damgalarına göre 14:17:30 - 14:19:12 duruyordu):
# 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
Daha sık değil, mysql yavaş günlük en eski sorgu stalling bir VARCHAR birincil anahtar ve tam metin arama dizini ile bir büyük ish (~ 10 M satır) tablo içine bir INSERT olduğunu fark:
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
Daha fazla araştırma (örn. MOTOR INNODB DURUMUNU GÖSTER), gerçekten her zaman duraklamaya neden olan tam metin dizinleri kullanan bir tablo için bir güncelleme olduğunu göstermiştir. "MOTOR INNODB DURUMUNU GÖSTER" in ilgili İŞLEMLER bölümünde, en eski çalışan işlemler için aşağıdaki gibi girişler bulunur:
---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
Bu nedenle , HERHANGİ BİR tablodaki TÜM SONRAKİ güncellemeleri durduran bazı ağır tam metin dizini eylemi var ( doing SYNC index
) .
Günlüklerden, undo log entries
sayı doing SYNC index
20.000'e ulaşana kadar ~ 150 / s'de ilerliyor gibi görünüyor , bu noktada işlem yapılır.
Bu özel tablonun FTS boyutu oldukça etkileyici:
# 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
Her ne kadar bu sorun, bunun gibi önemli ölçüde daha az büyük FTS veri boyutuna sahip tablolar tarafından da tetiklense de:
# 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
Bu durumlarda duraklama süresi de kabaca aynıdır. Devs bu içine bakmak böylece bugs.mysql.com bir hata açtım .
Tezgahların doğası bana ilk olarak log sifonlama aktivitesinin suçlu olmasını şüpheledi ve MySQL 5.5 ile log sifonu performans sorunları hakkındaki bu Percona makalesi çok benzer semptomları açıklıyor, ancak daha fazla olay, INSERT işlemlerinin bu veritabanındaki tek MyISAM tablosuna eklendiğini gösterdi. duraktan da etkileniyor, bu yüzden bu sadece InnoDB sorunu gibi görünmüyor.
Yine de, ben değerlerini takip etme kararı Log sequence number
ve Pages flushed up to
gelen "LOG" bölümünde çıkışları SHOW ENGINE INNODB STATUS
her 10 saniyede. Gerçekten, iki değer arasındaki yayılım azaldıkça, durma sırasında yıkama faaliyeti devam ediyor gibi görünüyor:
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
Ve 14:19:11'de spread minimum seviyeye ulaştı, bu yüzden durma aktivitesi burada durdu, sadece durakların sonuna denk geliyor. Ama bu puanlar neden InnoDB log sifonunu reddetti:
- yıkama işleminin veritabanındaki tüm güncelleştirmeleri engellemesi için "eşzamanlı" olması gerekir, yani günlük alanının 7 / 8'inin işgal edilmesi gerekir
- öncesinde
innodb_max_dirty_pages_pct
dolum seviyesinde başlayan bir "eşzamansız" yıkama aşaması olurdu - görmüyorum - duraklama sırasında bile LSN'ler artmaya devam eder, bu nedenle günlük etkinliği tamamen durmaz
- MyISAM tablosu INSERT'leri de etkilenir
- uyarlanabilir yıkama için page_cleaner iş parçacığı DML sorgularının durmasına neden olmadan işlerini yapıyor ve günlükleri yıkıyor gibi görünüyor:
(sayılardır ([Log Sequence Number] - [Pages flushed up to]) / 1024
gelen SHOW ENGINE INNODB STATUS
)
Sorun innodb_adaptive_flushing_lwm=1
, sayfa temizleyiciyi öncekinden daha fazla iş yapmaya zorlayarak ayarlanarak biraz azalmış gibi görünüyor .
error.log
Tezgahları rastlayan yazı bulunmamaktadır. SHOW INNODB STATUS
yaklaşık 24 saatlik çalışma sonrası alıntılar şöyle görünür:
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
Yani, evet, veritabanı kilitlenmeleri var, ama çok seyrek vardır ("son" istatistikleri okunmadan yaklaşık 11 saat önce ele alınmıştır).
"SEMAPHORES" bölüm değerlerini belirli bir süre boyunca, özellikle normal çalışma durumunda ve bir durak sırasında izlemeyi denedim (MySQL sunucusunun işlem listesini kontrol eden ve birkaç günlük tanılama komutunu çalıştıran küçük bir komut dosyası yazdım bariz bir durak). Sayılar farklı zaman dilimlerinde alındıkça, sonuçları olay / saniye olarak normalleştirdim:
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
Burada ne gördüğümden tam olarak emin değilim. Çoğu sayı büyüklük sırasına göre düşmüştür - büyük olasılıkla durdurulmuş güncelleme işlemlerinden dolayı, "Mutex spin bekler" ve "Mutex spin turları" her ikisi de 4 kat artmıştır.
Bunu daha da araştırarak, muteksler ( SHOW ENGINE INNODB MUTEX
) listesinde hem normal çalışma hem de bir durak sırasında listelenen ~ 480 muteks girişi vardır. Ben sağladı innodb_status_output_locks
bana daha fazla ayrıntı verecek olup olmadığını görmek için.
Konfigürasyon değişkenleri
(Kesin başarı olmadan çoğuyla uğraştım):
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 |
+-----------------------+-------+
İşler zaten denendi
- tarafından sorgu önbelleğini devre dışı bırakma
SET GLOBAL query_cache_size=0
innodb_log_buffer_size
128 milyona yükseliyor- uğraşırken
innodb_adaptive_flushing
,innodb_max_dirty_pages_pct
ve ilgili_lwm
değerleri (onlar varsayılan olarak ayarlanmış Değişikliklerime önce) - artan
innodb_io_capacity
(2000) veinnodb_io_capacity_max
(4000) - ayar
innodb_flush_log_at_trx_commit = 2
- innodb_flush_method = O_DIRECT ile çalışıyor (evet, kalıcı yazma önbelleğine sahip bir SAN kullanıyoruz)
- / sys / block / sda / kuyruk / zamanlayıcıyı
noop
veya olarak ayarlamadeadline