Vấn đề
Một phiên bản của MySQL 5.6.20 đang chạy (hầu hết chỉ là) một cơ sở dữ liệu với các bảng InnoDB đang hiển thị các quầy hàng thỉnh thoảng cho tất cả các hoạt động cập nhật trong thời gian 1-4 phút với tất cả các truy vấn INSERT, UPDATE và DELETE còn lại trong trạng thái "Kết thúc truy vấn". Điều này rõ ràng là đáng tiếc nhất. Nhật ký truy vấn chậm của MySQL đang ghi nhật ký ngay cả những truy vấn tầm thường nhất với thời gian truy vấn điên rồ, hàng trăm trong số chúng có cùng dấu thời gian tương ứng với thời điểm mà gian hàng đã được giải quyết:
# 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');
Và số liệu thống kê thiết bị đang hiển thị tăng, mặc dù không tải I / O quá mức trong khung thời gian này (trong trường hợp này các bản cập nhật bị đình trệ 14:17:30 - 14:19:12 theo dấu thời gian từ tuyên bố trên):
# 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
Thường xuyên hơn không, tôi nhận thấy trong nhật ký chậm mysql rằng truy vấn cũ nhất bị trì hoãn là một INSERT vào bảng lớn (~ 10 M hàng) với khóa chính VARCHAR và chỉ mục tìm kiếm toàn văn bản:
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
Nghiên cứu sâu hơn (ví dụ TÌNH TRẠNG SHOW Engine INNODB) đã chỉ ra rằng nó thực sự luôn là một bản cập nhật cho một bảng sử dụng các chỉ mục toàn văn bản gây ra gian hàng. Phần GIAO DỊCH tương ứng của "SHOW Engine INNODB STATUS" có các mục giống như hai mục này cho các giao dịch đang chạy lâu nhất:
---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
Vì vậy, có một số hành động chỉ mục văn bản đầy đủ nặng nề đang diễn ra ở đó ( doing SYNC index
) dừng TẤT CẢ các cập nhật SUBSEQUENT để BẤT CỨ bảng nào.
Từ nhật ký có vẻ hơi giống undo log entries
số doing SYNC index
đang tăng lên ~ 150 / s cho đến khi đạt 20.000, tại thời điểm đó, thao tác được thực hiện.
Kích thước FTS của bảng cụ thể này khá ấn tượng:
# 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
mặc dù vấn đề cũng được kích hoạt bởi các bảng có kích thước dữ liệu FTS nhỏ hơn đáng kể như thế này:
# 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
Thời gian của gian hàng trong những trường hợp đó là gần như nhau, quá. Tôi đã mở một lỗi trên bug.mysql.com để các nhà phát triển có thể xem xét điều này.
Bản chất của các quầy hàng đầu tiên khiến tôi nghi ngờ hoạt động xả gỗ là thủ phạm và bài báo Percona này về các vấn đề về hiệu suất xả nhật ký với MySQL 5.5 đang mô tả các triệu chứng rất giống nhau, nhưng các lần xuất hiện tiếp theo cho thấy các hoạt động của INSERT vào bảng MyISAM duy nhất trong cơ sở dữ liệu này cũng bị ảnh hưởng bởi gian hàng, vì vậy đây dường như không phải là vấn đề chỉ của InnoDB.
Tuy nhiên, tôi quyết định theo dõi các giá trị của Log sequence number
và Pages flushed up to
từ đầu ra của phần "LOG" trong SHOW ENGINE INNODB STATUS
mỗi 10 giây. Thực sự có vẻ như hoạt động xả nước đang diễn ra trong gian hàng khi sự lây lan giữa hai giá trị đang giảm:
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
Và vào lúc 14:19:11 sự lây lan đã đạt đến mức tối thiểu, vì vậy hoạt động xả nước dường như đã chấm dứt ở đây, chỉ trùng với sự kết thúc của gian hàng. Nhưng những điểm này khiến tôi loại bỏ nhật ký InnoDB là nguyên nhân:
- đối với hoạt động xả để chặn tất cả các cập nhật vào cơ sở dữ liệu, nó cần phải "đồng bộ", điều đó có nghĩa là phải chiếm 7/8 không gian nhật ký
- nó sẽ được bắt đầu bằng một giai đoạn xả "không đồng bộ" bắt đầu từ
innodb_max_dirty_pages_pct
lấp đầy - mà tôi không thấy - LSN tiếp tục tăng ngay cả trong gian hàng, vì vậy hoạt động đăng nhập không ngừng hoàn toàn
- CHỨNG CHỈ bảng MyISAM cũng bị ảnh hưởng
- luồng page_cleaner để xóa thích ứng dường như thực hiện công việc của nó và xóa nhật ký mà không khiến các truy vấn DML dừng lại:
(số là ([Log Sequence Number] - [Pages flushed up to]) / 1024
từ SHOW ENGINE INNODB STATUS
)
Vấn đề có vẻ giảm bớt bằng cách thiết lập innodb_adaptive_flushing_lwm=1
, buộc trình dọn dẹp trang phải thực hiện nhiều công việc hơn trước.
Không error.log
có mục trùng với các quầy hàng. SHOW INNODB STATUS
đoạn trích sau khoảng 24 giờ hoạt động trông như thế này:
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
Vì vậy, vâng, cơ sở dữ liệu có những bế tắc, nhưng chúng rất không thường xuyên ("mới nhất" đã được xử lý khoảng 11 giờ trước khi số liệu thống kê được đọc).
Tôi đã thử theo dõi các giá trị phần "SEMAPHORES" trong một khoảng thời gian, đặc biệt là trong tình huống hoạt động bình thường và trong một gian hàng (Tôi đã viết một đoạn mã nhỏ kiểm tra danh sách quy trình của máy chủ MySQL và chạy một vài lệnh chẩn đoán vào đầu ra nhật ký trong trường hợp của một gian hàng rõ ràng). Vì các số đã được lấy trong các khung thời gian khác nhau, tôi đã chuẩn hóa kết quả thành các sự kiện / giây:
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
Tôi không chắc chắn về những gì tôi đang thấy ở đây. Hầu hết các con số đã giảm theo một mức độ lớn - có thể là do các hoạt động cập nhật đã ngừng, "Mutex spin chờ đợi" và "Vòng quay Mutex" tuy nhiên đều tăng theo hệ số 4.
Điều tra thêm về điều này, danh sách các mutexes ( SHOW ENGINE INNODB MUTEX
) có ~ 480 mục mutex được liệt kê cả trong hoạt động bình thường cũng như trong một gian hàng. Tôi đã kích hoạt innodb_status_output_locks
để xem nếu nó sẽ cung cấp cho tôi chi tiết hơn.
Biến cấu hình
(Tôi đã mày mò với hầu hết trong số họ mà không thành công nhất định):
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 |
+-----------------------+-------+
Những điều đã cố gắng
- vô hiệu hóa bộ đệm truy vấn bằng cách
SET GLOBAL query_cache_size=0
- tăng
innodb_log_buffer_size
lên 128M - chơi đùa với
innodb_adaptive_flushing
,innodb_max_dirty_pages_pct
và tương ứng_lwm
giá trị (họ đã được thiết lập mặc định trước khi thay đổi của tôi) - tăng
innodb_io_capacity
(2000) vàinnodb_io_capacity_max
(4000) - cài đặt
innodb_flush_log_at_trx_commit = 2
- chạy với innodb_flush_method = O_DIRECT (vâng, chúng tôi sử dụng SAN với bộ đệm ghi liên tục)
- đặt / sys / block / sda / queue / calendaruler thành
noop
hoặcdeadline