博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
基于innodb_print_all_deadlocks从errorlog中解析MySQL死锁日志
阅读量:6091 次
发布时间:2019-06-20

本文共 5360 字,大约阅读时间需要 17 分钟。

 

本文是说明如何获取死锁日志记录的,不是说明如何解决死锁问题的。

MySQL的死锁可以通过show engine innodb status;来查看,
但是show engine innodb status;只能显示最新的一条死锁,该方式无法完全捕获到系统发生的死锁信息。
如果想要记录所有的死锁日志,打开innodb_print_all_deadlocks参数可以将所有的死锁日志记录到errorlog中,
因此问题就变成了如何从errorlog解析死锁日志。

参考如下截图,是errorlog中的一个典型的死锁日志信息,除了死锁日志,可以制造了一些其他的干扰日志(故意不输入密码登陆数据库让它记录一些其他错误日志信息)

如果要解析这个死锁日志(排除其他无关日志),也即解析产生死锁内容,拆分死锁日志内容中的两个(或者)多个事务
1,死锁开始和结束的标记====>截取单个死锁日志内容
2,解析第1步中的死锁日志===>截取各个事务日志

以下解析基于如下规则,基本上都是根据本关键字和正则做匹配

1,死锁日志开始的标记: Transactions deadlock detected, dumping detailed information.
2,死锁日中中事务开始的标记:*** (N) TRANSACTION:
3,死锁结束的标记:WE ROLL BACK TRANSACTION (N)

import osimport timeimport datetimeimport refrom IO.mysql_operation import mysql_operationclass mysql_deadlock_analysis:    def __init__(self):        pass    def is_valid_date(self,strdate):        try:            if ":" in strdate:                time.strptime(strdate, "%Y-%m-%d %H:%M:%S")            else:                time.strptime(strdate, "%Y-%m-%d")            return True        except:            return False    def insert_deadlock_content(self,str_id, str_content):        connstr = {
'host': '***,***,***,***', 'port': 3306, 'user': 'username', 'password': 'pwd', 'db': 'db01', 'charset': 'utf8mb4'} mysqlconn = mysql_operation(host=connstr['host'], port=connstr['port'], user=connstr['user'], password=connstr['password'], db=connstr['db'], charset=connstr['charset']) ''' 死锁日志表结构,一个完整的死锁日志按照死锁中第一个事务开始时间为主,deadlock_id一样的话,说明是归属于一个死锁 create table deadlock_log ( id int auto_increment primary key, deadlock_id varchar(50), deadlock_transaction_content text, create_date datetime ) ''' str_sql = "insert into deadlock_log(deadlock_id,deadlock_transaction_content,create_date) " \ "values ('%s','%s',now())" % (str_id, str_content) try: mysqlconn.execute_noquery(str_sql, None) except Exception as err: raise (Exception, "database operation error") #解析死锁日志内容 def read_mysqlerrorlog(self,file_name): try: deadlock_flag = 0 deadlock_set = set() deadlock_content = "" with open(file_name,"r") as f: for line in f: if(deadlock_flag == 0): str_datetime = line[0:19].replace("T"," ") if(self.is_valid_date(str_datetime)): if(line.find("deadlock")>0):#包含deadlock字符串,表示死锁日志开始 #输出死锁日志,标记死锁日志开始 deadlock_content = deadlock_content+line deadlock_flag = 1 elif(deadlock_flag == 1): #输出死锁日志 deadlock_content = deadlock_content + line #死锁日志结束 if (line.find("ROLL BACK")>0):#包含roll back 字符串,表示死锁日志结束 deadlock_flag = 0 #一个完整死锁日志的解析结束 deadlock_set.add(deadlock_content) deadlock_content = "" except IOError as err: raise (IOError, "read file error") return deadlock_set #解析死锁日志中的各个事务信息 def analysis_mysqlerrorlog(self,deadlock_set): #单个事务开始标记 transaction_begin_flag = 0 #死锁中的单个事务信息 transaction_content = "" # 死锁发生时间 str_datetime = "" #匹配事务开始标记正则 pattern = re.compile(r'[*]* [(0-9)]* TRANSACTION:') for str_content in deadlock_set: arr_content = str_content.split("\n") for line in arr_content: if (self.is_valid_date(line[0:19].replace("T", " "))): #死锁发生时间,在解析死锁日志内容的时候,每组死锁日志只赋值一次,一个死锁中的所有事物都用第一次的时间 str_datetime = line[0:19].replace("T", " ") #死锁日志中的事务开始标记 if( pattern.search(line)): transaction_begin_flag = 1 #事务开始,将上一个事务内容写入数据库 if(transaction_content): self.insert_deadlock_content(str_datetime,transaction_content) #死锁日志中新开始一个事务,重置transaction_content以及事务开始标记 transaction_content = "" transaction_begin_flag = 0 else: #某一个事务产生死锁的具体日志 if(transaction_begin_flag==1): transaction_content = transaction_content +"\n"+ line #死锁日志中的最后一个事务信息 if (transaction_content): self.insert_deadlock_content(str_datetime, transaction_content) transaction_content = "" transaction_begin_flag = 0if __name__ == '__main__': file_path = "\path\mysql.err" analysis = mysql_deadlock_analysis() str_content = analysis.read_mysqlerrorlog(file_path) analysis.analysis_mysqlerrorlog(str_content)

 

以下是写入到数据库之后的效果id为1,2的对应一组死锁的事务信息,id为3,4的对应一组死锁事务

 

 

纯属快速尝试自己的一些个想法,还有很多不足

1,解析后的日志格式很粗
2,解析的都是常规的死锁,不确定能hold所有的死锁日志格式,根据关键字解析的,不知道是不是总是有效
3,如何避免重复解析,也即定时解析MySQL的error的时候,没判断前一次解析过的内容的判断
4,没有做效率测试

 

转载地址:http://lmlwa.baihongyu.com/

你可能感兴趣的文章
SIP入门(二):建立SIPserver
查看>>
Servlet3.0的异步
查看>>
WebService连接postgresql( 失败尝试)
查看>>
从头认识java-13.11 对照数组与泛型容器,观察类型擦除给泛型容器带来什么问题?...
查看>>
从MFQ方法到需求分析
查看>>
android.view.WindowManager$BadTokenException: Unable to add window
查看>>
HDU5012:Dice(bfs模板)
查看>>
iphone openssh
查看>>
Linux下MEncoder的编译
查看>>
spark高级排序彻底解秘
查看>>
ylbtech-LanguageSamples-PartialTypes(部分类型)
查看>>
福建省促进大数据发展:变分散式管理为统筹集中式管理
查看>>
开发环境、生产环境、测试环境的基本理解和区别
查看>>
tomcat多应用之间如何共享jar
查看>>
Flex前后台交互,service层调用后台服务的简单封装
查看>>
MySQL入门12-数据类型
查看>>
Windows Azure 保留已存在的虚拟网络外网IP(云服务)
查看>>
修改字符集
查看>>
HackTheGame 攻略 - 第四关
查看>>
js删除数组元素
查看>>