MySQL 数据库磁盘爆的主要原因
数据量大
MySQL 磁盘爆的最常见原因之一就是数据量突然增大导致数据库爆,这种原因往往和业务相关。比如应用程序在短时间内生成了大量的数据,如果是突然出现新增大量数据,也有可能是某些测试用例或者压测导致。这种原因导致的数据库磁盘暴涨可以通过清理数据的方式解决,比如清除特定时间段的数据。
建议在测试环境等数据库,进行压力测试或者其他自动化测试时候对数据做特殊的标志,在完成测试后自动清除测试产生的垃圾数据,避免日积月来导致磁盘爆满影响数据库使用。
同时按照数据库日常使用的情况看是否需要对磁盘进行扩容,但是扩容只能缓解,不能根治。
日志文件
MySQL 在日常运行的时候回产生大量的日志文件,这些日志文件也会占用磁盘空间,日积月累可能会产生几百 G 的日志文件。
MySQL 的日志文件主要有以下几种:
- bin log 二进制文件通常是占用空间最大的日志类型,这和数据库的使用情况相关。
- error 错误日志占用空间大的原因主要体现在长时间的日积月累,没有定时清除导致,比如运行了一两年的数据库,产生的错误日志往往也比较大。
- 慢查询日志 慢查询日志通常不会占用太多空间,但是长时间不清理也会出现占用过多的问题,需要定时清理
临时文件
临时文件是数据库运行时候产生的临时性文件,这种临时性文件在运行结束以后会自动释放,但是某些异常情况下如果没有释放会造成比较严重的后果,比如短时间的慢查询语句,这种慢查询执行时间巨长,查询的数据很多,MySQL 在内存不够的情况下回临时将中间结果存放在数据库的临时目录下。
处理日志文件导致的磁盘爆满
清理日志文件导致的磁盘爆满比较容易,在确保文件备份转存的前提下可以直接清理文件。使用 echo ‘’ >> host- XXXXX.err 等命令可以直接清理这些日志文件。
切记不要直接删除相关的日志文件
查看当前数据库服务器磁盘占用情况可以使用如下命令
查看某个文件夹下的文件磁盘占中情况可以使用 du 明令参考
# 切换到需要查看的路径下使用 du -hl
日志文件导致的磁盘爆满可以通过 linux 命令
echo '' >> host-xxxxx.log
处理临时文件导致的磁盘爆满
查看 Mysql 配置的临时目录
通常 MySQL 的临时目录在 mysql/temp 路径下,如果想查看配置的参数,可以使用 show variableslike ‘tmpdir’ SQL 命令
show variables like 'tmpdir'
临时文件产生的原因
临时文件产生的主要原因是 MySQL 在执行的时候,对一些大数据量的操作的时候内存无法满足存储需求的时候,MySQL 会使用临时文件,比如某个临时表查询出的几百万数据,某个联合查询产生的结果集等。通常情况下 MySQL 产生的临时文件很小,同时也会及时释放,但是一些异常情况下,比如慢查询,会导致短时间产生大量的临时文件。
下面是一个因为慢查询导致临时目录下产生大量文件的案例。
临时文件产生过多导致磁盘爆满,造成数据库短时故障
数据库崩溃的前兆往往是短时间出现大量 IO,CPU 暴涨。出现以上征兆的时候数据库就离崩溃不远了,下面这个案例就是。
这个案例中我们发现在某个时间点数据库突然 CPU 暴涨,而且是持续性暴涨,与此对应的磁盘的 IO 次数暴增,内存使用暴增。这个时候基本可以判断数据库出现了短时间大量的慢查询。
为什么慢查询会导致磁盘 IO 暴增?原因是上面说的,数据库在查询的时候使用的临时表或者临时数据如果内存不足以存放的时候,数据库会将这些数据存放在磁盘中,随着慢查询越来越多就会出现集中踩踏的问题,问题愈演愈烈,最终导致数据库卡顿或者崩溃。
上面案例中通过查看数据库执行记录,我们发现的确出现了慢查询积压的情况,使用以下 SQL 查询 可以查询当前正在执行的 SQL 状态
SELECT id, `state`, user,host,time,`INFO` FROM information_schema.processlist where state IS NOT NULL and state <> "" ORDER BY time desc;
上面,你可以看到数据库正在执行超过 10W 秒的 SQL,而且是好几个,这样就不难理解为什么数据库会出现短时间 CPU 和 IO 暴增的情况。
解决这些问题的办法就是: kill 当前的慢查询,这个办法很管用,但是要记录查询的语句和使用的登录账号和机器,以备兴师问罪。
下面这个语句可以快速生成批量 kill 语句。
SELECT concat('kill ', id, ';') FROM information_schema.processlist where user = 'HispaceCMS' and `COMMAND` = 'Query' and state IS NOT NULL and state <> '' and DB is not null and time > 1000 ORDER BY time desc
生成以后批量执行就可以了。执行完查询磁盘占用情况,从 96% 下降到 50 左右。