Diskquota extension 是 Greenplum6.0 提供的磁盘配额管理工具,它支持控制数据库 schema 和 role 的磁盘使用量。当 DBA 为 schema 或者 role 设置磁盘配额上限后,diskquota 工作进程负责监控该schema和role的磁盘使用量,并维护超出配额上限的schema和role的黑名单。当用户试图往黑名单中的schema或者role中插入数据时,操作会被禁止。
Diskquota的典型应用场景是对于企业内部多个部门共享一个Greenplum集群,如何分配集群的磁盘资源给不同的部门。Greenplum的Resource Group功能支持对CPU,Memory等资源进行分配。而Diskquota则是对磁盘资源的细粒度分配,支持在schema和role的层级进行磁盘用量的控制,支持秒级延时的磁盘实时使用量检测,这是传统基于的cron job的磁盘管理工具做不到的。企业可以选择为不同的部门分配专属schema,从而实现对各个部门的磁盘配额分配。
需要指出Diskquota是对磁盘用量的一种软限制,“软”体现在两个方面: 1. 计算schema和role的实时用量存在一定延时(秒级),因此schema和role的磁盘用量可能会超出配额。延时对应diskquota模型的最小刷新频率,可以通过GUC diskquota.naptime 调整其大小。2. 对插入语句,diskquota只做查询前检查。如果加载数据的语句在执行过程中动态地超过了磁盘配额上限,查询并不会被中止。DBA可以通过show_fast_schema_quota_view和show_fast_role_quota_view快速查询每个schema和role的配额和当前使用量,并对超出配额上限的schema和role进行相应处理。
Diskquota设计伊始,主要考虑了如下几个问题:
最终diskquota extension的架构由以下四部分组成。
Quota Status Checker基于Greenplum background worker框架实现,包含两类bgworker: diskquota launcher和diskquota worker。
Diskquota launcher负责管理diskquota worker。每个集群只有一个launcher,并且运行在Master节点。laucher进程在数据库启动时(具体时间是Postmaster加载diskquota链接库的时候)被注册并运行。
Laucher进程主要负责:
Diskquota worker进程实际扮演Quota Status Checkers的角色。每个启动diskquota extension的数据库都有隶属于自己worker进程。没有采用一个worker进程监控多个数据库是由于Greenplum和Postgres存在一个进程只能访问一个数据库的限制。由于每个worker进程占用数据库连接和资源,我们为同时启动disk extension的数据库个数设置了上限:10。diskquota worker通过SPI与Segment进行交互,因此,diskquota worker同样只运行在Master节点。
Worker进程主要负责:
刷新diskquota模型的算法如下:
Quota Change Detector
Quota Change Detector通过一系列Hook函数实现。对于Heap表,在smgrcreate()/smgrextend()/smgrtruncate()等位置设置Hook函数,记录活跃表信息;对于AO表和CO表,在BufferedAppendWrite/copy_append_only_data/TruncateAOSegmentFile等位置设置Hook函数,记录活跃表信息。活跃表被存储在每个Segment的共享内存中,等待Quota Status Checker周期性查询。由于活跃表只是一个子集,显著减少了每次刷新diskquota模型的代价。
Quota Enforcement Operator
Quota Enforcement Operator同样通过Hook函数实现。通过重用Greenplum的Hook函数ExecutorCheckPerms_hook,实现在每次插入和更新数据前,检查目标schema或role是否在diskquota的黑名单中,并中止击中黑名单的查询。
Quota Setting Store
diskquota的磁盘配额分为schema和role两类,存储在数据表’diskquota.quota_config’中。每一个启动diskquota的数据库存储和管理自己的磁盘配额。需要指出的是,尽管role不隶属于数据库,而是一个数据库集群的对象,在diskquota中将role的磁盘配额限定为数据库特定。即role会在不同的数据库有不同的配额,role的磁盘使用量也是不同数据库独立计算。Quota Setting Store被定义为如下数据表。
create table diskquota.quota\_config (targetOid oid, quotatype int, quotalimitMB int8, PRIMARY KEY(targetOid, quotatype)); `
复制代码安装和配置
1.开源版diskquota下载地址:diskquota repo,安装步骤如下
# source greenplum\_path.sh
cd $diskquota;
make;
make install;
复制代码2.创建数据库diskquota 用来持久化启动diskquota extension的数据库列表。
create database diskquota;
复制代码3.将diskquota添加到shared_preload_libraries列表
# enable diskquota in preload shared library.
gpconfig -c shared\_preload\_libraries -v 'diskquota'
\# restart database.
gpstop -ar
复制代码4.置diskquota extension的刷新频率
# set naptime (second) to refresh the disk quota stats periodically
gpconfig -c diskquota.naptime -v 2
复制代码5.创建diskquota extension,例如希望在postgres数据库启用diskqota extension, 执行如下语句。
# suppose we are in database 'postgres'
create extension diskquota;
复制代码6.果DBA在非空数据库创建了dikquota extension,会收到提示信息,需要手动执行UDF初始化表table_size。根据数据库中已经存在的文件数,该操作可能耗时。
# after create extension diskquota on non empty database
select diskquota.init\_table\_size\_table();
复制代码7.删除diskquota extension,例如希望在’postgres’数据库禁用diskqota extension,执行如下语句。
# login into 'postgres'
drop extension diskquota;
复制代码使用
1.设置schema的磁盘配额
create schema s1;
select diskquota.set_schema_quota('s1', '1 MB');
set search_path to s1;
create table a(i int);
# insert small data succeeded
insert into a select generate_series(1,100);
# insert large data succeeded, since diskquota is soft limit
insert into a select generate_series(1,10000000);
# insert small data failed
insert into a select generate_series(1,100);
# delete quota configuration
select diskquota.set_schema_quota('s1', '-1');
# insert small data succeeded
select pg_sleep(5);
insert into a select generate_series(1,100);
reset search_path;
复制代码2.设置role的磁盘配额
create role u1 nologin;
create table b (i int);
alter table b owner to u1;
select diskquota.set_role_quota('u1', '1 MB');
# insert small data succeeded
insert into b select generate_series(1,100);
# insert large data succeeded, since diskquota is soft limit
insert into b select generate_series(1,10000000);
# insert small data failed
insert into b select generate_series(1,100);
# delete quota configuration
select diskquota.set_role_quota('u1', '-1');
# insert small data succeed
select pg_sleep(5);
insert into a select generate_series(1,100);
reset search_path;
复制代码3.询schema的磁盘使用量和配额
select * from diskquota.show_fast_schema_quota_view;
复制代码4.查询role的磁盘使用量和配额
select \* from diskquota.show\_fast\_role\_quota\_view;来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/69999831/viewspace-3150313/ ,如需转载,请注明出处,否则将追究法律责任。