RDS PostgreSQL支持SQL限流,该功能用于限制某一类SQL的最大并发量,确保数据库不会因突发流量或资源消耗过高的SQL语句而引起严重的性能问题。
背景
SQL限流是一种重要的数据库管理技术,可以通过限制并发SQL数,从而避免过高的数据库负载,保证数据库的稳定性和可靠性,提高数据库的性能和效率,从而更好地支持业务需求。
应用场景
SQL限流的应用场景不仅限于高并发访问,还包括以下几个方面:
-
防止恶意攻击
通过限制某类SQL的并发数,防止恶意攻击或者DoS攻击,保护数据库的安全性。
-
控制资源使用
通过限制某类SQL的并发数,控制数据库资源的使用量,避免资源耗尽导致数据库崩溃或者性能下降。
例如在数据库备份、恢复、监控等SQL操作时,为了避免其对数据库性能的影响,可以使用SQL限流控制相关操作的速度。
前提条件
-
RDS PostgreSQL实例需满足以下要求:
-
实例大版本为PostgreSQL 14或以上。
-
实例内核小版本为20230330或以上。
说明
如需升级内核小版本,请参见升级内核小版本。
-
-
使用此插件前,需配置如下参数:
-
rds_enable_ccl取值为
on
。 -
compute_query_id取值为
auto
或on
。
说明
您可以前往控制台修改实例参数,更多信息,请参见设置实例参数。
-
使用限制
无
影响
如果SQL限流配置不合理,可能影响业务,请在使用时根据业务负载进行配置。
例如,在某商城促销业务场景下,由于访问激增造成数据库压力较大,可使用此功能限制某类查询SQL的并发数,从而减轻数据库压力。但如果限流设置过小,也可能影响相关业务。
注意事项
如果在实例重启、主备切换等场景,SQL限流规则不会自动加载,需要手动重新加载。具体操作,请参见加载SQL限流规则。
费用
该插件免费。
创建和删除插件
请使用高权限账号执行如下命令。
-
创建插件
CREATE EXTENSION rds_ccl;
-
删除插件
DROP EXTENSION rds_ccl;
使用示例
请使用高权限账号执行如下命令。
创建SQL限流规则
使用场景
该函数只能在主实例中调用,用于创建一个SQL限流规则。
语法
语法一:根据设置的SQL语句进行限流。
SELECT rds_add_ccl_rule(
query_string varchar,
node_tag int,
max_concurrency int,
max_waiting int,
is_enabled boolean,
comment varchar, -- 可选
search_path varchar -- 可选
);
语法二:根据设置的query_id进行限流。
SELECT rds_add_ccl_rule_with_query_id(
query_id bigint,
node_tag int,
max_concurrency int,
max_waiting int,
is_enabled boolean,
query_string varchar, -- 可选
comment varchar -- 可选
);
参数解释
参数 |
类型 |
说明 |
query_string |
varchar |
需要限流的SQL语句。 配置时,使用 例如:
该函数根据query_string取值计算query_id,再根据query_id匹配同类SQL进行限流。query_id的更多信息,请参见query_id简介。 |
query_id |
bigint |
需要限流的SQL语句的query_id,更多信息,请参见query_id简介。 |
node_tag |
int |
限流的节点。
说明 创建SQL限流规则函数中,此参数仅表示规则可应用的范围,不会自动在只读实例中生效,您如果想要此规则在只读实例中发挥SQL限流作用,需要手动加载,具体操作,请参见加载SQL限流规则。 |
max_concurrency |
int |
限制此类SQL的最大并发数。 取值范围:0~100000 |
max_waiting |
int |
限制此类SQL的最大等待数,超过设置上限时,新的SQL会导致PostgreSQL内核触发ABORT,终止并回滚事务。 取值范围:0~100000 |
is_enabled |
boolean |
该规则是否生效。
|
comment |
varchar |
规则描述。 |
search_path |
varchar |
目标限流SQL运行时的模式搜索路径(search_path),如果配置为空字符串( |
注意事项
-
在语法一中,comment和search_path如果不配置,可以填写为空字符串(
''
),如果配置为NULL
,则函数不会进行任何操作而直接返回。 -
在语法二中:
-
query_string和comment如果不配置,可以填写为空字符串(
''
),如果配置为NULL
,则函数不会进行任何操作而直接返回。 -
如果同时配置了query_id和query_string,AliPG内核将以query_id为准进行SQL限流。
-
-
该函数会返回ccl_id,ccl_id是当前数据库下限流规则的唯一标识。
SQL示例
在主实例的ccl_test数据库中,有数据表ccl_tbl,创建SQL限流规则:
-
对所有的
SELECT * FROM ccl_tbl
语句(假设其query_id=1
)进行限流。 -
最多允许3条此类SQL并发执行。
-
最多允许2个此类SQL等待。
-
规则创建成功后立即生效。
-
语法一:
SELECT rds_add_ccl_rule( $$SELECT * FROM ccl_tbl;$$, -- 待限流的SQL语句,使用$$包裹 1, -- 仅限制主实例 3, -- 最多允许3条此类SQL并发执行 2, -- 最多允许2个此类SQL等待 true, -- 规则立即生效 'limit constant select', -- 规则描述 '' -- 使用默认的search_path );
-
语法二:
SELECT rds_add_ccl_rule_with_query_id( 1, -- 待限流的SQL语句的query_id 1, -- 仅限制主实例 3, -- 最多允许3条此类SQL并发执行 2, -- 最多允许2个此类SQL等待 true, -- 规则立即生效 '' -- SQL语句的文本,本示例不填写 'limit constant select', -- 规则描述 );
查询SQL限流规则
使用场景
该命令可以在主实例或只读实例中使用,用于查询已创建的SQL限流规则。
语法
-
查看当前实例中所有库下的SQL限流规则:
SELECT * FROM rds_enabled_ccl_rule;
说明
此命令查询结果中,由于显示限制,query_string和comment的信息会被截断,只显示前200个字符,如果需要查看完整信息,请使用
SELECT * FROM rds_show_current_db_ccl_rule();
命令。 -
查询当前数据库下的所有SQL限流规则:
SELECT * FROM rds_show_current_db_ccl_rule();
使SQL限流规则生效
使用场景
该函数只能在主实例中调用,适用于以下场景:
-
如果创建SQL限流规则时,is_enabled参数配置为false,则可以使用此函数使规则生效。
-
使失效的规则再次生效。
语法
SELECT rds_enable_ccl_rule(ccl_id int);
参数解释
参数 |
类型 |
说明 |
ccl_id |
int |
SQL限流规则ID,如何查询SQL限流规则ID,请参见查询SQL限流规则。 |
注意事项
无
SQL示例
SELECT rds_enable_ccl_rule(1);
加载SQL限流规则
使用场景
该函数可以在主实例或只读实例中调用,用于加载SQL限流规则,只有被加载的规则才会发挥SQL限流作用。
适用于以下场景:
-
主实例:
-
创建SQL限流规则时,如果is_enabled配置为true,则规则会自动加载到主实例,无需手动调用。
-
创建SQL限流规则时,如果is_enabled配置为false,调用
rds_enable_ccl_rule
函数使规则生效时,规则会自动加载到主实例,无需手动调用。 -
如果主实例重启,则需要手动调用此函数,加载规则。
-
-
只读实例:
如果需要规则在只读实例发挥作用,则需要在主实例创建规则(node_tag配置为2或3)后,再在只读实例中调用此函数,手动加载规则。
语法
SELECT rds_load_ccl_rule(ccl_id int);
参数解释
参数 |
类型 |
说明 |
ccl_id |
int |
SQL限流规则ID,如何查询SQL限流规则ID,请参见查询SQL限流规则。 |
注意事项
-
只有在主实例中调用
rds_add_ccl_rule
函数创建了SQL限流规则,且node_tag配置为2或3时,才能在只读实例中加载规则。 -
失效的规则无法被加载,如果只读实例需要加载某条失效的规则,请先在主实例中使其生效,具体方法,请参见使SQL限流规则生效。
SQL示例
SELECT rds_enable_ccl_rule(1);
变更SQL限流规则
使用场景
该函数只能在主实例中调用,用于变更SQL限流规则中的最大并发数和最大等待数。
语法
SELECT rds_update_ccl_rule(
ccl_id int,
new_max_concurrency int,
new_max_waiting int
);
参数解释
参数 |
类型 |
说明 |
ccl_id |
int |
SQL限流规则ID,如何查询SQL限流规则ID,请参见查询SQL限流规则。 |
new_max_concurrency |
int |
变更后最大并发数。
|
new_max_waiting |
int |
变更后最大等待数。
|
注意事项
-
更新SQL限流规则后,规则立即生效。
-
当前仅支持变更SQL限流规则中的最大并发数和最大等待数。
SQL示例
SELECT rds_update_ccl_rule(
2, -- ccl_id
4, -- 新的最大并发数为4
5 -- 新的最大等待数为5
);
使SQL限流规则失效
使用场景
该函数只能在主实例中调用,用于使某条SQL限流规则失效,该规则不再发挥SQL限流作用。
说明
如果要使指定的规则生效,请参见使SQL限流规则生效。
语法
-
使指定SQL限流规则失效:
SELECT rds_disable_ccl_rule(ccl_id int);
-
使当前库下的所有SQL限流规则失效:
SELECT rds_disable_all();
参数解释
参数 |
类型 |
说明 |
ccl_id |
int |
SQL限流规则ID,如何查询SQL限流规则ID,请参见查询SQL限流规则。 |
注意事项
-
失效的规则无法被加载,如果只读实例需要加载某条失效的规则,请先在主实例中使其生效,具体方法,请参见使SQL限流规则生效。
-
使SQL限流规则失效时,会自动将规则从主实例卸载,该规则不再发挥SQL限流作用。
SQL示例
SELECT rds_disable_ccl_rule(1);
卸载SQL限流规则
使用场景
该函数可以在主实例或只读实例中调用,用于卸载SQL限流规则,被卸载的规则不会再发挥SQL限流作用。
适用于以下场景:
-
主实例:
-
如果在主实例中调用了
rds_disable_ccl_rule
或rds_disable_all
函数使规则失效,规则将自动从主实例卸载,无需手动调用。 -
如果在主实例调用了
rds_del_ccl_rule
函数删除规则,规则将自动从主实例卸载,无需手动调用。 -
您也可以手动调用此函数,将规则从主实例卸载。
-
-
只读实例:
如果不希望某条规则在只读实例发挥限流作用,可以在只读实例中手动调用此函数。
语法
SELECT rds_unload_ccl_rule(ccl_id int, db_name varchar default '');
参数解释
参数 |
类型 |
说明 |
ccl_id |
int |
SQL限流规则ID,如何查询SQL限流规则ID,请参见查询SQL限流规则。 |
db_name |
varchar |
默认为空字符串,表示当前数据库。您也可以指定其他数据库,将其他数据库下的SQL限流规则卸载。 |
注意事项
规则卸载后,不再发挥SQL限流作用,如需再次使用,需要重新加载,更多信息,请参见加载SQL限流规则。
SQL示例
SELECT rds_unload_ccl_rule(1,'');
删除SQL限流规则
使用场景
该函数只能在主实例中调用,用于删除某条SQL限流规则。规则删除时,自动从主实例卸载。
语法
SELECT rds_del_ccl_rule(ccl_id int);
参数解释
参数 |
类型 |
说明 |
ccl_id |
int |
SQL限流规则ID,如何查询SQL限流规则ID,请参见查询SQL限流规则。 |
注意事项
无。
SQL示例
SELECT rds_del_ccl_rule(1);
返回结果:
rds_del_ccl_rule
----------------------
-7851264404688445170
(1 row)
说明
-
返回结果为query_id。
-
如果规则不存在,则删除报错。
附录
query_id简介
-
query_id是PostgreSQL中SQL的特殊标识,同类SQL的query_id相同。
例如:
-- 以下两个sql的query_id相同 SELECT * FROM tbl WHERE a = 1; SELECT * FROM tbl FROM a = 2; -- 以下两个sql的query_id相同 SELECT * FROM tbl FROM a < 3 AND b < 3; SELECT * FROM tbl FROM b < 9 AND a < 2;
-
query_id包含有SQL中对象的信息(即oid信息),不同数据库下的同名表不是同一个对象,不同schema下的同名表也不是同一个对象。所以相同的SQL,如果其包含的查询对象不同,那么query_id就不相同。
-
如果是SQL中的访问对象的是全局表,或是全局函数,query_id相同。
-
示例1:
pg_database
为全局表,在不同数据库中查询query_id相同。-
ccl_test数据库中执行如下语句:
SELECT rds_get_query_id($$SELECT * FROM pg_database;$$);
返回结果:
rds_get_query_id ---------------------- -8733244708994363681 (1 row)
-
ccl_test2数据库中执行如下语句:
SELECT rds_get_query_id($$SELECT * FROM pg_database;$$);
返回结果:
rds_get_query_id ---------------------- -8733244708994363681 (1 row)
-
-
示例2:
pg_sleep
为全局函数,在不同数据库中查询query_id相同。-
ccl_test数据库中执行如下语句:
SELECT rds_get_query_id($$SELECT pg_sleep(1);$$);
返回结果:
rds_get_query_id -------------------- 440101247839410938 (1 row)
-
ccl_test2数据库中执行如下语句:
SELECT rds_get_query_id($$SELECT pg_sleep(1);$$);
返回结果:
rds_get_query_id -------------------- 440101247839410938 (1 row)
-
-
-
调用函数场景下,当参数类型变化或是有无FROM子句时,query_id会发生变化。
例如,同样调用
pg_sleep
函数,不同情况下返回query_id
结果不同。-
无FROM子句:
SELECT rds_get_query_id($$SELECT pg_sleep(1);$$);
返回结果:
rds_get_query_id -------------------- 440101247839410938 (1 row)
-
有FROM子句:
SELECT rds_get_query_id($$SELECT * FROM pg_sleep(1);$$);
返回结果:
rds_get_query_id ---------------------- -3404018605099167039 (1 row)
-
参数类型变化:
select rds_get_query_id($$SELECT * FROM pg_sleep(1.0);$$);
返回结果:
rds_get_query_id --------------------- 3073869725037049158 (1 row)
-
内容没看懂? 不太想学习?想快速解决? 有偿解决: 联系专家
阿里云企业补贴进行中: 马上申请
腾讯云限时活动1折起,即将结束: 马上收藏
同尘科技为腾讯云授权服务中心。
购买腾讯云产品享受折上折,更有现金返利:同意关联,立享优惠
转转请注明出处:https://www.yunxiaoer.com/156106.html