记Linux服务器磁盘空间不足解决之路

1. 前言

在我登录我自己开发的产品血玉钻的时候,我发现接口没有数据返回,远程登录发现服务器也并没有挂掉。因为我是通过pm2管理我的应用的,于是乎,我日常pm2 restart 项目,发现接口还是数据没有返回,也没有报错,于是我没有用pm2启动项目,直接node main.js启动项目,发现MySql Lock wait timeout exceeded 这个错误。

然后我又进行万能重启操作,重启mysql,先systemctl stop mysqld,然后再systemctl start mysqld,这问题就出来了,启动失败,报如下错误。

Starting mysqld (via systemctl):  Job for mysqld.service failed because the control process exited with error code. See "systemctl status mysqld.service" and "journalctl -xe" for details.
                                                           [FAILED]

然后我就看我之前写的记录mysql的文章云服务器Mysql安装配置和linux安装mysql启动不起来总结这两篇文章,果然安装记录的文章,发现了mysql启动不起来的原因,如下:

Disk is full writing './binlog.000039' (OS errno 28 - No space left on device). Waiting for someone to free space... Retry in 60 secs. Message reprinted in 600 secs

2. linux命令查看磁盘使用情况

通过上面我们已经知道,mysql启动不成功的原因是因为磁盘不足。 这里我们就先来学习下,怎么查看linux服务器磁盘空间使用情况。

2.1 使用df -h命令查看磁盘空空间

使用df -h命令查看磁盘空间,若磁盘空间不足则清理(当然这是我解决之后的截图,之前的磁盘满的情况忘了截图)。


Snipaste_2020-07-26_17-39-23.png

2.2 du的用法

du命令用来查看目录或文件所占用磁盘空间的大小。常用选项组合为:du -sh

du常用的选项:
  -h:以人类可读的方式显示
  -a:显示目录占用的磁盘空间大小,还要显示其下目录和文件占用磁盘空间的大小
  -s:显示目录占用的磁盘空间大小,不要显示其下子目录和文件占用的磁盘空间大小
  -c:显示几个目录或文件占用的磁盘空间大小,还要统计它们的总和
  --apparent-size:显示目录或文件自身的大小
  -l :统计硬链接占用磁盘空间的大小
  -L:统计符号链接所指向的文件占用的磁盘空间大小
du -lh --max-depth=1: 查看当前目录下一级子文件和子目录占用的磁盘容量。
du -h -x --max-depth=1:查看哪个目录占用过高
du -sh * | sort -n 统计当前文件夹(目录)大小,并按文件大小排序
du -sk filename 查看指定文件大小

3. 查看占用空间大的文件

然后用du命令查看linux文件占用磁盘大小情况。


Snipaste_2020-07-26_17-44-31.png

然后我们查到原因了,是mysql文件夹里面就占用了25G磁盘,总共磁盘才40G,然后在进入mysql文件夹查看


Snipaste_2020-07-26_17-47-07.png

发现binglog之类的文件竟然达到了20多G。

binlog是什么呢?

Mysql Binlog是二进制格式的日志文件,但是不能把binlog文件等同于OS系统某目录下的具体文件,这是狭隘的。Binlog是用来记录Mysql内部对数据库的改动(只记录对数据的修改操作),主要用于数据库的主从复制以及增量恢复。

然后我们知道这写文件主要是记录对数据的修改操作,主要用于数据库的主从复制,但是我的应用并没有用到主从复制,所以是可以删除的。

4. mysql的binlog安全删除

默认情况下mysql会一直保留mysql-bin文件,这样到一定时候,磁盘可能会被撑满,这时候是否可以删除这些文件呢,是否可以安全删除,是个问题。

首先要说明一下,这些文件都是mysql的日志文件,如果不做主从复制的话,基本上是没用的,虽然没用,但是不建议使用rm命令删除,这样有可能会不安全,正确的方法是通过mysql的命令去删除。

我们登录mysql之后,使用命令

mysql> reset master;
Query OK, 0 rows affected (3 min 37.65 sec)

其实关键的命令就是reset master;这个命令会清空mysql-bin文件。

另外如果你的mysql服务器不需要做主从复制的话,建议通过修改my.cnf文件,来设置不生成这些文件,只要删除my.cnf中的下面一行就可以了。

log-bin=mysql-bin

如果你需要复制,最好控制一下这些日志文件保留的天数,可以通过下面的配置设定日志文件保留的天数:

expire_logs_days = 7

表示保留7天的日志,这样老日志会自动被清理掉。

另外的方法

4.1 手动清理binlog

① 查看主库和从库正在使用的binlog是哪个文件

show master status\G 
show slave status\G  \

② 在删除binlog日志之前,首先对binlog日志备份,以防万一
开始动手删除binlog:

purge master logs before'2016-09-01 17:20:00'; //删除指定日期以前的日志索引中binlog日志文件

purge master logs to'mysql-bin.000022'; //删除指定日志文件的日志索引中binlog日志文件

注意:
时间和文件名一定不可以写错,尤其是时间中的年和文件名中的序号,以防不小心将正在使用的binlog删除!!!

切勿删除正在使用的binlog!!!

使用该语法,会将对应的文件和mysql-bin.index中的对应路径删除。

4.2 通过设置binlog过期的时间,使系统自动删除binlog文件

这种就是类似上面的expire_logs_days = 7

mysql> show variables like 'expire_logs_days'; 
+------------------+-------+ 
| Variable_name  | Value | 
+------------------+-------+ 
| expire_logs_days |   0  | 
+------------------+-------+ 
mysql> set global expire_logs_days = 30;    #设置binlog多少天过期
————————————————

注意:
过期时间设置的要适当,对于主从复制,要看从库的延迟决定过期时间,避免主库binlog还未传到从库便因过期而删除,导致主从不一致!!!

通过上面的方法之后,我们再一次查看磁盘使用情况,发现删除binlog之后,足足多出了一半以上的磁盘空间,开心。

5. mysql扩展

5.1 innodb_file_per_table 的简要说明

在很久很久以前也就是说还没有innodb_file_per_table 的那个年代,所有的innodb表的数据都是保存在innodb系统表空间中的,

在有了innodb_file_per_table参数后innodb可以把每个表的数据单独保存。单独保存有两方面的优势一个是方便管理,二个是提长性能。

5.2 mysql 引用innodb_file_per_table是为了解决什么问题

在没有innodb_file_per_table之前所有的innodb表的数据都是统一保存到,innodb系统表空间文件中的,如果想让mysql的行为

与innodb_file_per_table还没有引入时的行为一致,那么把innodb_file_per_table设置为OFF就行。

1、由于数据都统一保存到innodb系统表空间文件中,在drop table ,truncate table后表空间文件并不会进行收缩,也就是说表空间文件所占的磁盘空间并不会因为drop table , truncate table 而释放。

2、对于mysql来说alter table 的过程大概可以概括为 1)根据alter table 的指示创建出一张新的表 . 2)把老表的数据插入表新表中3)删了老表. 4)把新表的表名字重命名成老表的名字;当然如今的mysql已经有inplace对上面的过程进行优化了,不过并不是所有的alter table 都支持inplace,更多关于inplace的问题在此不表了。还是回到alter table 的第2)步 由这里可以看出系统表空间是要增大的(理由是:创建了新的表,又在向新的表中插入数据) 所以啊alter table 会导致系统表空间的进一步加大。

3、在linux系统中不允许并行的对一个文件进行写入(innodb_flush_method=O_DIRECT的情况下是这样的),这可能成为一个性能问题

4、对于使用innodb_file_per_table=ON的情况下,默认创建出来的ibd文件的格式是Barracuda,在这个文件格式下innodb数据行的格式就可以设置为compressed 或 dynamic 格式了。compressed 提供压缩功能节约空间,dynamic能优化对blob,text这样的数据类型的存储以提升性能。

5.3 Mysql删除数据后磁盘空间未释放的解决办法

官方推荐使用 OPTIMIZE TABLE命令来优化表,该命令会重新利用未使用的空间,并整理数据文件的碎片。

语法如下:

OPTIMIZE [LOCAL | NO_WRITE_TO_BINLOG] TABLE tbl_name [, tbl_name] ...

注:该命令将会整理表数据和相关的索引数据的物理存储空间,用来减少占用的磁盘空间,并提高访问表时候的IO性能。但是,具体对表产生的影响是依赖于表使用的存储引擎的。该命令对视图无效。

执行语句:show table status like 'table_name'查看表信息


Snipaste_2020-07-26_18-11-39.png

查询结果中:

Index_length 代表索引的数量
Data_free 代表碎片数量

然后执行下面命令进行优化整理:

mysql > optimize table table_name

如果之前的碎片数量多,执行时间可能会久一点,执行结束后出现下面框内的数据则优化成功。

注意事项:
由于命令optimize会进行锁表操作,所以进行优化时要避开表数据操作时间,避免影响正常业务的进行。

MySQL5.7已经推荐对于InnoDB的table使用 alter table table_name engine=innodb;语句的方式来进行表碎片优化。

6. 相关文章

  • 云服务器Mysql安装配置
  • linux安装mysql启动不起来总结

你可能感兴趣的:(记Linux服务器磁盘空间不足解决之路)