节后第一天上班,生产环境突然告警:MySQL服务无法写入数据。运维同事第一时间检查磁盘空间,df -lh命令显示还有30%剩余空间,但MySQL错误日志却持续报错"Disk is full writing"。这种看似矛盾的状况让整个团队陷入困惑。
我接手这个问题后,首先确认了几个关键信息点:
执行df -i命令后发现,数据分区inode使用率已达100%。这是典型的"磁盘有空间但无法写入"场景。MySQL在创建新表或写入临时文件时需要消耗inode,当inode耗尽时即使有剩余空间也会报磁盘满错误。
为什么小文件会耗尽inode?
使用tune2fs -l /dev/sdb1检查发现,ext4文件系统默认保留了5%的空间给root用户。这意味着虽然df显示有30%空间,但实际上普通用户可用的只有25%。当MySQL进程以mysql用户运行时,可能提前触达这个限制。
bash复制# 查找占用inode最多的目录
find /var/lib/mysql -xdev -printf '%h\n' | sort | uniq -c | sort -k1 -n
# 清理过期binlog
PURGE BINARY LOGS BEFORE DATE_SUB(NOW(), INTERVAL 7 DAY);
# 删除临时文件
rm -f /tmp/ib* /var/lib/mysql/#sql_*
bash复制# 将预留空间比例降至1%
tune2fs -m 1 /dev/sdb1
# 立即生效无需重启
mount -o remount /var/lib/mysql
在现有磁盘空间监控基础上增加inode监控项:
bash复制# 每日检查脚本
INODE_USAGE=$(df -i /var/lib/mysql | awk 'NR==2 {print $5}' | tr -d '%')
[ $INODE_USAGE -gt 80 ] && alert "MySQL inode usage critical: $INODE_USAGE%"
ini复制# my.cnf 调整
[mysqld]
tmp_table_size=64M
max_heap_table_size=64M
expire_logs_days=7
innodb_autoextend_increment=64
设置cron定时任务:
bash复制0 3 * * * find /var/lib/mysql -name "#sql_*" -mtime +1 -exec rm -f {} \;
0 4 * * * mysql -e "PURGE BINARY LOGS BEFORE DATE_SUB(NOW(), INTERVAL 7 DAY);"
这次事故暴露出几个关键问题:
特别注意事项:
在后续的服务器规划中,建议: