• MySQL如何输出发生死锁的SQL到日志文件


    一、背景

    首先我们在日常的开发中,大概率会使用批量更新,或者在一个事务里面做增删改查,那么就有可能不同事务之间导致死锁的发生。这里主要讲的是如何将当时发生死锁的信息输出到日志文件中,以及具体的SQL打印。

    二、如何实现

    查了很多网上的文章,都是使用什么下面之类的命令

    1. show engine innodb status \G;
    2. SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX;

    但是我发现这些命令都是查正在死锁的语句,并不是历史死锁的语句,想想我们在日常工作中包括生产环境,如果发生了死锁,应用监控告警了,那么我们应该去找的历史死锁日志。

    言归正传,那么如何找到历史的死锁日志。

    (1)确认错误日志打印

    确认错误日志打印路径,死锁的日志都会打印到这个错误日志文件,是可以看到历史日志的关键

    通过命令 show global variables like "log_error%";查看错误日志路径

    (2)打开死锁检测机制(必要)

    MySQL有死锁检测机制,需要打开死锁检测机制(网上说死锁检测机制比较耗费性能,这个看个人取舍,我个人认为在现在的硬件环境支持下,这一点性能损耗是可以接受的)

    1. show variables like 'innodb_deadlock_detect';
    2. set GLOBAL innodb_deadlock_detect = ON;
    3. 当然你也可以在你的My.ini配置文件中写死(推荐)
    4. innodb_deadlock_detect = ON;

     (3)打开MySQL关于锁的Monitor监视器输出

    什么是MySQL的Monitor不在这里细说,想要了解的朋友可以参考InnoDB Monitor(innodb监视器)_yimenglin的博客-CSDN博客_innodb_monitor

    1. show global variables like "innodb_status_output%";
    2. set GLOBAL innodb_status_output = ON
    3. set GLOBAL innodb_status_output_locks = ON
    4. 同样最好在My.ini进行配置写死,免得每次重启服务器都要重新设置
    5. innodb_status_output = ON
    6. innodb_status_output_locks = ON

    (4)打印所有锁日志

    (非必要,博主发现不开这个参数也能实现打印历史的锁日志,如果你为了锁的日志更全面,也可以开启)

    1. show global variables like "innodb_print_all_deadlocks%";
    2. set GLOBAL innodb_print_all_deadlocks = ON;
    3. 同样建议在my.ini配置文件中写死
    4. innodb_print_all_deadlocks = ON

    (5)如何查找日志

    将上面的配置开启后,如果MySQL遇见死锁,则会帮你检测出来,并且回滚权重比较小的事务。这样另外一个事务就能往下执行(相当于自动帮你解除死锁)

    首先找到模拟一波

    开启两个事务

    交叉update id = 1 和 id = 2的记录,其中事务1出现了死锁。

    Deadlock found when trying to get lock; try restarting transaction

    同时也证明了死锁检测的好处,会自动帮你回滚其中一个事务的操作,让另外一个竞争的事务能够往下执行。

    接下来才是我们的重头戏,我们如何查找错误日志。

    根据第一步错误日志的文件

    1. 使用关键词INNODB MONITOR OUTPUT对日志进行过滤,一般会有开头和结束,例如我这次模拟的错的日志文件如下:
    2. 2022-11-10 07:46:26 0x6ef4 INNODB MONITOR OUTPUT
    3. =====================================
    4. Per second averages calculated from the last 20 seconds
    5. -----------------
    6. BACKGROUND THREAD
    7. -----------------
    8. srv_master_thread loops: 2 srv_active, 0 srv_shutdown, 131 srv_idle
    9. srv_master_thread log flush and writes: 0
    10. ----------
    11. SEMAPHORES
    12. ----------
    13. OS WAIT ARRAY INFO: reservation count 3
    14. OS WAIT ARRAY INFO: signal count 3
    15. RW-shared spins 0, rounds 0, OS waits 0
    16. RW-excl spins 0, rounds 0, OS waits 0
    17. RW-sx spins 0, rounds 0, OS waits 0
    18. Spin rounds per wait: 0.00 RW-shared, 0.00 RW-excl, 0.00 RW-sx
    19. ------------------------
    20. LATEST DETECTED DEADLOCK
    21. ------------------------
    22. 2022-11-10 07:46:22 0x7a38
    23. *** (1) TRANSACTION:
    24. TRANSACTION 273418, ACTIVE 25 sec starting index read
    25. mysql tables in use 1, locked 1
    26. LOCK WAIT 3 lock struct(s), heap size 1136, 2 row lock(s), undo log entries 1
    27. MySQL thread id 9, OS thread handle 4580, query id 72 localhost 127.0.0.1 root updating
    28. update foo set name = '123' where id = 2
    29. *** (1) HOLDS THE LOCK(S):
    30. RECORD LOCKS space id 711 page no 4 n bits 96 index PRIMARY of table `wechat_min_pro`.`foo` trx id 273418 lock_mode X locks rec but not gap
    31. Record lock, heap no 28 PHYSICAL RECORD: n_fields 4; compact format; info bits 0
    32. 0: len 4; hex 00000001; asc ;;
    33. 1: len 6; hex 000000042c0a; asc , ;;
    34. 2: len 7; hex 02000000b726d4; asc & ;;
    35. 3: len 3; hex 313233; asc 123;;
    36. *** (1) WAITING FOR THIS LOCK TO BE GRANTED:
    37. RECORD LOCKS space id 711 page no 4 n bits 96 index PRIMARY of table `wechat_min_pro`.`foo` trx id 273418 lock_mode X locks rec but not gap waiting
    38. Record lock, heap no 27 PHYSICAL RECORD: n_fields 4; compact format; info bits 0
    39. 0: len 4; hex 00000002; asc ;;
    40. 1: len 6; hex 00000004260a; asc & ;;
    41. 2: len 7; hex 02000000b725b8; asc % ;;
    42. 3: len 4; hex 33343536; asc 3456;;
    43. *** (2) TRANSACTION:
    44. TRANSACTION 273419, ACTIVE 19 sec starting index read
    45. mysql tables in use 1, locked 1
    46. LOCK WAIT 3 lock struct(s), heap size 1136, 2 row lock(s)
    47. MySQL thread id 10, OS thread handle 18376, query id 73 localhost 127.0.0.1 root updating
    48. update foo set name = '3456' where id = 1
    49. *** (2) HOLDS THE LOCK(S):
    50. RECORD LOCKS space id 711 page no 4 n bits 96 index PRIMARY of table `wechat_min_pro`.`foo` trx id 273419 lock_mode X locks rec but not gap
    51. Record lock, heap no 27 PHYSICAL RECORD: n_fields 4; compact format; info bits 0
    52. 0: len 4; hex 00000002; asc ;;
    53. 1: len 6; hex 00000004260a; asc & ;;
    54. 2: len 7; hex 02000000b725b8; asc % ;;
    55. 3: len 4; hex 33343536; asc 3456;;
    56. *** (2) WAITING FOR THIS LOCK TO BE GRANTED:
    57. RECORD LOCKS space id 711 page no 4 n bits 96 index PRIMARY of table `wechat_min_pro`.`foo` trx id 273419 lock_mode X locks rec but not gap waiting
    58. Record lock, heap no 28 PHYSICAL RECORD: n_fields 4; compact format; info bits 0
    59. 0: len 4; hex 00000001; asc ;;
    60. 1: len 6; hex 000000042c0a; asc , ;;
    61. 2: len 7; hex 02000000b726d4; asc & ;;
    62. 3: len 3; hex 313233; asc 123;;
    63. *** WE ROLL BACK TRANSACTION (2)
    64. ------------
    65. TRANSACTIONS
    66. ------------
    67. Trx id counter 273420
    68. Purge done for trx's n:o < 273414 undo n:o < 0 state: running but idle
    69. History list length 0
    70. LIST OF TRANSACTIONS FOR EACH SESSION:
    71. ---TRANSACTION 284451204563104, not started
    72. 0 lock struct(s), heap size 1136, 0 row lock(s)
    73. ---TRANSACTION 284451204561440, not started
    74. 0 lock struct(s), heap size 1136, 0 row lock(s)
    75. ---TRANSACTION 284451204560608, not started
    76. 0 lock struct(s), heap size 1136, 0 row lock(s)
    77. ---TRANSACTION 273418, ACTIVE 29 sec
    78. 3 lock struct(s), heap size 1136, 2 row lock(s), undo log entries 2
    79. MySQL thread id 9, OS thread handle 4580, query id 72 localhost 127.0.0.1 root
    80. TABLE LOCK table `wechat_min_pro`.`foo` trx id 273418 lock mode IX
    81. RECORD LOCKS space id 711 page no 4 n bits 96 index PRIMARY of table `wechat_min_pro`.`foo` trx id 273418 lock_mode X locks rec but not gap
    82. Record lock, heap no 28 PHYSICAL RECORD: n_fields 4; compact format; info bits 0
    83. 0: len 4; hex 00000001; asc ;;
    84. 1: len 6; hex 000000042c0a; asc , ;;
    85. 2: len 7; hex 02000000b726d4; asc & ;;
    86. 3: len 3; hex 313233; asc 123;;
    87. RECORD LOCKS space id 711 page no 4 n bits 96 index PRIMARY of table `wechat_min_pro`.`foo` trx id 273418 lock_mode X locks rec but not gap
    88. Record lock, heap no 27 PHYSICAL RECORD: n_fields 4; compact format; info bits 0
    89. 0: len 4; hex 00000002; asc ;;
    90. 1: len 6; hex 000000042c0a; asc , ;;
    91. 2: len 7; hex 02000000b726f6; asc & ;;
    92. 3: len 3; hex 313233; asc 123;;
    93. --------
    94. FILE I/O
    95. --------
    96. I/O thread 0 state: wait Windows aio (insert buffer thread)
    97. I/O thread 1 state: wait Windows aio (log thread)
    98. I/O thread 2 state: wait Windows aio (read thread)
    99. I/O thread 3 state: wait Windows aio (read thread)
    100. I/O thread 4 state: wait Windows aio (read thread)
    101. I/O thread 5 state: wait Windows aio (read thread)
    102. I/O thread 6 state: wait Windows aio (write thread)
    103. I/O thread 7 state: wait Windows aio (write thread)
    104. I/O thread 8 state: wait Windows aio (write thread)
    105. I/O thread 9 state: wait Windows aio (write thread)
    106. Pending normal aio reads: [0, 0, 0, 0] , aio writes: [0, 0, 0, 0] ,
    107. ibuf aio reads:, log i/o's:, sync i/o's:
    108. Pending flushes (fsync) log: 0; buffer pool: 0
    109. 1500 OS file reads, 232 OS file writes, 55 OS fsyncs
    110. 13.15 reads/s, 16384 avg bytes/read, 0.75 writes/s, 0.40 fsyncs/s
    111. -------------------------------------
    112. INSERT BUFFER AND ADAPTIVE HASH INDEX
    113. -------------------------------------
    114. Ibuf: size 1, free list len 195, seg size 197, 0 merges
    115. merged operations:
    116. insert 0, delete mark 0, delete 0
    117. discarded operations:
    118. insert 0, delete mark 0, delete 0
    119. Hash table size 2267, node heap has 1 buffer(s)
    120. Hash table size 2267, node heap has 0 buffer(s)
    121. Hash table size 2267, node heap has 0 buffer(s)
    122. Hash table size 2267, node heap has 0 buffer(s)
    123. Hash table size 2267, node heap has 0 buffer(s)
    124. Hash table size 2267, node heap has 0 buffer(s)
    125. Hash table size 2267, node heap has 0 buffer(s)
    126. Hash table size 2267, node heap has 1 buffer(s)
    127. 0.00 hash searches/s, 0.15 non-hash searches/s
    128. ---
    129. LOG
    130. ---
    131. Log sequence number 6117561793
    132. Log buffer assigned up to 6117561793
    133. Log buffer completed up to 6117561793
    134. Log written up to 6117561793
    135. Log flushed up to 6117561793
    136. Added dirty pages up to 6117561793
    137. Pages flushed up to 6117561793
    138. Last checkpoint at 6117561793
    139. 21 log i/o's done, 0.10 log i/o's/second
    140. ----------------------
    141. BUFFER POOL AND MEMORY
    142. ----------------------
    143. Total large memory allocated 8585216
    144. Dictionary memory allocated 388960
    145. Buffer pool size 512
    146. Free buffers 252
    147. Database pages 258
    148. Old database pages 0
    149. Modified db pages 0
    150. Pending reads 0
    151. Pending writes: LRU 0, flush list 0, single page 0
    152. Pages made young 0, not young 0
    153. 0.00 youngs/s, 0.00 non-youngs/s
    154. Pages read 1475, created 142, written 166
    155. 0.00 reads/s, 0.00 creates/s, 0.00 writes/s
    156. Buffer pool hit rate 353 / 1000, young-making rate 0 / 1000 not 0 / 1000
    157. Pages read ahead 0.00/s, evicted without access 0.00/s, Random read ahead 0.00/s
    158. LRU len: 258, unzip_LRU len: 0
    159. I/O sum[291]:cur[2], unzip sum[0]:cur[0]
    160. --------------
    161. ROW OPERATIONS
    162. --------------
    163. 0 queries inside InnoDB, 0 queries in queue
    164. 0 read views open inside InnoDB
    165. Process ID=9120, Main thread ID=00000000000053B0 , state=sleeping
    166. Number of rows inserted 0, updated 2, deleted 0, read 3
    167. 0.00 inserts/s, 0.05 updates/s, 0.00 deletes/s, 0.05 reads/s
    168. Number of system rows inserted 0, updated 315, deleted 0, read 5798
    169. 0.00 inserts/s, 0.00 updates/s, 0.00 deletes/s, 0.00 reads/s
    170. ----------------------------
    171. END OF INNODB MONITOR OUTPUT
    172. ============================

    我们发现产生死锁的两条SQL语句都被输出出来了

     update foo set name = '123' where id = 2

     update foo set name = '3456' where id = 1

    定位出具体的SQL,那么我们就可以在我们的代码上进行优化了,具体优化思路可以参照我另外一篇博客

    记录一次生产环境MySQL死锁以及解决思路_小胖子——鑫的博客-CSDN博客

    三、总结

    在生产环境日志,我这边是建议开启死锁检测、以及锁日志打印的,因为一旦发生死锁,首先死锁检测能帮助我们解除死锁,其次我们能够快速的定位具体的SQL以及代码问题,比起牺牲的性能来说,我们排查问题的效率就大大提升了。

  • 相关阅读:
    Redis数据结构之ziplist
    面对海量数据挑战,企业怎样进行数据处理?
    基于开源项目OCR做一个探究(chineseocr_lite)
    Allure-pytest功能特性介绍
    【SSL 1458】zzzyyds(DP)
    批量生成Excel文件,可以按模板进行自动生成
    java计算机毕业设计西安市城市绿地管理系统源码+系统+数据库+lw文档
    分享一个python无人超市管理系统django项目实战源码调试 lw 开题
    JavaScript---ECMAScirpt
    Visual Station 2022的头文件包含目录设置的区别
  • 原文地址:https://blog.csdn.net/qq_34798605/article/details/127781666