
# 使用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';
```
如果不支持，可通过[升级内核小版本](https://support.huaweicloud.com/usermanual-rds-pg/rds_pg_05_0003.html)或者[使用转储与还原升级大版本](https://support.huaweicloud.com/usermanual-rds-pg/rds_09_0053.html)使用该插件。
RDS for PostgreSQL实例支持的插件，具体可参见[支持的插件列表](https://support.huaweicloud.com/usermanual-rds-pg/rds_09_0045.html)。
#### 使用说明
一定要根据业务和资源使用的实际情况合理配置SQL限流规则，否则可能会影响业务。
#### 创建规则
1. 同一个数据库中，不能创建重复（query id相同）的限流规则；不同的数据库中，可以创建重复的限流规则。
2. 规则创建后不会立刻生效，需要调用enable_ccl_rule函数让规则生效。
3. get_query_id函数获取不到绑定变量的SQL的queryid，add_ccl_rule_by_query限制不了绑定变量SQL。
4. 绑定变量SQL的queryid可以通过pg_stat_statements插件获取，之后可以通过add_ccl_rule_by_queryid创建规则，可参考后续绑定变量SQL限流。
 
#### 规则生效
1. 方式1限制了同一时刻并发执行SQL数量，该规则会优先生效。在方式1的基础上还可以进一步通过方式2，限制某类特定SQL的并发执行。
2. 数据库重启后，所有规则不再生效。
3. 只读会同步主库的规则，然后调用enable_ccl_rule函数让规则生效。
4. 限流规则只对后续执行的SQL生效，已经并发执行的SQL不受影响。
 
#### 非绑定变量的SQL限流
前置条件：
1. 开启限流规则需要先安装内核插件rds_pg_sql_ccl，可以通过界面安装，也可执行SQL安装。
   ```
   SELECT control_extension ('create', 'rds_pg_sql_ccl');
   ```
   
2. 设置内核参数。
   ```
   rds_pg_sql_ccl.enable_ccl = on
   ```
   
而后，依次进行如下操作：
1. 在实例管理页面，单击实例名称，进入概览页。
2. 在左侧导航栏，选择"智能DBA助手 \> 历史诊断"。
3. 选择"全量SQL \> SQL限流"。
4. 打开SQL限流开关。
5. 单击"新建SQL限流规则"，配置SQL限流规则参数。
   图1新建限流规则   
   ![](https://support.huaweicloud.com/usermanual-rds-pg/zh-cn_image_0000002248780893.png "点击放大")
   - 单击"启用"，即可开启限流规则。
     图2启动规则   
     ![](https://support.huaweicloud.com/usermanual-rds-pg/zh-cn_image_0000002248940777.png "点击放大") 
   
   - 单击"停用"，即可停用限流规则。
     图3停用规则   
     ![](https://support.huaweicloud.com/usermanual-rds-pg/zh-cn_image_0000002248780897.png "点击放大") 
   
   - 单击"删除"，即可删除限流规则，删除启用状态下的限流规则，该规则不会继续生效。
     图4删除规则   
     ![](https://support.huaweicloud.com/usermanual-rds-pg/zh-cn_image_0000002213820828.png "点击放大") 
    
 
#### 绑定变量的SQL限流
JDBC等驱动支持prepare statement，对参数化SQL进行预编译，在输入参数后实际执行SQL。在pg_stat_statements视图中会以绑定变量的方式呈现。对于参数是绑定变量的SQL，内核计算的query id值与参数为实际值的SQL不一致，因此无法直接通过添加SQL语句方式进行限流。
对于这类SQL而言，只能通过实际执行后手动添加的方式进行限流。
1. 首先实际执行一次带绑定变量的SQL，这样内核会计算其query id。基于JDBC的prepare statement程序示例如下：
   ```
   String sql = "select pg_sleep(?);";
   PreparedStatement preparedStatement = conn.prepareStatement(sql);
   preparedStatement.setInt(1, 500);
   ResultSet resultSet = preparedStatement.executeQuery();
   ```
   
2. 而后在pg_stat_statements视图可以查询到该SQL的query id。
   ```
   select queryid from pg_stat_statements where query ilike '%select pg_sleep%';
   ```
   
3. 通过查询到的query id添加限流规则。
   ```
   select rds_pg_sql_ccl.add_ccl_rule_by_queryid($queryid);
   ```
   
4. 通过上一条SQL的返回值(rule_id)使该规则生效。
   ```
   select rds_pg_sql_ccl.enable_ccl_rule($rule_id);
   ```
   
5. 从插件提供的get_all_enabled_rule视图可以获取到当前所有生效的限流规则。
   ```
   select * from rds_pg_sql_ccl.get_all_enabled_rule;
   ```
   
 
#### 参数说明
表1参数说明 
| 参数名                               | 数据类型 | 默认值   | 最大值    | 最小值 | 含义                              |
|:---|:---|:---|:---|:---|:---|
| 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表示不限制。 |
   
#### 函数接口说明
表2函数接口说明 
| 序号 | 函数名                                    | 参数                                                                                                                                                                                                                                                                                                | 返回值     | 功能               |
|:---|:---|:---|:---|:---|
| 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：新的最大等待时间。
 
#### 视图接口说明
表3视图接口说明 
| 序号 | 视图                                       | 列                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         | 说明                               |
|:---|:---|:---|:---|
| 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 | 查看当前数据库创建的限流规则（不一定生效）。           |
   
