头图

OceanBase 是一个多租户的分布式数据库,统计数据量时需要考虑一台服务器上可能会有多个租户,每个租户会有多个副本。此外 OceanBase 中磁盘上的数据文件是预分配的,当我们统计数据量大小时,得找出真实数据占用的大小。我们需要考虑:

  • OceanBase 不同版本(V3、V4)的统计方式有何区别?
  • 不同级别(服务器级、租户级、表级)如何统计?

本文将总结在 OceanBase 中统计数据量大小的技巧,旨在扫清这方面的迷雾。

服务器级别

OCP 统计

OCP 上“集群总览”展示的数据量是集群中每个 OBServer 服务器的磁盘容量大小和已使用大小。通过这个信息我们可以快速知道整个集群大概的数据量,以及每台服务器上的存储是否够用。

OCP 资源水位

比如上图中 xxx.xxx.xxx.193 服务器显示的 2.5TB/16.8TB 含义如下:

  • 16.8TB:表示的是 OBServer 上用 datafile_size 或者 datafile_disk_percentage 参数指定的可以使用的存储大小,也就是 /data/1/{cluster_name}/sstable/block_file 数据文件的大小。

    • OceanBase 的数据文件是预分配的,在安装数据库后数据文件 block_file 的大小就已经预留好了,后续的写入不会改变文件大小。
  • 2.5TB:表示 block_file 数据文件中真实数据的大小,剩余都是可用空间。

磁盘统计

对应服务器上看到的磁盘使用量就是 block_file 数据文件的大小,和 OCP 上“集群总览”展示的一致:

df -h |grep /data/1
Filesystem                     Size  Used Avail Use% Mounted on
/dev/mapper/observervg-obdata   24T   17T  7.1T  71% /data/1

ll /data/1/group_x86_pt01/sstable/
total 17T
-rw-r----- 1 admin admin 17T Jan 18 01:31 block_file

视图统计

OCP 展示的数据实际上来自系统视图 __all_virtual_disk_stat,因此如果没有 OCP,也可以通过查询系统视图得到这个数据:

适用 V3、V4 版本,在 sys 租户下执行。

SELECT
  svr_ip,
  svr_port,
  total_size / 1024 / 1024 / 1024 AS total_size_GB,
  free_size / 1024 / 1024 / 1024 AS free_size_GB,
  (total_size - free_size) / 1024 / 1024 / 1024 as used_size_GB
FROM
  __all_virtual_disk_stat;
+----------------+----------+--------------------+--------------------+-------------------+
| svr_ip         | svr_port | total_size_GB      | free_size_GB       | used_size_GB      |
+----------------+----------+--------------------+--------------------+-------------------+
| xxx.xxx.xxx.193|     2882 | 17162.496093750000 | 14536.255859375000 | 2626.240234375000 |
| xxx.xxx.xxx.195|     2882 | 17162.496093750000 | 14494.105468750000 | 2668.390625000000 |
| xxx.xxx.xxx.197|     2882 | 17162.496093750000 | 14502.750000000000 | 2659.746093750000 |
+----------------+----------+--------------------+--------------------+-------------------+
3 rows in set (0.024 sec)

租户级别

单纯从数据量统计来说,租户级别会比集群级别更有意义!

租户对标的是 MySQL、Oracle 的一个实例,而集群上可能会有多个租户,多个租户可能会落在同一个服务器上。

一个 Zone 上会有一个租户所有表的完整的一份副本,因此可以根据 Zone 的维度来统计租户的总数据量大小。

适用 V3 版本,在 sys 租户下执行。

select
  zone,
  svr_ip,
  svr_port,
  sum(data_size) / 1024 / 1024 / 1024 as data_size_gb,
  sum(required_size) / 1024 / 1024 / 1024 as required_size_gb
from
  __all_virtual_meta_table
where
  tenant_id = 1001
group by
  zone,
  svr_ip,
  svr_port;
+-------+----------------+----------+-------------------+-------------------+
| zone  | svr_ip         | svr_port | data_size_gb      | required_size_gb  |
+-------+----------------+----------+-------------------+-------------------+
| zone1 | xxx.xxx.xxx.193|     2882 | 2302.406988900154 | 2601.037109375000 |
| zone2 | xxx.xxx.xxx.195|     2882 | 2302.406988900154 | 2601.037109375000 |
| zone3 | xxx.xxx.xxx.197|     2882 | 2302.406988900154 | 2601.037109375000 |
+-------+----------------+----------+-------------------+-------------------+
3 rows in set (0.384 sec)

适用 V4 版本,在 sys 租户下执行。

select
  svr_ip,
  svr_port,
  sum(data_size) / 1024 / 1024 / 1024 as data_size_gb,
  sum(required_size) / 1024 / 1024 / 1024 as required_size_gb
from
  CDB_OB_TABLET_REPLICAS
where
  TENANT_ID = 1004
group by
  svr_ip,
  svr_port;

通过上面例子可知:

  • 租户 1001 所在集群有 3 个 Zone(3 副本)。
  • 租户 1001 分配 Unit Num=1。
  • 每个 Zone 上只需 1 个 OBServer。

    • 若租户分配 Unit Num = 2,那么每个 Zone 需要 2 个 OBServer 保存 1 份完整副本。
  • 1 份副本的数据量:data_size_gb=2302GB
  • 1 份副本占用的磁盘空间大小:required_size_gb=2601GB

    • xxx.xxx.xxx.193 上只有 1001 租户,对应 block_file 文件中数据文件中真实数据的大小。
  • 3 个副本的总数据量就是 3 个 Zone 的数据量之和。

因为,OceanBase 的 Oracle 模式里的统计方法和 Oracle 一样(通过 DBA_SEGMENTS 系统视图),所以也可以在业务租户里统计。

注意:这里统计的是 1 个副本的数据量大小,和上面的 data_size_gb=2302GB 一致。
select
  ROUND(SUM(BYTES) / 1024 / 1024 / 1024, 2) AS "SIZE(GB)"
FROM
  DBA_SEGMENTS;
+----------+
| SIZE(GB) |
+----------+
|  2302.41 |
+----------+
1 row in set (2.948 sec)

如果是 OceanBase MySQL模式的租户,无法和原生 MySQL 一样使用 information_schema.tables 进行统计。需要使用 oceanbase 库下的系统视图,和在 sys 租户下方式一样,只是视图名变成 dba 前缀:

select
  svr_ip,
  svr_port,
  sum(data_size) / 1024 / 1024 / 1024 as data_size_gb,
  sum(required_size) / 1024 / 1024 / 1024 as required_size_gb
from
  DBA_OB_TABLET_REPLICAS
group by
  svr_ip,
  svr_port;

表级别

如果要看某张表的数据量大小,通常这个维度看的是单副本的大小,OceanBase Oracle 模式的业务租户下还是使用 DBA_SEGMENTS 视图:

select
  owner,
  SEGMENT_NAME,
  ROUND(BYTES / 1024 / 1024, 2) AS "SIZE(M)"
FROM
  DBA_SEGMENTS
where
  SEGMENT_NAME = 'ETL_P10IDS_RISKCON'
  and OWNER = 'LIFE';
+-------+--------------------+-----------+
| OWNER | SEGMENT_NAME       | SIZE(M)   |
+-------+--------------------+-----------+
| LIFE  | ETL_P10IDS_RISKCON | 177094.57 |
+-------+--------------------+-----------+

对应在 sys 租户下的统计方式:

select
  meta.zone,
  meta.svr_ip,
  t.database_name,
  t.table_name,
  ROUND(meta.data_size / 1024 / 1024, 2) AS "DATA_SIZE(M)",
  ROUND(meta.required_size / 1024 / 1024, 2) AS "REQUIRED_SIZE(M)"
from
  __all_virtual_meta_table meta
  join gv$table t on meta.table_id = t.table_id
where
  t.table_name = 'ETL_P10IDS_RISKCON'
  and t.database_name = 'LIFE';
+-------+----------------+---------+--------------------+--------------+------------------+
| zone  | svr_ip         | db_name | table_name         | DATA_SIZE(M) | REQUIRED_SIZE(M) |
+-------+----------------+---------+--------------------+--------------+------------------+
| zone1 | xxx.xxx.xxx.193| LIFE    | ETL_P10IDS_RISKCON |    177094.57 |        193888.00 |
| zone2 | xxx.xxx.xxx.195| LIFE    | ETL_P10IDS_RISKCON |    177094.57 |        193888.00 |
| zone3 | xxx.xxx.xxx.197| LIFE    | ETL_P10IDS_RISKCON |    177094.57 |        193888.00 |
+-------+----------------+---------+--------------------+--------------+------------------+
3 rows in set (0.787 sec)

--V4版本方式,将表的大小和索引的大小分别进行统计

select y.SVR_IP,y.DATABASE_NAME,
case when y.TABLE_TYPE = 'INDEX' then '' else y.TABLE_NAME end as TABLE_NAME,
y.TABLE_TYPE,
sum(y.DATA_SIZE) AS "DATA_SIZE(MB)",sum(y.REQUIRED_SIZE) AS "REQUIRED_SIZE(MB)"
from (
select a.TENANT_ID,a.SVR_IP,a.TABLET_ID,b.table_id,b.DATABASE_NAME,b.TABLE_NAME,b.TABLE_TYPE,ROUND(a.data_size/1024/1024,2) AS "DATA_SIZE",ROUND(a.required_size/1024/1024,2) AS "REQUIRED_SIZE" 
from CDB_OB_TABLET_REPLICAS a join cdb_ob_table_locations b on a.TABLET_ID=b.TABLET_ID and a.svr_ip=b.svr_ip and a.tenant_id=b.tenant_id 
where a.TENANT_ID=1004 
 and b.DATABASE_NAME='test'
and (
b.TABLE_NAME='sbtest3'
or b.DATA_TABLE_ID in(select table_id from cdb_ob_table_locations where TENANT_ID=1004 and TABLE_NAME='sbtest3')
)order by b.table_id
) y
group by y.SVR_IP,y.DATABASE_NAME,y.TABLE_TYPE
order by y.SVR_IP,y.DATABASE_NAME asc,TABLE_NAME desc;    
+--------------+---------------+------------+------------+---------------+-------------------+
| SVR_IP       | DATABASE_NAME | TABLE_NAME | TABLE_TYPE | DATA_SIZE(MB) | REQUIRED_SIZE(MB) |
+--------------+---------------+------------+------------+---------------+-------------------+
| 10.186.57.73 | test          | sbtest3    | USER TABLE |         72.90 |             90.00 |
| 10.186.57.73 | test          |            | INDEX      |         50.85 |             72.00 |
| 10.186.57.78 | test          | sbtest3    | USER TABLE |         72.90 |             90.00 |
| 10.186.57.78 | test          |            | INDEX      |         50.85 |             72.00 |
| 10.186.57.79 | test          | sbtest3    | USER TABLE |         72.90 |             90.00 |
| 10.186.57.79 | test          |            | INDEX      |         50.85 |             72.00 |
+--------------+---------------+------------+------------+---------------+-------------------+
6 rows in set (1.571 sec)

此外,OceanBase 敏捷诊断工具 obdiag 也可以统计指定表的大小。不过它只会统计其中一个 Follower 的大小,并且不会统计磁盘上 sstable 真实占用大小(require_data_size)。

在文章编写过程中,发现并提交了一个 Bug(已解决),在 obdiag 没有识别分区表时,只会统计一个分区的大小。

比如我们上面的示例中 test.sbtest3 是一个分区表,用 obdiag 统计的结果如下:

sbtest3 表统计

使用命令:

obdiag gather tabledump --user=root@my#hucq_421 --password='aaBB11@@' --database=test --table=sbtest3

爱可生开源社区
426 声望209 粉丝

成立于 2017 年,以开源高质量的运维工具、日常分享技术干货内容、持续的全国性的社区活动为社区己任;目前开源的产品有:SQL审核工具 SQLE,分布式中间件 DBLE、数据传输组件DTLE。