一次慢日志撑爆磁盘导致的业务主库宕机引发的思考

在MySQL的日常维护中,我们总会遇到这样或那样的问题,对于那些经常发生且有处理经验的事故,不论是新手还是老司机都能在故障规定的容错时间内解决。而对于那些不常见、比较棘手的问题,新手上路可能就显得举足无措了,这个时候新手和老司机的差距就体现出来了。从知识储备还是工作经验,可能老司机比新手强一点,但如果一个新司机没有日志排错的意识,不具备日志排错的经验,那怎么能学会弯道超车、漂移的快感。我们知道数据库中有很多重要的日志,如错误日志error log、慢日志slow log、二进制日志binary log、查询日志general log等等其他日志,错误日志error log是我们分析问题参考的依据,它记录数据库的启动/运行/停止的过程,包含了info、warning、error三个级别,分析error log也有助于我们了解数据库的运行机制。

我们知道数据库中的binary log、relay log都是数据库本身自带的purge清理线程处理过时的没有用的日志,这种处理能有效释放磁盘空间。而对于慢日志slow log、错误日志error log这种记录数据库实例整个运行阶段的日志,不会被定期处理,那么就有可能会被记录得过多,占据过多的磁盘空间。对于错误日志error log,默认记录;对于slow log需要我们自己选择是否记录。建议开启slow log功能,这对于数据库优化之一的SQL优化有很大的帮助。

通常我们在业务主库是开启慢日志功能并通过参数long_query_time这个参数来控制执行时间多长的SQL被记录进慢日志中,且对于执行时间超过1s的SQL就认为是慢SQL,这样的设定值,很多场合下不会记录太多的慢SQL,因而不会占据太多的磁盘空间。然而当开发上线的程序有问题,SQL执行效率不高,且执行的频率非常高,这些慢SQL被记录就会存在磁盘空间被撑爆的安全隐患,从而导致数据库宕机并尝试重启且多次尝试失败,严重影响业务。不过值得庆幸的是,该部分业务我们有MMM高可用架构,VIP已经漂移到另一台master上了。

2018-05-29 09:09:18 28094 [ERROR] Error writing file ‘/opt/app/mysql/logs/slow.log‘ (errno: 1 - No space left on device)
2018-05-29 09:09:18 28094 [ERROR] Error writing file ‘/opt/app/mysql/logs/slow.log‘ (errno: 1 - No space left on device)
180529 09:09:19 mysqld_safe mysqld restarted
InnoDB: 3 transaction(s) which must be rolled back or cleaned up
InnoDB: Starting in background the rollback of uncommitted transactions
/opt/app/mysql/bin/mysqld: Error writing file ‘/opt/app/mysql/logs/slow.log‘ (Errcode: 28 - No space left on device)
2018-05-29 09:09:33 33114 [ERROR] Could not open /opt/app/mysql/logs/slow.log for logging (error 28). Turning logging off for the whole duration of the MySQL server process. To turn it on again: fix the cause, shutdown the MySQL server and restart it.
2018-05-29 09:09:34 33114 [ERROR] /opt/app/mysql/bin/mysqld: Error writing file ‘/opt/app/mysql/tmp/mysqld.pid‘ (Errcode: 28 - No space left on device)
2018-05-29 09:09:34 33114 [ERROR] Can‘t start server: can‘t create PID file: No space left on device

如上面的报错显示(只是选择截取部分错误日志),数据库发生错误的原因是磁盘没有足够的空间,慢日志无法写入,数据库尝试restart并rollback没有提交的事务(继续查看后面的日志能看到redo log的信息),而数据库也对我们提出了建议关闭错误日志的记录功能。继续看启动过程,发现关于pid文件的No space left on device,数据库还是无法启动。排查故障并处理故障,在尽可能短的时间内恢复业务是最重要的,因而这里就没有详细的操作代码保存来说明。通过df -Th查看发现/空间不足,并ls -lh查看慢日志的大小是1.2T,已经严重消耗了磁盘空间。这个时候我们并不能直接rm -rf删除慢日志文件,因为数据库的启动时需要慢日志功能切且日志文件占据了磁盘空间,我们只能重定向清空慢日志,这样数据库得以重新启动。

虽然我们的业务主库有MMM高可用架构,事实发现VIP确实是漂移到另一台master上,但仍然给我们的其他slave造成了复制同步错误的故障,更为严重的是影响到了我们的多源复制库的使用,内部人员使用和维护也带来很大的影响。对于数据库本身来讲,error log和slow log不能自动清理,这有一定的优点,但同时也会有磁盘空间可能被撑爆的潜在危险。

如果能够通过一个crontab,或者一个告警,定期或者提醒我们对慢日志进行清理,我想也不会造成如今的这个麻烦。我们可以通过如下的一个Shell脚本,策略是删除几天以前的慢日志 ,保留最近几天的慢日志,或者使用过Inception工具的,可以将慢日志定期拉走,备份到远端。

[[email protected] shells]# cat clean_mysql_slow_log.sh
#!/binbash
#author=lyx
#time:2018-05-29

cur_date=`date +%y%m%d`
#step_days=5 #clean slowlog 6 days ago
for step_days in $(seq 5 -1 0)
do
        end_date=`expr $cur_date - $step_days`
        clean_line_num=`cat /opt/shells/slow.log |grep -n "^# Time: $end_date"|head -n 1|cut -d : -f 1`
        if ((${#clean_line_num} > 1))
        then
                clean_max_line_num=`expr $clean_line_num - 1`
                sed -i "1,$clean_max_line_num d" /opt/shells/slow.log
                break
        fi
done
echo $clean_max_line_num
echo $step_days

该脚本的策略是根据当前时间,保留最近5天的慢日志,每次运行脚本则保留的日志天数减少一天。当然如果你有更好的业务策略或者脚本逻辑也可以择优选择,比如你可以根据慢日志的文件大小,配置告警并触发清理,或者crontab都可以。

[[email protected] shells]# bash clean_mysql_slow_log.sh
1746208
5
[[email protected] shells]# bash clean_mysql_slow_log.sh
1638936
4
[[email protected] shells]# cp /opt/app/mysql_3309/logs/slow.log .
cp: overwrite `./slow.log‘? y
[[email protected] shells]# ls -lh slow.log
-rw-r----- 1 root root 844M May 29 18:24 slow.log
[[email protected] shells]# bash clean_mysql_slow_log.sh
1746208
5
[[email protected] shells]# ls -lh slow.log
-rw-r----- 1 root root 781M May 29 18:25 slow.log
[[email protected] shells]# bash clean_mysql_slow_log.sh
1638936
4
[[email protected] shells]# cat slow.log |head -n 1
# Time: 180525 0:00:00
[[email protected] shells]# bash clean_mysql_slow_log.sh
4257796
3
[[email protected] shells]# ls -lh slow.log
-rw-r----- 1 root root 571M May 29 18:26 slow.log
[[email protected] shells]# cat slow.log |head -n 1
# Time: 180526 0:00:01

其实这是一个比较low的一个技术点,但是慢日志的清理很容易被我们忽略,很多时候开发不会随意上线,DBA也会对慢SQL进行把控并优化,然而当你半夜在睡觉,开发很晚上线一段有问题的代码,这个 时候的后果....,确实有些危险。慢日志功能是我们优化数据库的一个重要的参考,但也要注意慢日志文件的大小的增长速度,避免占据过多的磁盘空间。

原文地址:https://www.cnblogs.com/liyingxiao/p/mingyuesanqianli.html

时间: 2024-08-03 07:40:59

一次慢日志撑爆磁盘导致的业务主库宕机引发的思考的相关文章

ORA-0402导致oracle11gADG备库宕机问题处理

发现数据库告警,查看alert日志,发现如下报错Errors in file /u01/app/oracle/diag/rdbms/orcl/orcl1/trace/orcl1_lgwr_26383.trc:ORA-04021: timeout occurred while waiting to lock object LGWR (ospid: 26383): terminating the instance due to error 4021Sun Mar 25 03:29:07 2018Sy

接口异步调用导致的一个低概率问题引发的思考。

最近5个月接触到的异步调用占工作以来接触到的一半以上,这些异步调用都是消费消息的方式. 应用A在处理完业务后,需要调用应用B的接口做信息同步(记录数据或者更新数据),有两种方式: 一般情况是采用同步方式,等待应用B的接口处理完后,拿到返回值,继续后续处理.这样的好处是可以根据应用B的接口返回值来做接下来的数据处理:如果B失败了,可以数据回滚:或者使用应用B的接口返回数据继续业务处理. 还有一种比较少的方式是异步:有发消息的,也有往系统插入一条定时任务数据的.这种方式的好处时不用等待调用方处理,节

MySQL ibdata1撑爆占满磁盘空间

MySQL主从由于ibdata1占满磁盘空间-->主从失效 因为设置了innodb_file_per_table = 1,ibdata1依旧撑爆占满磁盘空间 主从断的时候,IO线程在连接,SQL线程断掉. 想要了解为何ibdata1增长那么大? 个人这么理解的:主从断掉,IO线程在,获取到了事件事物的更新,而SQL线程断掉,导致产生大量的undo,撑爆了ibdata1. 最终验证发现,确实是undo占满了ibdata1. 下载一个小工具:py_innodb_page_info.py  本人网盘下

如何快速的把日志输出到磁盘上

不管是做客户端业务,还是做服务端业务,日志子系统都是非常重要的一个组件. 日志系统的输出目的地可以是disk,也可以是tty,更可以是network. 我的日志系统可以输出到tty,不同log level可以有不同的color,这样看日志非常的醒目,当然这里着重谈的是如何快速的把log内容写到磁盘上. 其实,如何快速的把log内容写到磁盘上,网上文章已经汗牛充栋,真正高质量的没多少,本篇可能也是狗尾续貂之作.不过,我的log子系统能够达到106M/s的输出速率. 详细介绍我的log系统之前,推荐

css限制图片大小,避免页面撑爆

/*==========限制图片大小======避免页面撑暴========*/img { max-width:100%;width:expression(width>669?"100%":width+"px");} --说明 .content img { max-width:100%;width:expression(width>(外层宽度px)?"100%":width+"px");} css限制图片大小,避免

oracle rac 11g 日志占满系统盘导致数据库down掉

oracle日志占满系统盘满了导致数据库挂掉 并且archivelog日志也满了倒是数据库无法open,无法登陆,幸好还可以到mount状态.解决办法: 1.根据报错查看 表象: crs 服务down掉 CRS-0184: Cannot communicate with the CRS daemon删除/var/tmp/.oracle 目录删除oracle alter日志:cd /u01/app/oracle/rdbms/bol/BOL1/alterrm -rf * 到此重启机器 可以启动ora

几百万数据放入内存不会把系统撑爆吗?

在公司有一个需求是要核对一批数据,之前的做法是直接用SQL各种复杂操作给怼出来的,不仅时间慢,而且后期也不好维护,就算原作者来了过一个月估计也忘了SQL什么意思了,于是有一次我就想着问一下之前做这个需求的人为什么不将这些数据查出来后在内存里面做筛选呢?直接说了你不怕把内存给撑爆吗?此核算服务器是单独的服务器,配置是四核八G的,配置堆的大小是4G.本着怀疑的精神,就想要弄清楚几百万条数据真的放入内存的话会占用多少内存呢? 计算机的存储单位计算机的存储单位常用的有bit.Byte.KB.MB.GB.

数据库修改字段导致宕机

170614 23:28:56 [ERROR] Slave SQL: Error 'Got error 64 'Temp file write failure' from InnoDB' on query. Default database: 'loandb'. Query: 'ALTER TABLE 'trd_loanapply DROP COLUMN LAP_SIGNRATE , Internal MariaDB error code: 1296 170614 23:28:56 [Warni

由于master宕机等导致resource调用出现异常,直接将该resource返回到pool以便其他代码使用会导致得到不可预期的结果,导致返回数据混乱。

实现一:public String get(final String key) {              Jedis resource = null;              try {                           resource = pool.getResource();                            return resource.get(key);           } finally {