乐趣区

关于数据库:磁盘占用高问题如何排查三步教你搞定

作者简介:杨嘉力,OceanBase 开源内核高级工程师。

通常状况下,数据库对磁盘的占用量会随着业务的接入工夫和业务数据量大增而一直回升,导致磁盘空间有余,进而产生数据无奈写入、数据库无奈重启等问题。这时咱们就须要排查问题本源,使磁盘得以安稳运行。本文以 OceanBase 开源 3.x 版本为例,分享磁盘问题的排查办法,心愿对你有所帮忙。

排查概括

磁盘问题排查通常包含两方面,一方面,排查磁盘数据 required_size 和理论数据 data size 的大小,如果 required_size 比 data size 要大很多,那么很可能是多版本问题;另一方面,要排查宏块使用率,如果使用率低,排查是不是宏块重用的问题。
在正式进入排查阶段前,让咱们先理解排查过程中波及的虚构表和排查指令。
排查过程中波及的虚构表和相应的注意事项如下。

  • __all_virtual_meta_table (确认 reqiured_size 统计的是不是最初保留在磁盘的数据长度)
  • __all_virtual_table_mgr(查看 sstable 所占用的空间)
  • __all_virtual_tenant_partition_meta_table(查看租户级的 required_size 和 data_size)
  • __all_virtual_sys_variable
  • __all_acquired_snapshot(查看须要的快照表)

波及的排查指令如下。

  • 查看压缩算法:show parameters like ‘%compress%’;
  • 查看建表语句(确认应用的压缩算法):show create table xxx\G

当初让咱们开始排查磁盘占用高的问题。

排查过程三步走

如果你相熟 OceanBase 数据库存储架构,那么你会晓得,OceanBase 的数据文件由多个 Memable、多个 Minor SSTable 及一个(或没有)Major SSTable 组成。因而,在排查过程中,咱们能够遵循下述的“三步走”策略进行排查。
第一步,咱们要查看某台机器的 table_type 大于 0(所有 sstable)的应用状况,输出指令如下:

select /*+ parallel(30) */ svr_ip, table_type, sum(size) / 1024 / 1024 / 1024 as size_G from __all_virtual_table_mgr where table_type > 0 group by 1,2 order by 3 desc;

从查问的结果显示(见图 1),次要问题是基线(major sstable)占用大,但 data_size 和 require size 没匹配(见图 2),可能还有多个版本。_

_

图 1 查问某台机器 table_type 大于 0 的应用状况的后果
 

图 2 data_size 和 require size 没匹配

如果你不分明 table_type 的所有类型,能够参考以下列表。

enum TableType {
    MEMTABLE = 0,
    MAJOR_SSTABLE = 1,
    MINOR_SSTABLE = 2,  // obsoleted type after 2.2
    TRANS_SSTABLE = 3,  // new table type from 3.1
    MULTI_VERSION_MINOR_SSTABLE = 4,
    COMPLEMENT_MINOR_SSTABLE = 5,            // new table type from 3.1
    MULTI_VERSION_SPARSE_MINOR_SSTABLE = 6,  // reserved table type
    MINI_MINOR_SSTABLE = 7,
    RESERVED_MINOR_SSTABLE = 8,
    MAX_TABLE_TYPE
  };

摸清了问题方向和 table_type 的所有类型后,咱们进入 第二步,排查基线数据 major sstable 波及的版本,指令如下:

select /*+ parallel(30) */ svr_ip, version, sum(size) / 1024 / 1024 / 1024 as size_G from __all_virtual_table_mgr where table_type = 1 group by 1,2 order by 3 desc;__

__
执行后果(见图 3)显示集群中保留了基线的多版本数据,而且有大量的历史版本,导致 required size 变大,起因可能是多版本保留位点没有推。
 

_

图 3 基线数据 major sstable 波及版本的排查后果
 
此时,咱们输出 select * from __all_virtual_sys_variable where name like ‘%undo_rete%’ 进行查问,查问后果见图 4。

1       undo_retention  2022-06-14 20:50:15.821272  2022-06-14 20:50:15.821272  5  0  specifies (in seconds) the low threshold value of undo retention.  1  0  4294967295
1001    undo_retention  2022-06-14 20:58:07.599412  2022-06-14 20:58:07.599412  5  0  specifies (in seconds) the low threshold value of undo retention.  1  0  4294967295
1002    undo_retention  2022-06-22 18:00:03.182527  2022-06-22 18:00:03.182527  5  0  specifies (in seconds) the low threshold value of undo retention.  1  0  4294967295

图 4 查问多版本保留位点的后果
 
为什么会保留这些版本呢,咱们持续找一个 svr ip 剖析,执行 select * from _all_virtual_table_mgr where svr_ip = xxx’ and version = 100 limit 3; 后果(见图 5)显示,ip=xxx 机器下存在多个索引表,因为索引表的创立须要依赖主表的 snapshot_version,会 hold 住 snapshot_version 数据。因而咱们要查看某个索引表的详细情况。

_

图 5 svr ip 剖析后果
 
上面持续查问某个 index_id 下的 snapshot_version 版本,执行如下命令后得出图 6 所示后果:

select * from __all_virtual_table_mgr where svr_ip = xxx and index_id = 1101710651081814 and partition_id = 5 order by snapshot_version asc;

图 6 查问某个 index_id 下的 snapshot_version 版本所示后果
 
再进一步查问,执行命令为 select * from _all_acquired_snapshot; 得出后果见图 7,咱们能够看到保留的 snapshot 快照比拟多,因为合并较频繁、叠加建索引工夫较久,所以须要保留多版本,故而留下来太多的 major 版本。

_

图 7 snapshot 快照

 
第三步,咱们须要排查为什么保留了如此多的 snapshot 快照。

首先排查建索引历史工作和状态,执行命令:__all_virtual_sys_task_status,后果如图 8 所示。_

_

图 8 排查建索引历史工作和状态

咱们从图 8 中能够失去的信息是,命名为”1101710651081782“的表保留了两个 snapshot,因为新建索引对 snapshort 有依赖,可能导致 snapshort 始终不被删除,因而咱们要排查 1101710651081782 table 的 index_status 状态,执行命令:select table_id, index_status from __all_virtual_table where data_table_id = 1101710651081782; 后果见图 9.

图 9 1101710651081782 table 的 index_status 状态
 
须要留神的是,图 9 中的 table_id 是指索引表的 table_id,data_table_id 是指主表的 table_id。从此处看 index_status=2,示意索引是 avaliable 的,实践上能够排除建索引失败导致的 snapshot 保留的问题。
接下来能够查看所有在__all_acquired_snapshot 快照表中的 table 的建索引状态,排查所有在 snapshot 表中的 table 是否存在建索引异样,执行命令:select table_id, index_status from __all_virtual_table where data_table_id in (select table_id from __all_acquired_snapshot); 得出后果如图 10 所示。

图 10 所有在 snapshot 表中的 table 状态查问后果
咱们联合图 10 中显示的查问后果与 index_status 的取值(如下),能够排除是新建索引失败导致的 snapshot 未被删除,进而导致快照点未开释,因而 major merge 的增多加剧了磁盘空间的占用。

enum ObIndexStatus {
  // this is used in index virtual table:__index_process_info:
  // means the table may be deleted when you get it
  INDEX_STATUS_NOT_FOUND = 0,
  INDEX_STATUS_UNAVAILABLE = 1,
  INDEX_STATUS_AVAILABLE = 2,
  INDEX_STATUS_UNIQUE_CHECKING = 3,    // not used anymore
  INDEX_STATUS_UNIQUE_INELIGIBLE = 4,  // not used anymore
  INDEX_STATUS_INDEX_ERROR = 5,
  INDEX_STATUS_RESTORE_INDEX_ERROR = 6,
  INDEX_STATUS_UNUSABLE = 7,
  INDEX_STATUS_MAX = 8,
};

到此,咱们的排查与剖析就告一段落了,根本起因曾经明确。如何解决呢?
解决办法很简略,就是将__all_acquired_snapshot 表格的记录删掉,使后台任务删除__all_acquired_snapshot 的快照即可。指令为:delete * from __all_acquired_snapshot。
然而,事件并未完结!

OceanBase 集群磁盘占用异样排查

当你操作完上述三步,你发现 OceanBase 集群的磁盘空间占用为 207TB,磁盘占用仍然处于高位。这显然不合乎失常状况,就须要持续定位。
排查统计办法的问题,将 OceanBase 集群的数据通过导入工具,从 MySQL 集群中导出,并从 information_schema.tables 汇总的所有非 MySQL 原生表的数据量看,数据量失常的状况下存储却收缩近一倍,从 create table 语句中能够明确用户曾经开了压缩,在排除数据压缩的问题后,还有一个可能的起因是宏块中存在较多空间未被应用。
咱们执行以下命令查看所有宏块的空间应用状况:
select /+ parallel(30) / 2*count(1)/1024 as size_g, sum(occupy_size)/1024/1024/1024 as occupy_G from __all_virtual_partition_sstable_macro_info where tenant_id = 1001;
从图 11 显示的查问后果可见,宏块空间未满,残余 70TB。

图 11 宏块的空间应用状况
 
为什么会存在 70TB 如此大的宏块磁盘空间未被应用?个别状况下,做一次 major merge 后,存储系统会将 mini sstable、minor sstable 与 major 基线做一次全量合并,合并过程重整宏块以紧凑宏块空间,增大宏块空间利用率。因而,咱们能够查问是不是基线 major sstable 未做合并或合并时未对宏块进行重整,导致了宏块空间使用率低的问题。在此之前,咱们还须要排除上面两种 mini sstable 和 minor sstable 宏块多造成磁盘应用高的烦扰。
第一,确认有没有转储对宏块应用的影响(排查是否频繁转储生成 mini sstable),命令如下:
select /+ parallel(30) / table_type, sum(size) / 1024 / 1024 / 1024 as size_G from __all_virtual_table_mgr where table_type > 0 group by 1 order by 2 desc;
排查后果如图 12 所示,可见磁盘空间次要被 major sstable 占用。
 

图 12 排查是否频繁转储生成 mini sstable 的后果
 
第二,确认有没有多个不同版本的 major(排查是否有多版本 major sstable 导致磁盘应用高),命令如下:
select /+ parallel(30) / version, sum(size) / 1024 / 1024 / 1024 as size_G from __all_virtual_table_mgr where table_type =1 group by 1 order by 2 desc;
排查后果见图 13,从中可知,只有一个 114 版本的 major sstable,排除多版本的影响。
 _*

*_

图 13 排查是否有多版本 major sstable 导致磁盘应用高的后果
 
排除了 mini sstable 和 minor sstable 宏块多造成磁盘应用高的烦扰后,咱们持续排查所有表中 data_version=114,tenant_id=1001 的 sstable 宏块应用状况,命令如下:

select  /*+ parallel(100) */ table_id, count(1), 2*count(1)/1024 as size_g, sum(occupy_size)/1024/1024/1024 as occupy_G from __all_virtual_partition_sstable_macro_info where data_version = 114 and tenant_id = 1001 group by 1 order by 2 desc limit 30;_

_
从排查后果(见图 14)中剖析,table_id 为 1100611139454851 的宏块空间利用率很低。650/4000,不到 1 /7。当初咱们根本能够确定是宏块空间使用率低导致的数据收缩。
 _

_

图 14 所有表中 data_version=114,tenant_id=1001 的 sstable 宏块应用状况
 
到此,磁盘空间收缩(收缩空间 207TB,理论空间是 140TB)的起因曾经确定是索引宏块没有写满导致的。
 
解决办法是进行数据重整,能够批改参数:alter table tablename set progressive_merge_num = 1,而后执行 alter system major freeze,合并完结后,设置 progressive_merge_num = 0(以上操作仅针对磁盘放大的几张索引所在的表)。数据重整后,磁盘空间开释。
 

总结

总的来说,个别须要长久化的数据库系统必然须要占用磁盘空间,而磁盘占用大小取决于用户写入的数据,能够简略了解是一个线性反比关系。另外,呈现不合乎预期的磁盘占用状况,比方磁盘数据要比理论数据要大得多时,倡议先从根底的外部表排查是否存在多版本,包含索引表的依赖版本,最初排除是否宏块利用率低导致的起因,根本就能定位问题并取得解决思路。

退出移动版