最近遇到一个故障和磁盘满有关系,并且同事也发现经常有磁盘满导致操作hang住无响应的情况,于是抽时间研究了一下这2种情况。

 

一、磁盘满了之后MySQL会做什么?

我们看下官方的说法

When a disk-full condition occurs, MySQL does the following: 
  * It checks once every minute to see whether there is enough space to write the current row. If there is enough space,it continues as if nothing had happened.
  * Every 10 minutes it writes an entry to the log file, warning about the disk-full condition.

其实MySQL本身并不会做任何操作,如官方文档说说,只会每分钟check一次是否有空闲空间,并且10分钟写一次错误日志。

但是再次期间由于磁盘满了,意味着binlog无法更新,redo log也无法更新,所有buffer pool中的数据无法被flush上,如果不幸的服务器重启,或者实例被kill了,那必然会造成数据丢失,这几乎是一定的。所以,处理磁盘满的问题最好是先释放出来一定空间让dirty数据刷新下来。

 

二、磁盘满了为什么会导致操作hang住?

1、select

  首先经过经验和实际测试,select操作不会由于磁盘满导致问题,也就是所有select操作都会正常运行。

2、insert

  经过不通的测试发现,当磁盘满了之后,并不是第一个insert就卡住,而是会在n个之后出现卡住的情况。

  通过查看error日志,发现卡住现象和刷磁盘的操作有关系。

[ERROR] /usr/local/mysql-5.1.42/libexec/mysqld: Disk is full writing './test/cj_webex.MYD'

[ERROR] /usr/local/mysql-5.1.42/libexec/mysqld: Disk is full writing './mysql-bin.000017'

  为了验证推论是否正确,我们将sync_binlog设置为1,在这种情况下,insert第一条就卡住了,并且error log中直接报错提示写binlog失败。看来卡住确实和刷磁盘有关系。

  目前已知和刷磁盘有关系的参数有3个,分别是sync_binlog,innodb_flush_log_tr_commit,和duoblewrite。

3、show slave status

LOCK_active_mi锁,然后锁上mi->data_lock,但是由于磁盘满了无法将io_thread中的数据写入到relay log中,导致io_thread持有mi->data_lock锁,这就导致了死锁。

  所以,这就导致在磁盘满的情况下,执行show slave status操作会卡住。

4、show status

LOCK_status,而由于status状态中包含slave status,所以还需要锁上LOCK_active_mi。如果限制性了show slave status,这时候由于mi->data_lock死锁问题,导致io_thread不会释放LOCK_active_mi锁。这时候就导致show status和show slave status争抢同一把LOCK_active_mi锁,也形成了死锁。

  所以,在磁盘满的情况下,如果先执行show slave status,后执行show status,连个操作都会卡住。