SQL throttling

更新时间:
复制 MD 格式

PolarDB for PostgreSQL and provide an SQL throttling feature. This feature allows you to configure throttling rules for specific endpoints to prevent abnormal traffic from affecting your services. This topic describes how to use the SQL throttling feature.

Introduction

The SQL throttling feature allows you to configure throttling rules for specific endpoints. You can use an SQL template to match SQL statements executed on the current endpoint and limit their maximum concurrency or queries per second (QPS). This feature can be used in the following scenarios:

  • A PolarDB cluster experiences high database load due to a slow SQL query, which affects normal business operations.

  • You want to limit the resources available to specific types of risky SQL queries or block their execution entirely.

Procedure

Note

To enable the SQL throttling feature, contact us.

  1. Log on to the PolarDB console. In the left-side navigation pane, click Clusters. Select the region where the cluster is located, and click the cluster ID to open the cluster details page.

  2. In the left-side navigation pane, click Configuration and Management > Security Management.

  3. On the SQL throttling tab, click Add to create a new SQL throttling rule.

  4. In the Create SQL Throttling Rule dialog box, set the following parameters and click OK.

    Category

    Parameter

    Description

    Basic Information

    Rule Name

    The name of the throttling rule. The name must meet the following requirements:

    • Be 30 characters or shorter.

    • Contain only uppercase letters, lowercase letters, and digits.

    Description

    Optional. A description for the throttling rule for easier management. It must be 64 characters or shorter.

    EndpointId

    Select the endpoint to which the throttling rule applies.

    Note
    • You can configure throttling rules only for a cluster endpoint or a custom endpoint (read/write or read-only) that uses active-request-based load balancing. SQL throttling is not supported for primary endpoints or for read-only endpoints that use connection-based load balancing.

    • Rules are endpoint-specific. A rule configured for one endpoint affects only connections made to that endpoint.

    Configurations

    Rule Type

    Select a rule type. Throttle Active Concurrent Statements and Throttle QPS per Connection are supported.

    Note

    Throttle QPS per Connection limits the number of requests per second for a single connection. This type is suitable for scenarios where a connection pool or a persistent connection is used. For short-lived connections, use Throttle Active Concurrent Statements.

    Current Mode

    Select a matching mode for the SQL template. Template Match and Full-text Match are supported. For more information about the differences between the two modes, see Template match vs. full-text match.

    Database Account Name

    Specifies the accounts to which the rule applies. You can specify up to 10 accounts, separated by commas. If left empty, the rule applies to all accounts.

    Database Name

    Specifies the databases to which the rule applies. You can specify up to 10 databases, separated by commas. If left empty, the rule applies to all databases.

    SQL Template

    Configure the SQL template. For more information, see SQL templates and matching modes.

    Maximum Waiting Queue Length

    The maximum length of the waiting queue. The value can range from 0 to 1024. When the concurrency or QPS of matched SQL queries reaches the rule's limit, the proxy adds the queries to a waiting queue to be retried. If the number of queries in the queue exceeds this limit, new requests fail and an error is returned. Setting this parameter correctly prevents the waiting queue from growing indefinitely and causing an out of memory (OOM) error on the database proxy when many SQL queries are throttled.

    Maximum Active Concurrent Statements

    The maximum number of active concurrent statements.

    Note

    This parameter is required only when Throttle Active Concurrent Statements is set to Throttle Active Concurrent Statements.

    Maximum QPS per Connection

    The maximum QPS for each connection.

    Note

    This parameter is required only when Throttle QPS per Connection is set to Throttle QPS per Connection.

How it works

SQL throttling is implemented at the database proxy level. You configure throttling rules on the database proxy to control the concurrency or QPS of specific forwarded SQL statements. This process does not add overhead to the read/write or read-only nodes of the database cluster. As a result, you can configure rules only for cluster and custom endpoints, which route traffic through the proxy.

SQL templates and matching modes

Template match vs. full-text match

An SQL template can be any SQL statement that follows the standard syntax of a PolarDB for PostgreSQL or cluster. The database proxy preprocesses the template differently based on the selected matching mode.

  • Suppose you configure a throttling rule with the following SQL template:

    SELECT * FROM tbl WHERE id < 1;
    • If you select Template Match, the SQL template is normalized. Extra spaces and comments are removed, and constants such as strings in single quotation marks and numbers are replaced with a wildcard. The result is:

      -- Templated result
      SELECT * FROM tbl WHERE id < ?
    • If you select Full-text Match, the SQL template is also normalized, but the constants are not replaced. The result is:

      -- Normalized result only
      SELECT * FROM tbl WHERE id < 1

    The database proxy then generates a unique identifier for the processed SQL for later matching.

  • After the throttling rule is enabled, the database proxy preprocesses each incoming SQL statement similarly. For example, consider the following incoming SQL statement:

    SELECT * FROM tbl WHERE id < 100;

    Two types of normalized SQL are generated, and their unique identifiers are calculated to match against the throttling rule:

    -- Templated result
    SELECT * FROM tbl WHERE id < ?
    -- Normalized result only
    SELECT * FROM tbl WHERE id < 100

After an SQL throttling rule is enabled, the database proxy evaluates the statement against the configured rules before forwarding an SQL statement. If the rule is configured for Template Match, it uses the templated result for matching. If the rule is configured for Full-text Match, the normalized-only result is used. Once a match is found, its concurrency or QPS is calculated, and the proxy performs the corresponding throttling action.

Therefore, for the SQL statement and SQL template in the preceding example, a match is found only when the rule is configured for Template Match.

Parameterized queries

SQL templates support parameterized queries that use the standard PostgreSQL parameter binding syntax:

SELECT * FROM tbl WHERE id < $1 AND name = $2 LIMIT 1;

In both Template Match and Full-text Match modes, the parameterized parts are formatted as wildcards:

-- Templated result
SELECT * FROM tbl WHERE id < ? AND name = ? limit ?
-- Normalized result only
SELECT * FROM tbl WHERE id < ? AND name = ? limit 1

Therefore, for the following SQL statement:

SELECT * FROM tbl WHERE id < $1 AND name = 2 LIMIT 100;

A match is found if the Current Mode is set to Template Match. A match is not found if the Current Mode is set to Full-text Match.

Note

You cannot use the ? character as a parameter marker in an SQL template:

-- Invalid SQL template. This does not conform to standard PostgreSQL syntax and will not match any SQL.
SELECT ?, ?, ?;
-- Valid SQL template
SELECT $1, $2, $3;

Prepared statements

When your application uses a prepared statement, the PREPARE statement itself does not trigger throttling. Only the EXECUTE statement triggers throttling. For an EXECUTE statement, the SQL part of the corresponding PREPARE statement is formatted or templated to match the rules.

Note

For more information about prepared statements, see PREPARE.

Example

Configure a throttling rule with the following SQL template and select Template Match for the matching mode:

SELECT * FROM tbl WHERE id < $1 AND name > $2;

For the following SQL statement:

-- The PREPARE statement does not trigger throttling.
PREPARE s1 AS SELECT * FROM tbl WHERE id < $1 AND name > 100;
-- The EXECUTE statement uses the SQL part from its corresponding PREPARE statement to match the throttling rule.
EXECUTE s1;
EXECUTE s1;
EXECUTE s1;

The three EXECUTE statements will match the throttling rule and be throttled.

Similarly, if you use a PREPARE statement in the SQL template of a throttling rule, only the SQL part of the PREPARE statement is formatted or templated for throttling. Therefore, the following two SQL templates are equivalent when creating a rule:

-- Template 1
PREPARE s1 AS SELECT * FROM tbl WHERE id < $1 AND name > $2;
-- Template 2
SELECT * FROM tbl WHERE id < $1 AND name > $2;

Extended query protocol support

Similar to a prepared statement, when an application driver uses the extended query protocol, only the Execute message triggers throttling. For each Execute message, the database proxy finds the corresponding Parse message and uses its SQL to match throttling rules. Therefore, SQL throttling supports the extended query protocol, so you typically do not need to be concerned with the protocol your application uses.

Note

For more information about the extended query protocol, see the community documentation.

Limitations

Currently, the SQL throttling feature has the following limitations:

  • Throttling is not supported for multi-statements. If you use a multi-statement, no configured throttling rules are triggered.

    A multi-statement refers to a single SQL text that contains multiple SQL statements separated by semicolons. The following is an example of a multi-statement executed using a JDBC driver:

    Statement statement = connection.createStatement();
    statement.execute("select 1; select 2; select 3");

    A multi-statement could match multiple throttling rules simultaneously. To prevent unexpected behavior, throttling is not supported for multi-statements.

  • Throttling is not supported for some special statements, such as transaction control statements and stored procedures. Throttling a transaction control statement like COMMIT would prevent transactions from ending normally. For this reason, they are exempt from throttling rules.

  • When a client or driver uses statement batching mode, batched SQL queries only trigger the first throttling rule that is matched. The following is an example of statement batching using a JDBC driver:

    Statement statement = connection.createStatement();
    statement.addBatch("select 1");
    statement.addBatch("select 2");
    statement.addBatch("select 3");
    int[] result = statement.executeBatch();
    statement.close();
    connection.close();

    Similar to a multi-statement, when you use statement batching, the driver usually combines the extended query protocol messages for multiple SQL queries and sends them at once. This can also result in a situation where multiple throttling rules are matched simultaneously. In this case, only the first matched throttling rule takes effect. In the preceding example, if throttling rules for the following three SQL templates are configured on the endpoint:

    -- Template 1
    SELECT 1;
    -- Template 2
    SELECT 2;
    --Template 3
    SELECT 3;

    Only Template 1 will be matched.

  • The keyword case in your template must match the case in the SQL text you want to throttle.

  • SQL templates do not support templating for variable-length expressions, such as IN or ANY, where the number of elements can differ. For example:

    -- SQL template
    SELECT * FROM tbl WHERE id IN ($1, $2, $3);
    -- SQL1, can match the template
    SELECT * FROM tbl WHERE id IN (1, 6, 8);
    -- SQL2, cannot match the template
    SELECT * FROM tbl WHERE id IN (1, 6, 8, 8);
  • When no throttling rules are configured, the first rule you add does not apply to existing connections. If any rule is already configured in the console (enabled or disabled), subsequent additions, modifications, or deletions of rules take effect in real time for all connections.

    Note
    • If your application uses a persistent connection and you want new rules to take effect immediately, we recommend that you configure and disable an arbitrary rule on the endpoint. Then, any subsequent rules you add or modify will take effect for both new and existing connections.

    • If your PolarProxy version is 2.3.58 or later, adding, modifying, and deleting throttling rules takes effect in real time for all connections. You can check the PolarProxy version in the console. If the minor version is outdated, you can update PolarProxy.

Throttling behavior

SQL throttling uses SQL templates and a waiting queue to limit QPS or active concurrency. An SQL statement must match a throttling rule before its QPS or concurrency is counted for that rule. When the concurrency or QPS exceeds the limit set in the rule, the database proxy places the SQL statement into a waiting queue to be retried after a delay. This ensures the concurrency or QPS on the database remains within the configured limit.

The delay time of the waiting queue is inversely proportional to the QPS or concurrency configured in the rule. The maximum number of SQL statements that can wait in the queue for a specific rule is limited by the Maximum Waiting Queue Length parameter. If this limit is exceeded, the proxy does not forward the SQL statement and returns the following error to the client:

SELECT 123;
Current query is being throttled and waiting queue is full.
Note

The preceding error does not interrupt or change the transaction state of the current connection. After receiving this error, the client can still choose to commit or roll back the transaction.

Additionally, if you set Maximum Active Concurrent Statements or Maximum QPS per Connection to 0 in a throttling rule, any SQL statement that matches the rule is rejected and not forwarded. The client receives the preceding error directly. You can use this method to completely block a specific type of SQL statement.

Note
  • The waiting queue has a minimum retry interval. If you set a high maximum QPS, the actual QPS might be slightly lower than the set value.

  • For high availability, a database proxy is typically deployed with two or more nodes, and client connections are randomly distributed among them. The Maximum Active Concurrent Statements and Maximum Waiting Queue Length parameters are configured at the node level. Each node independently counts concurrency and queue length, so the actual concurrency cannot be precisely controlled. Assume the number of nodes is N, and the single-node configuration is C (Maximum Active Concurrent Statements) and Q (Maximum Waiting Queue Length). The range of client concurrency is [C+Q, N×(C+Q)], and the range of database active concurrency is [C, N×C].

  • After you configure any SQL throttling rule, the proxy must template each business SQL statement, generate a unique identifier, and try to match it against the rules, regardless of whether a match is found. Therefore, enabling SQL throttling can cause a 5% to 10% decrease in forwarding performance. Use throttling only when a slow SQL query is significantly affecting your normal business operations. After you resolve the slow SQL query, you can disable the throttling rule in the console. Disabled rules do not take effect but are saved, and you can re-enable them at any time.

Best practices

Verify a throttling rule

Because throttling rules can be scoped to specific accounts and databases, you can create a test account and configure a rule with concurrency or QPS set to 0 to verify whether the rule can match the desired SQL statement.

Assume you want to throttle the following SQL statement:

SELECT * FROM generate_series(1, 100000);
  1. Create a test database account

    Ensure the account name is test_usr, the type is high-privilege account, and the status is Available.

  2. Configure a throttling rule for the test account and set the maximum active concurrent statements to 0. For details about how to configure a throttling rule, see Procedure.

    For Rule Type, select Throttle Active Concurrent Statements. For Current Mode, select Template Match. For Database Account Name, enter test_usr. For SQL Template, enter select * from generate_series(1, 100000);.

  3. Verify that the rule is effective. This rule applies only to the new test account and does not affect your current services. After configuration, connect to the database through the endpoint selected in the rule and execute the SQL statement. If the expected error is returned, the rule is working correctly:

    SELECT * FROM generate_series(1, 100000);
    Current query is being throttled and waiting queue is full.

Handle slow SQL in production

  1. Prepare the test environment.

    • Prepare an ECS instance

      1. Create a Linux-based ECS instance. For this example, an ECS instance running CentOS 7.6 64-bit is used. For more information, see Create an instance by using the wizard.

        Note

        The ECS instance and the PolarDB cluster should be in the same availability zone and VPC.

      2. Install the pgbench tool on the ECS instance.

        sudo yum install postgresql-contrib
    • Prepare a PolarDB cluster

      1. Log on to the PolarDB cluster purchase page and create a database cluster

      2. Create a database account

      3. Obtain the cluster endpoint If the PolarDB cluster and the ECS instance are in the same availability zone, you can use a private endpoint. Otherwise, you must apply for a public endpoint. Add the IP address of the ECS instance to the PolarDB cluster whitelist. For more information, see Configure a cluster whitelist

      4. In the console, create a test database

      5. To ensure that subsequently configured throttling rules take effect on existing connections, configure a placeholder rule in the console and disable it. For more information, see Procedure.

        Note

        This step is not required if your PolarProxy version is 2.3.58 or later, as new, modified, or deleted throttling rules take effect in real time for all connections. You can check the PolarProxy version in the console. If the minor version is outdated, you can update PolarProxy.

  2. On the ECS instance, use pgbench to connect to the PolarDB cluster endpoint and initialize the benchmark data.

    pgbench -h <PolarDB cluster endpoint> -p <Port of PolarDB cluster endpoint> -i -s 10 -U <PolarDB database username> <Test database name>

    Then, start the stress test. Use the built-in tpcb-like mode of pgbench to simulate a normal application workload.

    pgbench -h <PolarDB cluster endpoint> -p <Port of PolarDB cluster endpoint> -P 1 -b tpcb-like -j 5 -c 10 -M prepared -T 6000 -U <PolarDB database username> <Test database name> 
  3. Simulate a slow SQL scenario. Create a new connection session and execute the following statement in the test database:

    WITH t AS (SELECT md5(i::text) AS id FROM generate_series(1, 10000000) i) SELECT * FROM t ORDER BY id LIMIT 1;

    This SQL statement consumes a large amount of computing resources and typically takes about 5 seconds to return the following result:

                    id                
    ----------------------------------
     0000023f507999464aa2b78875b7e5d6
    (1 row)

    Start pgbench again. Use a custom script to stress test the preceding SQL statement. Start 10 connections to simulate a high cluster load caused by slow SQL queries:

    echo "WITH t AS (SELECT md5(i::text) AS id FROM generate_series(1, 10000000) i) SELECT * FROM t ORDER BY id LIMIT 1;" > slow.sql
    pgbench -h <PolarDB cluster endpoint> -p <Port of PolarDB cluster endpoint> -P 1 -f slow.sql -j 5 -c 10 -M prepared -T 6000 -U <PolarDB database username> <Test database name> 

    After the stress test starts, the original normal application workload drops sharply:

    progress: 11.0 s, 6324.2 tps, lat 1.581 ms stddev 0.454
    progress: 12.0 s, 6143.1 tps, lat 1.627 ms stddev 0.837
    progress: 13.0 s, 6251.8 tps, lat 1.599 ms stddev 0.464
    progress: 14.0 s, 6256.8 tps, lat 1.598 ms stddev 0.439
    progress: 15.0 s, 6201.0 tps, lat 1.612 ms stddev 0.536
    progress: 16.0 s, 6248.2 tps, lat 1.600 ms stddev 0.484
    progress: 17.0 s, 6290.0 tps, lat 1.589 ms stddev 0.439
    progress: 18.0 s, 6244.8 tps, lat 1.601 ms stddev 0.475
    progress: 19.0 s, 6195.0 tps, lat 1.613 ms stddev 0.576
    progress: 20.0 s, 6200.3 tps, lat 1.612 ms stddev 0.628
    progress: 21.0 s, 6099.7 tps, lat 1.640 ms stddev 0.666
    progress: 22.0 s, 5831.2 tps, lat 1.714 ms stddev 1.578
    progress: 23.0 s, 5122.8 tps, lat 1.952 ms stddev 3.239
    progress: 24.0 s, 5925.0 tps, lat 1.686 ms stddev 1.263
    progress: 25.0 s, 5677.0 tps, lat 1.763 ms stddev 1.606
    progress: 26.0 s, 5899.0 tps, lat 1.695 ms stddev 1.117
    progress: 27.0 s, 5832.0 tps, lat 1.714 ms stddev 2.484
    progress: 28.0 s, 6448.0 tps, lat 1.551 ms stddev 0.182
    progress: 29.0 s, 6449.0 tps, lat 1.550 ms stddev 0.187
    progress: 30.0 s, 1252.0 tps, lat 6.038 ms stddev 33.858
    progress: 31.0 s, 147.0 tps, lat 64.147 ms stddev 129.137
    progress: 32.0 s, 274.0 tps, lat 46.103 ms stddev 93.193
    progress: 33.0 s, 240.0 tps, lat 41.924 ms stddev 36.949
    progress: 34.0 s, 106.0 tps, lat 94.393 ms stddev 85.844
  4. In the console, configure a throttling rule with the following SQL template, and select Throttle Active Concurrent Statements for the rule type:

    WITH t AS (SELECT md5(i::text) AS id FROM generate_series($1, $2) i) SELECT * FROM t ORDER BY id LIMIT $3;

    For Current Mode, select Template Match. For Database Account Name, enter test_usr. For Database Name, enter test_db. Set Maximum Waiting Queue Length to 1024.

    Limit the concurrency of the slow SQL query to 1. After you enable the rule, you can see the application workload recover, which indicates the throttling rule is effective.

    progress: 56.0 s, 127.0 tps, lat 82.943 ms stddev 81.855
    progress: 57.0 s, 137.0 tps, lat 68.631 ms stddev 32.356
    progress: 58.0 s, 127.0 tps, lat 84.783 ms stddev 78.936
    progress: 59.0 s, 146.0 tps, lat 67.840 ms stddev 11.758
    progress: 60.0 s, 145.0 tps, lat 62.824 ms stddev 25.166
    progress: 61.0 s, 134.0 tps, lat 82.475 ms stddev 68.729
    progress: 62.0 s, 142.0 tps, lat 70.240 ms stddev 18.793
    progress: 63.0 s, 1994.1 tps, lat 5.134 ms stddev 14.502
    progress: 64.0 s, 3347.8 tps, lat 2.973 ms stddev 9.346
    progress: 65.0 s, 707.0 tps, lat 14.247 ms stddev 25.863
    progress: 66.0 s, 4410.0 tps, lat 2.273 ms stddev 5.326
    progress: 67.0 s, 5808.0 tps, lat 1.722 ms stddev 0.667
    progress: 68.0 s, 5436.0 tps, lat 1.840 ms stddev 3.052
    progress: 69.0 s, 6100.0 tps, lat 1.639 ms stddev 0.208
    progress: 70.0 s, 6107.0 tps, lat 1.638 ms stddev 0.204
    progress: 71.0 s, 6066.0 tps, lat 1.648 ms stddev 0.456
    progress: 72.0 s, 6086.0 tps, lat 1.643 ms stddev 0.202
  5. In the console, modify the throttling rule. In the Actions column of the target rule, click Modify and set Maximum Active Concurrent Statements to 0 to completely block the slow SQL queries.

    After the configuration, the slow SQL stress test returns an error and is interrupted. At this point, the application workload is fully restored.

    progress: 198.0 s, 0.0 tps, lat 0.000 ms stddev 0.000
    progress: 199.0 s, 0.0 tps, lat 0.000 ms stddev 0.000
    progress: 200.0 s, 0.0 tps, lat 0.000 ms stddev 0.000
    progress: 201.0 s, 2.0 tps, lat 5733.302 ms stddev 39.976
    progress: 202.0 s, 0.0 tps, lat 0.000 ms stddev 0.000
    pgbench: error: client 1 script 0 aborted in command 0 query 0: Current query is being throttled and waiting queue is full.
    pgbench: error: client 0 script 0 aborted in command 0 query 0: Current query is being throttled and waiting queue is full.
    pgbench: error: client 9 script 0 aborted in command 0 query 0: Current query is being throttled and waiting queue is full.
    pgbench: error: client 8 script 0 aborted in command 0 query 0: Current query is being throttled and waiting queue is full.
    pgbench: error: client 5 script 0 aborted in command 0 query 0: Current query is being throttled and waiting queue is full.
    pgbench: error: client 2 script 0 aborted in command 0 query 0: Current query is being throttled and waiting queue is full.
    pgbench: error: client 7 script 0 aborted in command 0 query 0: Current query is being throttled and waiting queue is full.
    pgbench: error: client 4 script 0 aborted in command 0 query 0: Current query is being throttled and waiting queue is full.
    pgbench: error: client 3 script 0 aborted in command 0 query 0: Current query is being throttled and waiting queue is full.
    pgbench: error: client 6 script 0 aborted in command 0 query 0: Current query is being throttled and waiting queue is full.
    transaction type: slow.sql
    scaling factor: 1
    query mode: prepared
    number of clients: 10
    number of threads: 5
    duration: 6000 s
    number of transactions actually processed: 112