diskquota是GPDB用于管理磁盘配额的插件,支持库、表、用户等对象磁盘空间限制。
“软限制”(diskquota.hard_limit = off):默认配置。查询开始时检查配额是否超限,所以,DML过程中磁盘使用超限,不会触发报错,仅在下一条SQL有数据写入时参数触发报错。
“硬限制”(diskquota.hard_limit = on):DML过程中如果发现磁盘使用超限,终止查询。
但是,硬限制也不是实时的,在配置不当的情况下,“实时性”效果会大打折扣。
GPDB master分支(相当于GPDB 7) + diskquota插件。
GPDB集群拓扑为3主3备。
(过程略)
# 将检查时间间隔调到最大(120秒) gpconfig -c diskquota.naptime -v 120 # 启用硬限制 gpconfig -c diskquota.hard_limit -v on # 重启使参数生效(可以使用gpstop -u,但重启更便于测试) gpstop -a gpstart -a
重启后,迅速执行以下SQL:
-- 创建用户 CREATE USER user2 WITH superuser; -- 设置用户配额 SELECT diskquota.set_role_quota('user2', '10 MB'); -- 切换用户 \c - user2 CREATE TABLE t1(a INT, b VARCHAR(20)); -- 重启后,120秒内多次插入数据,不会触发超限报错。 INSERT INTO t1 SELECT i,10*i FROM generate_series(1, 4400000) AS i; -- 每次插入后,查看使用量统计,发现使用量在120秒内不更新。 SELECT * FROM diskquota.show_fast_role_quota_view; INSERT INTO t1 SELECT i,10*i FROM generate_series(1, 4400000) AS i; ...
在GPDB重启后,120秒内,多次插入数据,每次插入数据量都远大于10MB,但都不会触发磁盘超限报错。直到120秒后,才会触发超限报错。
显然,硬限制的效果与diskquota.naptime参数有关,发现超限不是完全由插入操作触发的。
经过对diskquota源代码分析可知:
Coordinator上每个database有个名称为“diskquota bgworker”的进程,周期性检查各种对象(库、表、用户等)的磁盘使用量是否超限,检查的周期由参数diskquota.naptime确定。周期值默认2秒,值越小越能即时发现超限,但CPU消耗越高。进程循环堆栈如下:
#0 0x00007fa5d538c143 epoll_wait #1 0x0000000000b74b55 WaitEventSetWaitBlock #2 0x0000000000b74a57 WaitEventSetWait #3 0x0000000000b73ae2 WaitLatch #4 0x00007fa5d712846d disk_quota_worker_main #5 0x0000000000ac104a StartBackgroundWorker #6 0x0000000000accd44 do_start_bgworker #7 0x0000000000acd1cb maybe_start_bgworkers #8 0x0000000000acbe2b process_pm_pmsignal #9 0x0000000000ac7140 ServerLoop #10 0x0000000000ac695b PostmasterMain #11 0x00000000009392e8 main #12 0x00007fa5d52c0f1e __libc_start_main #13 0x00000000004bc779 _start
检查过程中仅标记状态(内部维护一个reject列表,即黑名单),但不会主动触发超限报错。报错的时机由diskquota.hard_limit参数确定。
软限制时,在查询开始时,如果发现已标记超限,则报错,查询过程中不报错。
硬限制时,在数据写入过程中(数据落盘新页面申请时),如果发现已标记超限,则报错终止查询。
如果检查周期设置太长,不会及时标记对象磁盘超限状态。因此,无论是软限制还是硬限制都不会“即时”超限报错。