问题描述,今天发现一台db服务器,错误日志中有innodb 报错信息,具体如下:
space 1131 offset 1221565 (448 records, index id 2730)
206 InnoDB: Submit a detailed bug report to http://bugs.mysql.com
209 2015-01-27 14:47:03 30309 [Warning] 'proxies_priv' entry '@ root@cndb012.5405.zr.sh.gcimg.net
' ignored in --skip-name-resolve mode.
210 InnoDB: Warning: a long semaphore wait:
211 --Thread 139840252565248 has waited at row0upd.cc line 2391 for 241.00 seconds the semaphore:
212 X-lock (wait_ex) on RW-latch at 0x7f30e81ffec0 created in file buf0buf.cc line 994
213 a writer (thread id 139840252565248) has reserved it in mode wait exclusive
214 number of readers 1, waiters flag 0, lock_word: ffffffffffffffff
215 Last time read locked in file btr0sea.cc line 931
216 Last time write locked in file /root/mysql-5.6.10/storage/innobase/row/row0upd.cc line 2391
217 InnoDB: ###### Starts InnoDB Monitor for 30 secs to print diagnostic info:
218 InnoDB: Pending preads 1, pwrites 0
219
220 =====================================
221 2015-02-17 01:33:24 7f2f1c5cd700 INNODB MONITOR OUTPUT
222 =====================================
223 Per second averages calculated from the last 9 seconds
224 -----------------
225 BACKGROUND THREAD
226 -----------------
227 srv_master_thread loops: 9485924 srv_active, 0 srv_shutdown, 12079 srv_idle
228 srv_master_thread log flush and writes: 9498003
229 ----------
230 SEMAPHORES
231 ----------
232 OS WAIT ARRAY INFO: reservation count 20878957
233 --Thread 139840305547008 has waited at srv0srv.cc line 2642 for 0.00 seconds the semaphore:
234 X-lock (wait_ex) on RW-latch at 0x17dcce78 created in file trx0purge.cc line 128
235 a writer (thread id 139840305547008) has reserved it in mode wait exclusive
cndb012.5405.zr.sh.gcimg.net.err 227,1 11%
a writer (thread id 139840252565248) has reserved it in mode wait exclusive
242 number of readers 1, waiters flag 0, lock_word: ffffffffffffffff
243 Last time read locked in file btr0sea.cc line 931
244 Last time write locked in file /root/mysql-5.6.10/storage/innobase/row/row0upd.cc line 2391
245 OS WAIT ARRAY INFO: signal count 24461907
246 Mutex spin waits 46796216, rounds 120553500, OS waits 2922505
247 RW-shared spins 27488053, rounds 494141792, OS waits 11545932
248 RW-excl spins 6660716, rounds 158988739, OS waits 3758819
249 Spin rounds per wait: 2.58 mutex, 17.98 RW-shared, 23.87 RW-excl
250 ------------
251 TRANSACTIONS
252 ------------
253 Trx id counter 34084627765
254 Purge done for trx's n:o < 33966059091 undo n:o < 0 state: running but idle
255 History list length 58473189
256 LIST OF TRANSACTIONS FOR EACH SESSION:
257 ---TRANSACTION 34084627619, ACTIVE 207 sec
258 MySQL thread id 10667405, OS thread handle 0x7f2f164f6700, query id 6964941502 192.168.2.55 m
ha_user cleaning up
259 Trx read view will not see trx with id >= 34084627620, sees < 33966059089
260 ---TRANSACTION 34084627590, ACTIVE 243 sec
。。。。。。。。。。。。。。。。。截取部分日志,网上搜到姜老师写的文章,拿来
存储,学习,共享
前段时间遇到一个问题,DBA反映有台MySQL数据库非常诡异,在无任何操作的前提下,磁盘IO负载都几乎跑满。然后跑了3、4个小时磁盘负载依旧。DBA的初步判断认为是RAID卡出了问题(之前遇到过类似RAID卡BBU问题导致负载较高)。不过既然是数据库无任何操作,那么即使RAID卡出现问题,也不应该出现这个问题。因此在调查了问题现场后,询问了DBA之前做了哪些操作,之后我便大致定位到了问题所在。
DBA的反馈是之前在做sysbench的全update性能测试,测试完成后就关闭了数据库。但是当再重启后就发现这个现象,并且等待3,4个小时候后问题依旧。待其叙述完后,我的第一反映是srv_innodb_fast_shutdown默认值为1,在关闭是不会对change buffer进行合并操作,因此会再下次启动时进行这类操作。因为MySQL 5.5版本InnoDB存储引擎的change buffer可以使用到1/2的Buffer Pool,故可能测试时期的update操作大部分都在change buffer中完成,再次启动会导致大量的合并操作。
问题可能是定位了,然而怎么证明我的想法又是另外一个过程了。首先根据DBA的描述,我在测试服务器上进行了类似的sysbench测试,然后关闭数据库,并对数据库进行备份以便再次进行观察。当再次启动MySQL数据库后,通过命令iotop可以观察到如下的运行状态:
|
可以发现的确有两个线程的IO负载较高,但是这两个进程对应于MySQL数据库的哪两个线程就不得而知了。接着,通过命令SHOW ENGINE INNODB STATUS可以观察到如下的内容:
|
这里可以看到Main thread process显示当前的状态为doing insert buffer merge,可以判断当正在处理change buffer。MySQL对命令SHOW ENGINE INNODB STATUS进行小小的改进,可以看到每个线程对应于Linux的进程号,也就是iotop对于的进程号,而默认只能看到对应的线程号。配置文件中启用了innodb_purge_thread=1,因此还可以看到purge线程的信息。
可以发现进行535和536就是上述iotop中IO负载较高的进程。因此问题基本已经被证实。然而通过iotop发现,purge线程的IO负载要比main线程的要高许多。这是之前没有特别注意的,虽然InnoDB快速关闭不会进行change buffer的合并操作,但是其也不会等待purge操作全部完成。而之前的测试产生了大量的undo log需要等待被purge。通过命令SHOW ENGINE INNODB STATUS发现:
|
可以看到History list length为29 572 089,也就是说差不多有接近3000W的undo log记录。OMG,还真不少。。。不过也好理解,毕竟测试的都是update操作。
另外,还可通过类似pstack工具找出当前MySQL数据库线程调用的函数信息:
|
可以看到有大量的trx_purge,ibuf_contract_for_n_pages函数调用,也就是purge和change buffer的操作。从这里也可以进一步证实之前的猜测。pstack的另一个好处是可以看到线程具体的函数调用情况,这里通过之前SHOW ENGINE INNODB STATUS得到的main线程号140593741342464(对于十六进制0x7FDE8802A700)可以看到该线程的函数调用:
|
问题定位并被证实了。然而为什么DBA的服务器在经历了3,4个小时后还没有完成purge操作呢?最后发现DBA测试服务器的磁盘较差,而purge需要大量的离散操作,因此导致了较长的purge与merge时间。
总之,innodb_fast_shutdown默认值为1,在关闭时不进行change buffer的merge操作以及purge操作。想要下次启动时,不发生这样的现象,那么必须将innodb_fast_shutdown的值设置为0。其实也就是将merge change buffer和purge的操作时间放在了关闭数据库的时候。但是,在数据库升级或者测试环境中,可能必须要进行这样的操作。