Docker部署出现MySQL磁盘占用100%情况
情景
MySQL的binlog文件配置出错导致磁盘占用完的问题
由于使用Docker部署MySQL,然后未配置一些相关设置,导致再长久的使用中,已经让MySQL占用磁盘达到了恐怖的31G
sudo du -h --max-depth=1 / 2>/dev/null | sort -hr | head -n 10
# 扫描根目录下占用空间最大的前10个目录
39G /
34G /usr
3.8G /var
1.3G /snap
102M /boot
6.3M /etc
1.1M /run
516K /root
68K /tmp
40K /home
sudo du -sh /var/lib/docker/*
# 检查 Docker 存储目录占用
5.9M /var/lib/docker/buildkit
4.0K /var/lib/docker/containers
4.0K /var/lib/docker/engine-id
6.2M /var/lib/docker/image
92K /var/lib/docker/network
4.0K /var/lib/docker/nuke-graph-directory.sh
2.2G /var/lib/docker/overlay2
16K /var/lib/docker/plugins
4.0K /var/lib/docker/runtimes
4.0K /var/lib/docker/swarm
4.0K /var/lib/docker/tmp
28K /var/lib/docker/volumes
sudo du -sh /usr/app/mysql/data
31G /usr/app/mysql/data
由上面的检测情况就知道MySQL已经爆炸了
Linux的du命令解析
du命令用来查看目录或文件所占用磁盘空间的大小。常用选项组合为:du -sh du常用的选项: -h:以人类可读的方式显示 -a:显示目录占用的磁盘空间大小,还要显示其下目录和文件占用磁盘空间的大小 -s:显示目录占用的磁盘空间大小,不要显示其下子目录和文件占用的磁盘空间大小 -c:显示几个目录或文件占用的磁盘空间大小,还要统计它们的总和 --apparent-size:显示目录或文件自身的大小 -l :统计硬链接占用磁盘空间的大小 -L:统计符号链接所指向的文件占用的磁盘空间大小 du -sh : 查看当前目录总共占的容量。而不单独列出各子项占用的容量 du -lh --max-depth=1 : 查看当前目录下一级子文件和子目录占用的磁盘容量。 du -sh * | sort -n 统计当前文件夹(目录)大小,并按文件大小排序 du -sk filename 查看指定文件大小
使用ls查看Mysql的文件情况,发现有一对binlog文件,并且每个文件大小都超过了1G
root@main-blog:/usr/app/mysql/data# ls
auto.cnf binlog.000060 binlog.000065 binlog.000070 binlog.000075 binlog.000080 binlog.000085 binlog.000090 client-cert.pem ibdata1 mysql.sock server-cert.pem
binlog.000056 binlog.000061 binlog.000066 binlog.000071 binlog.000076 binlog.000081 binlog.000086 binlog.index client-key.pem '#innodb_redo' mysql_upgrade_history server-key.pem
binlog.000057 binlog.000062 binlog.000067 binlog.000072 binlog.000077 binlog.000082 binlog.000087 blog '#ib_16384_0.dblwr' '#innodb_temp' performance_schema sys
binlog.000058 binlog.000063 binlog.000068 binlog.000073 binlog.000078 binlog.000083 binlog.000088 ca-key.pem '#ib_16384_1.dblwr' mysql private_key.pem undo_001
binlog.000059 binlog.000064 binlog.000069 binlog.000074 binlog.000079 binlog.000084 binlog.000089 ca.pem ib_buffer_pool mysql.ibd public_key.pem undo_002
root@main-blog:/usr/app/mysql/data# du -sh * | sort -n
0 mysql.sock
1.1G binlog.000059
1.1G binlog.000060
1.1G binlog.000061
1.1G binlog.000062
1.1G binlog.000063
1.1G binlog.000064
1.1G binlog.000065
1.1G binlog.000066
1.1G binlog.000067
1.1G binlog.000068
1.1G binlog.000070
1.1G binlog.000071
1.1G binlog.000072
1.1G binlog.000073
1.1G binlog.000074
1.1G binlog.000075
1.1G binlog.000076
1.1G binlog.000080
1.1G binlog.000081
1.1G binlog.000082
1.1G binlog.000084
1.1G binlog.000085
1.1G binlog.000086
1.1G binlog.000087
1.1G binlog.000088
1.1G binlog.000089
66M binlog.000083
697M binlog.000069
825M binlog.000077
891M binlog.000056
944M binlog.000058
973M binlog.000090
为什么
为什么会有大量的binlog文件?
- MySQL 默认行为:
- binlog 用于记录数据库的修改操作(如增删改),支持主从复制和数据恢复。
- 默认情况下,如果未配置过期策略,binlog 会一直保留,文件数量会不断增加。
- 大事务操作:
- 批量插入、大批量更新或长时间未提交的事务会导致单个 binlog 文件急剧增大。
- 复制延迟:
- 如果使用主从复制,从库长时间未同步会导致主库保留大量 binlog 文件。
怎么解决
怎么解决大量binlog文件恢复系统?
- 方式一:通过 MySQL 命令清理
连接到 MySQL 容器,执行以下命令清理 早于指定时间或指定文件之前 的 binlog:
docker exec -it blog_mysql /bin/bash # 进入容器内部
mysql -u root -p # 登录
SHOW BINARY LOGS; # 查看所有 binlog 文件列表
+---------------+------------+-----------+
| Log_name | File_size | Encrypted |
+---------------+------------+-----------+
| binlog.000075 | 1074323858 | No |
| binlog.000076 | 1074323858 | No |
| binlog.000077 | 864701254 | No |
| binlog.000078 | 181 | No |
| binlog.000079 | 181 | No |
| binlog.000080 | 1074326012 | No |
| binlog.000081 | 1074323858 | No |
| binlog.000082 | 1074323858 | No |
| binlog.000083 | 68783098 | No |
| binlog.000084 | 1074324790 | No |
| binlog.000085 | 1074323858 | No |
| binlog.000086 | 1074323858 | No |
| binlog.000087 | 1074323858 | No |
| binlog.000088 | 1074323858 | No |
| binlog.000089 | 1074323858 | No |
| binlog.000090 | 1018642405 | No |
| binlog.000091 | 22927797 | No |
+---------------+------------+-----------+
17 rows in set (0.04 sec)
SHOW BINARY LOG STATUS; # 查看当前正在使用的 binlog 文件
+---------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+---------------+----------+--------------+------------------+-------------------+
| binlog.000091 | 36029305 | | | |
+---------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)
-- 删除早于 7 天的 binlog
PURGE BINARY LOGS BEFORE NOW() - INTERVAL 7 DAY;
-- 或删除指定文件名之前的 binlog(保留最新文件)
PURGE BINARY LOGS TO 'binlog.000090'; -- 删除 000090 之前的所有 binlog
- 方式二:直接删除文件(需谨慎)
直接删除文件可能导致数据不一致,仅限紧急情况:
# 进入 MySQL 数据目录
cd /usr/app/mysql/data
bash
# 删除旧的 binlog 文件(保留最新的 3-5 个)
sudo rm binlog.000056 binlog.000057 ... # 手动指定要删除的文件名
怎么预防
- 配置 binlog 自动清理策略
修改 MySQL 配置文件(my.cnf
或通过 Docker 环境变量),设置 binlog 过期时间和最大文件大小:
[mysqld]
# 设置 binlog 过期时间为 3 天(按需调整)
expire_logs_days = 3
# 或 MySQL 8.0+ 使用时间单位(推荐)
binlog_expire_logs_seconds = 259200 # 3天(3*24*3600)
# 限制单个 binlog 文件大小(默认 1G,可调整为 100M-500M)
max_binlog_size = 100M
- Docker 部署的配置方式
在 docker run
命令中直接传递参数:
docker run -d \
--name mysql \
-v mysql_data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=your_password \
mysql:8.0 \
--expire_logs_days=3 \
--max_binlog_size=100M
- 排查大事务问题
如果某个 binlog 文件异常大(如 1.1GB),可能是由大事务导致。检查慢查询日志:
-- 查看未提交的长事务
SELECT * FROM information_schema.INNODB_TRX\G
-- 查看 binlog 事件详情(需启用 GTID 或知道具体 binlog 文件)
SHOW BINLOG EVENTS IN 'binlog.000071' LIMIT 10;
+---------------+--------+----------------+-----------+-------------+--------------------------------------+
| Log_name | Pos | Event_type | Server_id | End_log_pos | Info |
+---------------+--------+----------------+-----------+-------------+--------------------------------------+
| binlog.000091 | 4 | Format_desc | 1 | 127 | Server ver: 9.1.0, Binlog ver: 4 |
| binlog.000091 | 127 | Previous_gtids | 1 | 158 | |
| binlog.000091 | 158 | Anonymous_Gtid | 1 | 238 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS' |
| binlog.000091 | 238 | Query | 1 | 330 | BEGIN |
| binlog.000091 | 330 | Table_map | 1 | 418 | table_id: 85 (blog.article) |
| binlog.000091 | 418 | Update_rows | 1 | 242984 | table_id: 85 flags: STMT_END_F |
| binlog.000091 | 242984 | Table_map | 1 | 243072 | table_id: 85 (blog.article) |
| binlog.000091 | 243072 | Update_rows | 1 | 387686 | table_id: 85 flags: STMT_END_F |
| binlog.000091 | 387686 | Table_map | 1 | 387774 | table_id: 85 (blog.article) |
| binlog.000091 | 387774 | Update_rows | 1 | 442598 | table_id: 85 flags: STMT_END_F |
+---------------+--------+----------------+-----------+-------------+--------------------------------------+
10 rows in set (0.01 sec)
优化应用逻辑,避免以下操作:
-
单条 SQL 操作大量数据(如
DELETE FROM large_table
)。 -
未提交的事务长时间运行。
- 验证结果
清理后检查磁盘空间:
df -h
查看当前 binlog 状态:
SHOW BINARY LOGS; -- 列出所有 binlog 文件
SHOW VARIABLES LIKE 'binlog_expire_logs_seconds%'; -- 检查过期策略
配置文件
[mysqld]
server-id=1 # 必须设置
pid-file = /var/run/mysqld/mysqld.pid
socket = /var/run/mysqld/mysqld.sock
datadir = /var/lib/mysql
secure-file-priv= NULL
#最大链接数
max_connections=1024
#是否对sql语句大小写敏感,1表示不敏感
lower_case_table_names=1
log_bin_trust_function_creators=1
#启用log-bin
log-bin=mysql-bin
#设置binlog日志格式
binlog_format=mixed
# 设置 binlog 过期时间为 3 天(按需调整)
# expire_logs_days = 3
# MySQL 8.0+ 使用时间单位(推荐)
binlog_expire_logs_seconds = 259200 # 3天(3*24*3600)
# 限制单个 binlog 文件大小(默认 1G,可调整为 100M-500M)
max_binlog_size = 500M
# 数据表默认时区
default-time-zone='+08:00'
# Custom config should go here
!includedir /etc/mysql/conf.d/
server-id
是 MySQL 主从复制(Replication)环境中用于 唯一标识每个实例 的核心参数。
场景 | 作用 |
---|---|
主从复制 | 主库和从库必须配置不同的 server-id ,否则复制链路会因标识冲突而中断。 |
多源复制 | 当从库需要连接多个主库时,每个主库和从库的 server-id 必须唯一,避免数据混乱。 |
组复制(Group Replication) | 在 InnoDB Cluster 或 Group Replication 中,server-id 用于节点间的唯一识别和通信。 |
Binlog 写入 | 即使未启用主从复制,若开启了 binlog(log-bin ),MySQL 也要求必须设置 server-id ,否则服务无法启动。 |
binlog_format
的三种模式详解
binlog_format
决定了 binlog 记录数据变更的方式,直接影响 数据一致性、复制安全性和日志大小。
模式 | 工作原理 | 优点 | 缺点 | 适用场景 |
---|---|---|---|---|
STATEMENT | 记录实际执行的 SQL 语句(如 UPDATE users SET age=30 WHERE id=5; )。 | 日志量小,节省存储和网络带宽。 | 某些场景下主从不一致(如使用 NOW() 、UUID() 等非确定性函数)。 | 简单业务,无复杂函数或存储过程。 |
ROW | 记录每行数据的变更细节(如 UPDATE users SET age=30 WHERE id=5; 会记录修改前后的整行数据)。 | 数据一致性高,无不确定性问题。 | 日志体积大,尤其是批量操作(如全表更新)。 | 金融等高一致性要求的业务。 |
MIXED | 混合模式:默认使用 STATEMENT ,当检测到不确定操作时自动切换到 ROW 。 | 平衡日志大小和一致性。 | 仍需处理部分潜在不一致问题。 | 常规业务,需兼顾性能和一致性。 |
查看配置文件启用情况
SHOW VARIABLES LIKE 'server_id';
SHOW VARIABLES LIKE 'binlog_format';
检查时区
-- 查看全局时区
SHOW GLOBAL VARIABLES LIKE '%time_zone%';
-- 查看当前会话时区
SHOW VARIABLES LIKE '%time_zone%';
-- 查看当前时间
SELECT NOW();