问题现象
用户使用火山引擎 RDS for MySQL 高可用版实例,整个集群具有一个主节点,一个备节点,三个只读节点,发现其中一个只读节点磁盘占用率高,我们该如何排查此类问题?
排查步骤
查看碎片率
查看每个数据库占用的空间大小以及碎片大小:
SELECT
SUBSTRING_INDEX( it.NAME, '/', 1 ) AS table_schema,
ROUND( SUM( its.allocated_size ) / 1024 / 1024 / 1024, 2 ) "size in GB",
ROUND( SUM( t.data_free ) / 1024 / 1024 / 1024, 2 ) "fragmented size in GB"
FROM
information_schema.innodb_tables it
INNER JOIN information_schema.innodb_tablespaces its ON it.space = its.space
INNER JOIN information_schema.innodb_tablestats istat ON istat.table_id = it.table_id
INNER JOIN information_schema.TABLES t ON t.table_schema = SUBSTRING_INDEX( it.NAME, '/', 1 )
AND t.table_name = SUBSTRING_INDEX( it.NAME, '/', - 1 )
GROUP BY 1
ORDER BY 2 DESC;
查看临时文件
临时文件的使用主要有如下场景:
- 在 DDL 过程中创建的临时文件。
- 优化器创建的临时文件,复杂的 SQL 语句在引擎层需要依赖隐式临时表来辅助计算,在 Server 层可能也会创建临时文件来存储临时结果,比如 order by 操作。
- binlog 产生的临时文件。
运行如下语句查看临时表空间占用情况:
mysql> SELECT file_name, tablespace_name, table_name, engine, index_length, total_extents, extent_size from information_schema.files WHERE file_name LIKE '%ibt%';
查看文件大小
在 MySQL 5.7 及更高版本或 MySQL 8.0 及更高版本中获得文件大小
mysql> SELECT file_name, tablespace_name, table_name, engine, index_length, total_extents, extent_size from information_schema.files ;
主库输出结果如下: 从库输出结果: 从结果上来看,此只读节点上,undo 表空间文件空间占用异常,总大小为 TOTAL_EXTENTS x EXTENT_SIZE,约为 25GB。需要排查 undo 表空间异常的问题。
根因描述
Undo Log 是 InnoDB 十分重要的组成部分,主要作用为:
- 并发控制(Concurrency Control)
- 故障恢复(Crash Recovery)
我们怀疑在此只读节点上存在长时间未提交的 SQL,阻塞了 undo 的 purge 操作。 查看 show engine innodb status:
------------
TRANSACTIONS
------------
Trx id counter 1139855969
Purge done for trx's n:o < 1077956438 undo n:o < 3 state: running but idle
History list length 29096470
使用 show full processlist 查看当前的连接信息:
mysql> show full processlist;
+----------+--------------------+----------------------+--------------------+------------------+----------+---------------+-----------------------+
| Id | User | Host | db | Command | Time | State | Info |
+----------+--------------------+----------------------+--------------------+------------------+----------+---------------------------------------+
| 36891633 | appa_rds_admin | 172.xx.xxx.xxx:xxxxx | apply | Execute | 765967 | executing | select count(*)...... |
因为 MySQL InnoDB 使用了 Undo Log 中记录的历史版本数据来满足 MVCC 的需求,存在长时间未执行完的 SQL / 未提交的事务,会阻塞 undo 的清理动作。
解决方案
在此场景中,只需要 kill 掉次长时间运行的 SQL,即可使 MySQL 回收 undo 表空间。在后续的使用中,我们建议:
- 老生常谈的,避免大事务,长事务,事务要及时进行提交,优化 SQL 语句。
- 可以在参数组中设置 max_execution_time,超出此执行后自动 kill SQL。此参数设定需要依据业务场景来定。
参考文档