当前位置: 首页 > 科技观察

优化MySQL行锁超时排查方法

时间:2023-03-13 23:13:04 科技观察

1.大纲,pstmt-38675}executeerror.updatexxxsetxxx=?,xxx=?whereRowGuid=?com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException:Lockwaittimeoutexceeded;tryrestartingtransaction在文章如何监控和解决行锁超时错误之前的【如何有效排查和解决MySQL行锁等待超时问题】中介绍过。当时介绍的监控方案主要是使用shell脚本+general_log来抓取行锁等待信息。后来觉得比较麻烦,于是经过优化,改为在MySQl中使用Event+Procedure定时执行。log表中记录了行锁等待信息,增加了pfs表中的事务上下文信息,省去了登录服务器执行脚本和分析general_log的过程,更加方便。因为使用了Event和performance_schema下的系统表,所以需要开启两者的配置。pfs可以使用默认的监控项。这里主要使用events_statements_history表,默认会保留会话的10条SQL语句。performance_schema=onevent_scheduler=1二、步骤目前该方法只在MySQL5.7版本中使用过,MySQL8.0未测试。createdatabase`innodb_monitor`;createdatabase`innodb_monitor`;2.2创建存储过程useinnodb_monitor;delimiter;;CREATEPROCEDUREpro_innodb_lock_wait_check()BEGINdeclarewait_rowsint;setgroup_concat_max_len=1024000;CREATETABLEIFNOTEXISTS`innodb_lock_wait_log`(`report_time`datetimeDEFAULTNULL,`waiting_id`int(11)DEFAULTNULL,`blocking_id`int(11)DEFAULTNULL,`duration`varchar(50)DEFAULTNULL,`state`varchar(50)DEFAULTNULL,`waiting_query`longtextDEFAULTNULL,`blocking_current_query`longtextDEFAULTNULL,`blocking_thd_last_query`longtext,`thread_id`int(11)DEFAULTNULL);selectcount(*)intowait_rowsfrominformation_schema.innodb_lock_waits;ifwait_rows>0THENinsertinto`innodb_lock_wait_log`SELECTnow(),r.trx_mysql_thread_idwaiting_id,b.trx_mysql_thread_idblocking_id,concat(timestampdiff(SECOND,r.trx_wait_started,CURRENT_TIMESTAMP()),'s,r.trx_querywaiting_query,b.trx_queryblocking_current_query,group_concat(left(h.sql_text,10000)orderbyh.TIMER_STARTDESCSEPARATOR';\n')Asblocking_thd_query_history,thread_idFROMinformation_schema.innodb_lock_waitswJOINinformation_schema.innodb_trxbONb.trx_id=w.blocking_trx_idJOINinformation_schema.innodb_trxrONr.trx_id=w.requesting_trx_idLEFTJOINperformance_schema.threadstont.processlist_id=b.trx_mysql_thread_idLEFTJOINperformance_schema.events_statements_historyhUSING(thread_id)groupbythread_id,r.trx_idorderbyr.trx_wait_started;endif;END;;2.3创建事件事件每5秒执行一次(通常等于innodb_lock_wait_timeout的值),连续监听7天,事件结束后会自动删除,保留期也可以定制useinnodb_monitor;delimiter;;CREATEEVENT`event_innodb_lock_wait_check`ONSCHEDULEEVERY5SECONDSTARTSCURRENT_TIMESTAMPENDSCURRENT_TIMESTAMP+INTERVAL7DAYONCOMPLETIONNOTPRESERVEENABLEDOcallpro_innodb_lock_wait_check();;;2.4事件启停--1为全局开启事件,0为全局关闭mysql>SETGLOBALevent_scheduler=1;--临时关闭事件mysql>ALTEREVENTevent_innodb_lock_wait_checkDISABLE;--关闭并打开事件mysql>ALTEREVENTevent_innodb_lock_wait_checkENABLE;3.log表然后根据应用日志报错时间点和sql分析innodb_lock_wait_log表。主要有两种情况:blocking_current_query不为空,说明阻塞事务正在运行。这时候就需要分析当前运行的SQL是否存在性能问题。Blocking_current_query为空,状态为Sleep。此时阻塞事务处于挂起状态,即SQL不再运行。这时候需要通过分析blocking_thd_last_query来分析事务上下文。注意本栏SQL是按时间降序排列的,即从下往上执行。