OceanBase 是一个多租户的分布式数据库,统计数据量时需要考虑一台服务器上可能会有多个租户,每个租户会有多个副本。此外 OceanBase 中磁盘上的数据文件是预分配的,当我们统计数据量大小时,得找出真实数据占用的大小。我们需要考虑:
- OceanBase 不同版本(V3、V4)的统计方式有何区别?
- 不同级别(服务器级、租户级、表级)如何统计?
本文将总结在 OceanBase 中统计数据量大小的技巧,旨在扫清这方面的迷雾。
服务器级别
OCP 统计
OCP 上“集群总览”展示的数据量是集群中每个 OBServer 服务器的磁盘容量大小和已使用大小。通过这个信息我们可以快速知道整个集群大概的数据量,以及每台服务器上的存储是否够用。
比如上图中 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
的大小就已经预留好了,后续的写入不会改变文件大小。
- OceanBase 的数据文件是预分配的,在安装数据库后数据文件
- 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 统计的结果如下:
使用命令:
obdiag gather tabledump --user=root@my#hucq_421 --password='aaBB11@@' --database=test --table=sbtest3
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。