使用rds_pg_sql_ccl插件
简介
高并发和消耗资源过多的SQL会导致实例不稳定,对此,RDS for PostgreSQL提供了限流能力,是由华为云自研插件rds_pg_sql_ccl实现,其中ccl是concurrent control的缩写,合理地使用SQL限流可以保障实例的稳定性,可以很好地做到性能优化和资源保护,应对的场景有:
- 业务量突增:通过限制某类SQL的执行保障实例的稳定性。
 - 保障核心任务:通过限制其他SQL的执行从而降低资源的消耗保障核心任务的顺利完成。
 
该插件提供了两种限流方式:
- 方式1: 限制同一时刻同时执行SQL数量( 由rds_pg_sql_ccl.max_concurrent_sql参数控制,当参数值≤ 0时,表示不限制)。
 - 方式2: 限制某一类SQL(query id相同)同一时刻并发执行的数量,由限流规则控制,限流规则见下文。
 
支持的版本
支持rds_pg_sql_ccl插件的版本如下:
- PostgreSQL 17及以上版本的全部小版本。
 - 对于PostgreSQL 16:16.2及以上的小版本。
 - 对于PostgreSQL 15:15.4及以上的小版本。
 - 对于PostgreSQL 14:14.8及以上的小版本。
 - 对于PostgreSQL 13:13.11及以上的小版本。
 - 对于PostgreSQL 12:12.15及以上的小版本。
 - 对于PostgreSQL 11:11.20及以上的小版本。
 
可通过以下SQL语句查询当前实例是否支持该插件:
SELECT * FROM pg_available_extension_versions WHERE name = 'rds_pg_sql_ccl';
如果不支持,可通过升级内核小版本或者使用转储与还原升级大版本使用该插件。
RDS for PostgreSQL实例支持的插件,具体可参见支持的插件列表。
使用说明
一定要根据业务和资源使用的实际情况合理配置SQL限流规则,否则可能会影响业务。
创建规则
- 同一个数据库中,不能创建重复(query id相同)的限流规则;不同的数据库中,可以创建重复的限流规则。
 - 规则创建后不会立刻生效,需要调用enable_ccl_rule函数让规则生效。
 - get_query_id函数获取不到绑定变量的SQL的queryid,add_ccl_rule_by_query限制不了绑定变量SQL。
 - 绑定变量SQL的queryid可以通过pg_stat_statements插件获取,之后可以通过add_ccl_rule_by_queryid创建规则,可参考后续绑定变量SQL限流。
 
规则生效
- 方式1限制了同一时刻并发执行SQL数量,该规则会优先生效。在方式1的基础上还可以进一步通过方式2,限制某类特定SQL的并发执行。
 - 数据库重启后,所有规则不再生效。
 - 只读会同步主库的规则,然后调用enable_ccl_rule函数让规则生效。
 - 限流规则只对后续执行的SQL生效,已经并发执行的SQL不受影响。
 
非绑定变量的SQL限流
前置条件:
- 开启限流规则需要先安装内核插件rds_pg_sql_ccl,可以通过界面安装,也可执行SQL安装。 
     
SELECT control_extension ('create', 'rds_pg_sql_ccl'); - 设置内核参数。 
     
rds_pg_sql_ccl.enable_ccl = on
 
而后,依次进行如下操作:
- 在实例管理页面,单击实例名称,进入概览页。
 - 在左侧导航栏,选择“智能DBA助手 > 历史诊断”。
 - 选择“全量SQL > SQL限流”。
 - 打开SQL限流开关。
 - 单击“新建SQL限流规则”,配置SQL限流规则参数。 
     图1 新建限流规则
     - 单击“启用”,即可开启限流规则。 
       图2 启动规则
        - 单击“停用”,即可停用限流规则。 
       图3 停用规则
        - 单击“删除”,即可删除限流规则,删除启用状态下的限流规则,该规则不会继续生效。 
       图4 删除规则
        
 - 单击“启用”,即可开启限流规则。 
       
 
绑定变量的SQL限流
JDBC等驱动支持prepare statement,对参数化SQL进行预编译,在输入参数后实际执行SQL。在pg_stat_statements视图中会以绑定变量的方式呈现。对于参数是绑定变量的SQL,内核计算的query id值与参数为实际值的SQL不一致,因此无法直接通过添加SQL语句方式进行限流。
对于这类SQL而言,只能通过实际执行后手动添加的方式进行限流。
- 首先实际执行一次带绑定变量的SQL,这样内核会计算其query id。基于JDBC的prepare statement程序示例如下: 
     
String sql = "select pg_sleep(?);"; PreparedStatement preparedStatement = conn.prepareStatement(sql); preparedStatement.setInt(1, 500); ResultSet resultSet = preparedStatement.executeQuery();
 - 而后在pg_stat_statements视图可以查询到该SQL的query id。 
     
select queryid from pg_stat_statements where query ilike '%select pg_sleep%';
 - 通过查询到的query id添加限流规则。 
     
select rds_pg_sql_ccl.add_ccl_rule_by_queryid($queryid);
 - 通过上一条SQL的返回值(rule_id)使该规则生效。 
     
select rds_pg_sql_ccl.enable_ccl_rule($rule_id);
 - 从插件提供的get_all_enabled_rule视图可以获取到当前所有生效的限流规则。 
     
select * from rds_pg_sql_ccl.get_all_enabled_rule;
 
参数说明
| 
         参数名  | 
       
         数据类型  | 
       
         默认值  | 
       
         最大值  | 
       
         最小值  | 
       
         含义  | 
      
|---|---|---|---|---|---|
| 
         rds_pg_sql_ccl.enable_ccl  | 
       
         bool  | 
       
         false  | 
       
         -  | 
       
         -  | 
       
         是否开启限流规则。  | 
      
| 
         rds_pg_sql_ccl.max_enabled_rules  | 
       
         int  | 
       
         5000  | 
       
         500000  | 
       
         0  | 
       
         同时生效的限流规则数。  | 
      
| 
         rds_pg_sql_ccl.max_concurrent_sql  | 
       
         int  | 
       
         -1  | 
       
         50000  | 
       
         -1  | 
       
         并发执行的SQL数量(优先级高于限流规则),≤ 0表示不限制。  | 
      
函数接口说明
| 
         序号  | 
       
         函数名  | 
       
         参数  | 
       
         返回值  | 
       
         功能  | 
      
|---|---|---|---|---|
| 
         1  | 
       
         rds_pg_sql_ccl.get_query_id  | 
       
         query_string text, search_path text default 'public'  | 
       
         queryid  | 
       
         计算SQL的queryid。  | 
      
| 
         2  | 
       
         rds_pg_sql_ccl.add_ccl_rule_by_query  | 
       
         query_string text, max_concurrency int default 0, max_waiting int default 0, search_path text default 'public'  | 
       
         ruleid  | 
       
         通过SQL语句添加限流规则。  | 
      
| 
         3  | 
       
         rds_pg_sql_ccl.add_ccl_rule_by_queryid  | 
       
         query_id bigint, max_concurrency int default 0, max_waiting int default 0, search_path text default 'public'  | 
       
         ruleid  | 
       
         通过queryid添加限流规则。  | 
      
| 
         5  | 
       
         rds_pg_sql_ccl.enable_ccl_rule  | 
       
         rule_id bigint  | 
       
         bool  | 
       
         通过ruleid让限流规则生效。  | 
      
| 
         6  | 
       
         rds_pg_sql_ccl.disable_ccl_rule  | 
       
         rule_id bigint  | 
       
         bool  | 
       
         通过ruleid让限流规则失效。  | 
      
| 
         7  | 
       
         rds_pg_sql_ccl.disable_all_ccl_rule  | 
       
         -  | 
       
         void  | 
       
         让所有限流规则失效。  | 
      
| 
         8  | 
       
         rds_pg_sql_ccl.delete_ccl_rule  | 
       
         rule_id bigint  | 
       
         void  | 
       
         通过ruleid删除限流规则。  | 
      
| 
         9  | 
       
         rds_pg_sql_ccl.update_ccl_rule  | 
       
         new_rule_id bigint, new_max_concurrency int, new_max_waiting int  | 
       
         void  | 
       
         通过ruleid更新限流规则。  | 
      
部分参数说明:
- max_concurrency:最大并发数,并发执行该类型SQL的最大数量。
 - max_wait:最大等待时间,达到最大并发数之后,该类型的新SQL的最大等待时间,超过这个时间,则执行失败。
 - new_max_concurrency:新的最大并发数。
 - new_max_wait:新的最大等待时间。
 
视图接口说明
| 
         序号  | 
       
         视图  | 
       
         列  | 
       
         说明  | 
      
|---|---|---|---|
| 
         1  | 
       
         rds_pg_sql_ccl.get_all_enabled_rule  | 
       
         dbid oid, queryid bigint, max_concurrency int, max_wait int  | 
       
         查看所有生效的限流规则。  | 
      
| 
         2  | 
       
         rds_pg_sql_ccl.get_activity_query_status  | 
       
         queryid bigint, wait_start_time timestamptz, pid int, dbid oid  | 
       
         查看当前实例每个SQL的运行状态(queryid,是否等待等)。  | 
      
| 
         3  | 
       
         rds_pg_sql_ccl.get_current_db_ccl_rule  | 
       
         rule_id bigint, query_id bigint , query_string, max_concurrency int, max_waiting int, search_path text, create_time timestamptz, enabled bool  | 
       
         查看当前数据库创建的限流规则(不一定生效)。  |