MARS3 自动降级存储

本文档介绍了在 YMatrix 中支持数据自动降级到对象存储(如 AWS S3),从而实现全自动化冷热分级的方法。

注意!
此功能仅支持MARS3 表

1 背景

物联网场景会产生海量的数据存储。YMatrix 认同热数据(实时数据)重要性的同时,也兼顾对冷数据(历史数据)存储性能和易用性的挖掘。例如:电商平台 7 天内的交易订单访问量会较高,而超过无理由退换的时间后,订单数据被访问的频率就会逐步减少,但过期的订单数据又占用了大量存储空间......此时,如何能够尽量降低此部分的存储成本便成为一个值得思考的问题。

为解决冷数据的存储问题,YMatrix 开发了降级存储功能。其支持将冷热数据存储在不同的介质上:热存储保持为标准型存储、性能性存储、本地 SSD 盘或本地 HDD 盘,冷数据则主动转储到容量型存储,如对象存储之上。容量型存储的价格仅为标准型存储的 20%,大大降低了存储成本。成功转储的数据也将无缝接入 YMatrix 强大的大规模并行计算(MPP)底座,完成数据分级和存储优化。

除存储环境本身的成本节约外,数据降级存储的过程也无需人工干预,最大程度的降低了人工管理成本和使用成本。

目前主流的降级存储方案大多基于 FDW(Foreign Data Wrapper)。区别于基于 FDW 的方案,YMatrix 将对象存储视作一种和本地文件系统等价的存储介质,并将它无缝的接入了 MARS3 存储引擎,对于普通的文件系统适用的能力,对降级存储中的数据同样适用。

这意味着在 MARS3 中降级存储将拥有更多的可能性:

特性 YMatrix(MARS3 降级存储) FDW 相关方案
支持事务
支持冷数据自动转储
管理复杂度 不需要人工接入 需要复杂的运维支持

2 快速体验

此部分我们将通过完整的流程测试使你直观、快速地体验降级存储的过程与结果。

2.1 创建对象存储

本文以 AWS S3 为例。

首先登陆 AWS ,点击右上角用户名处按钮,选中 Security credentials,下滑选择 创建访问密钥

因为我们需要将冷数据从 YMatrix 中整理并转储到 AWS S3 对象存储桶中去,因此需要选择 在 亚马逊云科技 之外运行的应用程序

创建成功。

成功创建对象存储桶后可得到以下信息:

  • 访问密钥(Access Key)
  • 私密密钥(Secret Key)
  • 地区(Region)
  • 桶(Bucket)
  • 服务地址(Endpoint): https://.s3..amazonaws.com.cn

2.2 初始化测试集群

在测试集群的 Master 和 Segments 服务器上创建表空间目录。

$ mkdir -p <tablespace_dir,eg:'/home/mxadmin/test'>

2.3 初始化降级存储

首先使用 vi quick.sql 命令创建 quick.sql 文件,并保存以下内容:

-- 创建 matrixts 扩展
CREATE EXTENSION IF NOT EXISTS matrixts;

-- 配置相关系统配置参数
\!gpconfig -c mars3.enable_objectstore -v ON --skipvalidation
\!gpconfig -c mars3.degrade_min_run_size -v 0 --skipvalidation
\!gpconfig -c mars3.degrade_probe_interval -v 300 --skipvalidation

-- 创建表空间 your_tbs
DROP TABLESPACE IF EXISTS your_tbs;

CREATE TABLESPACE your_tbs LOCATION :tablespace_dir
WITH(
        oss_accessid=:oss_accessid,
        oss_secretkey=:oss_secretkey,
        oss_endpoint=:oss_endpoint,
        oss_region=:oss_region,
        oss_bucket=:oss_bucket
);

替换下方 < > 内(含 < >)的配置信息,并执行该命令,快速初始化降级存储:

$ psql -be -d <your_database> 
                  -v tablespace_dir="'<your_tablespace_dir>'" \
                  -v oss_accessid="'<your_oss_accessid>'" \
                  -v oss_secretkey="'<your_oss_secretkey>'" \
                  -v oss_endpoint="'<your_oss_endpoint>'" \
                  -v oss_region="'<your_oss_region>'" \
                  -v oss_bucket="'<your_oss_bucket>'" \
                  -f quick.sql

重新加载配置文件:

$ mxstop -u

2.4 创建开启降级存储功能的表

使用 vi quick2.sql 命令创建 quick2.sql 文件,并保存以下内容:

\set tname t1
\set tnamestr '''t1'''

-- 创建测试表,设置将 7 天前的数据转储到对象存储
DROP TABLE IF EXISTS :tname;
CREATE TABLE IF NOT EXISTS
:tname(
   key int,
   value int,
   c3 date)
USING mars3
WITH(ttl_interval='7 d', ttl_space='your_tbs')
DISTRIBUTED BY (key)
ORDER BY (key, value);

-- 往测试表中插入一批测试数据
INSERT INTO :tname SELECT i, i, current_date FROM generate_series(1, 12000000) i;

执行 quick2.sql 文件:

$ psql -be -d <your_database> -f quick2.sql

2.5 手动转储(仅为体验功能)

通过内置的工具函数,将这张表所有的数据全部手动转储到对象存储:

$ psql <your_database>
=# SELECT matrixts_internal.mars3_degrade('t1'::regclass, -1);

2.6 检查是否转储成功

成功执行以上命令后,t1 的数据已经全部转储到了你的对象存储上,集群上只有一个用来访问这些数据的“壳”。可以用以下命令来验证一下数据访问是否正常:

=# \set tname t1

SELECT * FROM :tname LIMIT 10;
DELETE FROM :tname WHERE key < 50;
SELECT * FROM :tname WHERE key < 50;

最后,你可以直接进入对象存储的管理平台,可以看到你创建的存储桶中已经存在这些数据。你可以将这些转储成功的对象存储测试数据全部删除,再从集群访问,例如:

=# SELECT * FROM :tname WHERE key < 50;

就会发现数据库报错 key not exist,这意味着测试成功:你访问的数据已经完全变成对象存储中的对象数据了。

3 完整功能

功能 介绍 配置参数
不同认证模式接入 YMatrix 支持用两种认证模式来接入对象存储,选择其一即可:
静态的 AccessId/SecretKey
基于 Security Token Service(STS) 的动态 AccessId/SecretKey
创建表空间时相关配置参数
系统参数 mars3.degrade_credential_update_interval
转储策略管理 管理转储策略。包括历史数据的判断依据,数据后台任务的定时检查时间间隔等 ttl_interval/ttl_space/mars3.enable_objectstore/mars3.degrade_probe_interval
数据查询缓存 缓存通过减少直接与对象存储之间的交互提升数据 I/O 的效率,从而提升查询性能 matrixts.enable_object_cache/mars3.enable_object_prefetch/oss_cache_size
运维工具 数据链路检查工具:系统检查当前环境是否已满足降级存储功能所需的依赖条件
垃圾扫描工具:找出对象存储中的残留数据并手动清理

3.1 不同认证模式接入对象存储

YMatrix 支持用两种认证模式来接入对象存储,选择其一即可

  1. 本文快速体验部分采用了 AWS S3 为例,为静态认证,语法如下:

    =# CREATE TABLESPACE <your_tablespace> LOCATION '<your_tablespace_dir>'
    WITH(
     oss_accessid='<your_accessid>',
     oss_secretkey='<your_secretkey>',
     oss_endpoint='<your_address>',
     oss_bucket='<your_bucket>'
    );
  2. 如果使用 STS 模式来访问对象存储,那么你不仅需要在表空间上填充参数,还需要额外实现一个脚本来定时刷新表空间上的参数:

-- 创建表空间
CREATE TABLESPACE <your_tablespace> LOCATION '<your_tablespace_dir>'
WITH(
        oss_endpoint='<your_address>',
        oss_bucket='<your_bucket>'
);
-- 实现能更新表空间中 oss_sessiontoken/oss_accessid/oss_secretkey 配置项的定时任务。参考脚本如下
DB="postgres"
SPACE="tbs"

RES=$(aws sts get-session-token)
if [ $? != 0 ]
then
        echo "get credentials fail!"
        exit 1
fi

ak=$(echo "${RES}"|jq -r .Credentials.AccessKeyId)
sk=$(echo "${RES}"|jq -r .Credentials.SecretAccessKey)
token=$(echo "${RES}"|jq -r .Credentials.SessionToken)

if [ "${ak}" == "" ]
then
        echo "AccessKeyId is empty!"
        exit 1
fi

if [ "${sk}" == "" ]
then
        echo "SecretAccessKey is empty!"
        exit 1
fi

if [ "${token}" == "" ]
then
        echo "SessionToken is empty!"
        exit 1
fi

echo $ak
echo $sk
echo $token

psql -d "${DB}" -c "ALTER TABLESPACE ${SPACE} SET (oss_accessid='${ak}', oss_secretkey='${sk}', oss_sessiontoken='${token}');"
if [ $? != 0 ]
then
        echo "alter tablespace fail!"
        exit 1
fi

如需定期更新访问对象存储的授权信息,请配置以下参数:

注意!
此部分表空间相关配置参数介绍请见CREATE TABLESPACE

3.2 转储策略管理

使用转储策略的前提是启用数据转储功能,通过以下参数配置:

例如:

$ gpconfig -c mars3.enable_objectstore -v ON --skipvalidation
$ gpconfig -c mars3.degrade_probe_interval -v 300 --skipvalidation
$ mxstop -u

具体的转储策略通常在建表时使用 ttl_intervalttl_space 参数进行设置,语法如下:

=# CREATE TABLE <your_table> (
  ...
) 
...
WITH (ttl_interval='<your_interval>', ttl_space='<your_tablebspace>')
...
;

也可以在已有表上修改策略,示例如下:

=# ALTER TABLE <your_table> SET (ttl_interval='14d');

3.3 数据查询缓存

当一个查询需要使用对象存储中的冷数据的时候,开启缓存可以大大降低数据库操作 I/O 的开销,从而可以提升查询性能,缓存受以下参数控制:

示例如下。建表时指定表空间下文件缓存空间为 10000MB:

=# CREATE TABLESPACE <your_tablebspace> LOCATION <your_tablespace_dir>
WITH(
    ...
    oss_cache_size=10000,
    ...
);

然后在查询会话内开启缓存(如需关闭缓存,也要在会话内完成):

=# SET matrixts.enable_object_cache to ON;
=# SET mars3.enable_object_prefetch to ON;

注意!
文件缓存和内存缓存在每个后台进程上都需要占用 64MB 的内存空间,如一个查询需要启动 10 个后台进程,那么预计需要额外的内存空间为 640MB x 2 (假设两个缓存都打开),一般为了最优的查询性能,建议同时开启以上两个缓存。

3.4 运维工具

3.4.1 数据链路检查

如果你要现有的生产集群上接入降级存储功能,那么请先使用数据链路检查工具检查目前集群所在环境是否允许完整的功能运行。

链路检查工具 osscheck 安装后在 $GPHOME/bin 目录下。

使用步骤如下:

  1. 生成配置文件模板
$ osscheck -g conf
  1. 执行 vi conf 命令编写配置文件

说明:

  • 必填 oss_accessidoss_secretkeyoss_endpointoss_bucket
  • 如果使用 STS 认证方式还需要填写 oss_sessiontoken
  • 如果需要前缀还要填写 oss_keyprefix

模版如下,请替换下方 < > 内(含 < >)的配置信息:

oss_accessid='<your_oss_accessid>'
oss_secretkey='<your_oss_secretkey>'
oss_sessiontoken='<your_oss_sessiontoken>'
oss_endpoint='<your_oss_endpoint>'
oss_region='<your_oss_region>'
oss_bucket='<your_oss_bucket>'
oss_keyprefix='<your_oss_keyprefix>'
oss_retry_mode=default
oss_upload_partsize=5
oss_upload_parallelnum=3
oss_retry_times=3
oss_timeout=3000
  1. 链路检查

运行如下命令,基于填写好的配置文件做链路检查。如果验证成功,将出现绿色的 success 提示:

$ osscheck -t conf
put object success
get object success
list object success
delete object success

如果检测失败,将会用红色 fail 提示失败的检测项:

$ osscheck -t conf.template
ERROR: InvalidAccessKeyId: The Access Key Id you provided does not exist in our records.
put object fail

3.4.2 垃圾扫描工具

垃圾扫描工具会检查对象存储服务上是否有不符合预期的垃圾数据。

垃圾数据产生可能有如下几个原因:

  • 删除对象表时,删除对象数据失败。表删除了,但是对象数据还在,无法回收;
  • 没有删除对象表,直接删除了数据库,或者直接删除了集群。因为删除对象数据是在删除对象表时触发,直接删除数据库和集群不会删除包含的对象表的对象数据;
  • 人为原因,比如放了一些测试数据忘记删除。

在使用垃圾扫描工具时需要注意:

  • 垃圾扫描工具通过调用 matrixts_internal.oss_junkobjects() 函数查询数据库目录的方式开展工作 ;
  • 垃圾扫描需要提供对象存储的配置信息,目前存储在表空间中。所以垃圾扫描仅可以扫描当前对象存储配置下的垃圾对象,即在当前 oss_bucket/oss_keyprefix/ 目录下的垃圾对象。所以请确保该目录仅为当前集群所用。

使用方法如下:

=# CREATE EXTENSION IF NOT EXISTS matrixts;
=# SELECT * FROM matrixts_internal.oss_junkobjects('<your_tablespace>');
                 key                 |       lastmodify       |   size
-------------------------------------+------------------------+----------
 49948/2/52751/4/0                   | 2023-10-19 16:00:14+08 |    38964
 49948/2/53021/1/0                   | 2023-10-19 16:04:55+08 |    38964
 16384/2/158581/3/0                  | 2023-09-03 13:16:26+08 |     4080
 16384/2/158581/p2                   | 2023-09-03 15:18:36+08 |        5
 16384/2/202151/3/0                  | 2023-09-21 16:22:09+08 |       80
 49948/1/52751/4/0                   | 2023-10-19 16:00:14+08 |    40620
 49948/1/52861/1/0                   | 2023-10-19 16:01:34+08 |   240000
 49948/1/53021/1/0                   | 2023-10-19 16:04:55+08 |    40620
 49948/1/53038/1/0                   | 2023-10-19 16:05:10+08 |   120000
 16384/1/158581/3/0                  | 2023-09-03 13:16:26+08 |     3864
 16384/1/202151/3/0                  | 2023-09-21 16:22:09+08 |       20
 49948/0/52751/4/0                   | 2023-10-19 16:00:14+08 |    40416
 49948/0/53021/1/0                   | 2023-10-19 16:04:55+08 |    40416
 ......

其中:

  • key:垃圾对象键值
  • lastmodify:垃圾对象最后修改时间
  • size:垃圾对象大小

常见问题

  1. 降级存储的列中必须要有时间吗?

是的,而且隐含了时间必须为分区键,这个时间列可以是 datetimestamp 类型的,这是因为冷数据的转储需要以时间作为判断标准。目前分区键中如果找不到时间列是无法使用降级存储功能的。

注意!
目前降级存储功能尚不支持分区键中存在多个时间列的表。

  1. 转储的时间周期是多久(多久检查一次)?

默认是 1 小时,可以通过 mars3.degrade_probe_interval 参数修改。

  1. 开启自动转储后,想要临时关闭怎么办?

设置如下参数并重新加载配置:

$ gpconfig -c mars3.enable_objectstore -v off --skipvalidation
$ mxstop -u
  1. 一个集群支持多少个表空间?

逻辑上支持任意多个,但目前缓存尚不能很好支持多个表空间的数据同时使用的场景,建议每个集群仅创建一个对象存储表空间。

  1. 对象存储表空间是某个数据库独占的还是多个数据库共享的?

共享。

  1. 缓存可以只开内存缓存或者文件缓存吗?

是可以单独使用的,但为了最佳的查询性能,建议全部开启。

  1. 分区表的配置项可以直接更新到子表吗?

不能,目前的版本只有在新建分区表,或者扩展新分区的时候,分区子表才能自动继承父表的配置项;如果是已经存在的父表,直接 ALTER TABLE 父表,是不能自动继承到子表去的.

  1. 降级存储使用的额外内存

此问题中阐述的额外内存 = 缺省配置下的内存 + 开启自动转储 + 并发查询 + 开启内存缓存和文件缓存

注意!
此结果估算的是一种理论上存在的最坏场景.

具体计算公式如下:

额外内存开销 = 客户端并发查询数 * 每个单节点的 Segment 实例数 * 查询平均扫描的表数 * (并行 Worker 数 + 1) * (64MB + 64MB + 10M) + 分区表数 * 每个单节点的 Segment 实例数 * 64MB