我是靠谱客的博主 踏实毛豆,最近开发中收集的这篇文章主要介绍mysql sys库 oom_MySQL异常OOM排查,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

收到告警,提示mysql挂了,此时看监控,负载已经比较高,服务器已经无法登录。看见监控此时的负载情况如下:

AIAACAyCL8AAACIDMIvAAAAIoPwCwAAgIgQ+f+BqZKwD5hiuQAAAABJRU5ErkJggg==

除了系统层面的监控还可以看到,mysql层面的监控已经断图,等负载降下来的时候mysql已经被oom,自动重启了。

dfd24b593cdab160639e79e52da1f57f.png

从mysql错误日志看到如下信息:

2020-08-01T09:14:11.778918+08:00 0 [Note] InnoDB: page_cleaner: 1000ms intended loop took 4271ms. The settings might not be optimal. (flushed=386 and evicted=119, during the time.)

这基本上说明,数据库收到的写入过多,导致BufferPool充满脏页。这会触发PageCleaner进行操作并清除脏页。由于脏页比平时多,因此PageCleaner清除缓冲区需要花费更多时间。

由于监控在负载异常高的这段时间msyql层面已经断图,看不到相关监控,那么如何排查呢?那只能从binlog入手了,好,那么分析一下binlog,看有没有大事务之类的。

mysqlbinlog mysql-bin.005298 | grep "GTID$(printf 't')last_committed" -B 1 | egrep -E '^# at|^#20' | awk '{print $1,$2,$3}' | sed 's/server//' | sed 'N;s/n/ /' | awk 'NR==1 {tmp=$1} NR>1 {print $4,$NF,($3-tmp);tmp=$3}' | sort -k 3 -n -r | head -n 20

f697be10462c2e0dad07ae13752c305b.png

可以看见再8:56:44左右,可以看见最大的一个事务在100M,这是比较大了。通过在该时间范围内继续解析binlog,发现有大范围的更新数据。这不够直观,我们写一段代码,把DML趋势放入ES来分析一下,代码比较简单,如下:

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

#!/usr/bin/python#coding: utf8

"""跟踪一段时间内dml趋势,用ES分析

Usage:

python dml2es.py | logstash -f /etc/logstash/conf.d/t_binlog.conf"""

importjsonimportosimportsysimportloggingfrom datetime importdatetimefrom pymysqlreplication importBinLogStreamReaderfrom pymysqlreplication.event importQueryEvent, RotateEventfrom pymysqlreplication.row_event import(

WriteRowsEvent,

UpdateRowsEvent,

DeleteRowsEvent,

)definit_log():#get root logger

mylogger =logging.getLogger()

mylogger.setLevel(logging.DEBUG)#create file handler and add formatter to handler

verbose_log_file = "/tmp/%s.verbose.log" %(os.path.basename(sys.argv[0]))

fh=logging.FileHandler(verbose_log_file)

fh.setLevel(logging.DEBUG)

fh.setFormatter(logging.Formatter(

fmt="%(asctime)s %(filename)s:%(lineno)d %(levelname)s %(message)s",

datefmt="%a %d %b %Y %H:%M:%S"))#create stream handler and add formatter to handler

sh =logging.StreamHandler(sys.stdout)

sh.setLevel(logging.INFO)

sh.setFormatter(logging.Formatter(

fmt="%(asctime)s %(levelname)-8s %(message)s",

datefmt="%H:%M:%S"))#add two handler to logger

mylogger.addHandler(fh)

mylogger.addHandler(sh)returnmyloggerif __name__ == "__main__":

logger=init_log()

mysql_settings={'host': '127.0.0.1','port': 3306,'user': 'xxx','passwd': 'xxx'}

binlog_file= 'mysql-bin.005298'start_position= 123stop_position= 1031510925

#不需要blocking

stream =BinLogStreamReader(

connection_settings=mysql_settings,

server_id=9999,

log_file=binlog_file,

log_pos=start_position,

resume_stream=True,

blocking=False

)for binlogevent instream:

data={}if binlogevent.packet.log_pos >=stop_position:break

#当输出 "@timestamp" : binlogevent.timestamp

#即 "@timestamp" => 1582624830

#logstash 会有warning

#[WARN ] 2020-02-25 18:00:31.313 [[main]

#所以需要进行下面的格式转换

#使用 datetime.fromtimestamp 将解析为 当前操作系统时区的 datetime

ifisinstance(binlogevent, WriteRowsEvent):

data={"schema": binlogevent.schema,"table": binlogevent.table,"dmltype" : "insert","@timestamp" :datetime.fromtimestamp(binlogevent.timestamp).strftime('%Y-%m-%dT%H:%M:%S') ,

}printjson.dumps(data)elifisinstance(binlogevent, DeleteRowsEvent):

data={"schema": binlogevent.schema,"table": binlogevent.table,"dmltype" : "delete","@timestamp" :datetime.fromtimestamp(binlogevent.timestamp).strftime('%Y-%m-%dT%H:%M:%S') ,

}printjson.dumps(data)elifisinstance(binlogevent, UpdateRowsEvent):

data={"schema": binlogevent.schema,"table": binlogevent.table,"dmltype" : "update","@timestamp" :datetime.fromtimestamp(binlogevent.timestamp).strftime('%Y-%m-%dT%H:%M:%S') ,

}printjson.dumps(data)elifisinstance(binlogevent, RotateEvent):if binlogevent.packet.log_pos <= 1655:

logger.debug( u"next_binlog:" +binlogevent.next_binlog )

stream.close()

View Code

我们在kibana里面把时间缩短到秒级看看这段时间的DML趋势

977f60e53c3c514349bd7c3d5f1858c7.png

可以看见和我们直接分析binlog得到的结果一致,就是这个时间点的几个大事务导致的大量的数据更新。由于innodb_page_cleaners参数已经是4,不做调整。

总结:

1.杜绝大事务,同时注意SQL是否合理利用索引

2.mysql相关参数调整,比如innodb_io_capacity,innodb_io_capacity_max,由于这台机器使用的NVME接口的SSD,故把innodb_io_capacity参数调整到10000

最后

以上就是踏实毛豆为你收集整理的mysql sys库 oom_MySQL异常OOM排查的全部内容,希望文章能够帮你解决mysql sys库 oom_MySQL异常OOM排查所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(52)

评论列表共有 0 条评论

立即
投稿
返回
顶部