Concurrency Control

为了应对突发的数据库请求流量、资源消耗过高的SQL语句以及SQL语句访问模型变化问题,保证PolarDB集群持续稳定运行,阿里云提供了基于SQL语句的并发控制Concurrency Control(简称CCL)规则,并提供了工具包DBMS_CCL便于您快捷地使用该功能。

前提条件

PolarDB集群版本需为以下版本之一:

  • PolarDB MySQL版8.0版本。

  • PolarDB MySQL版5.7版本且内核小版本需为5.7.1.0.6及以上。

    说明

    当集群版本为PolarDB MySQL版5.7版本且内核小版本为5.7.1.0.27及以上时,CCL与Thread Pool实现兼容。

  • PolarDB MySQL版5.6版本。

注意事项

  • CCL规则的修改操作只能在主节点进行,修改完成后会自动同步到其他节点。

  • CCL提供了超时机制以应对执行DML操作时导致事务锁死锁的问题,等待中的线程也会响应事务超时和线程KILL操作以应对死锁问题。

功能设计

维度特征

CCL定义了如下五个维度特征,SQL语句将根据这些维度特征与CCL规则进行匹配:

维度

说明

TYPE

SQL语句类型(如SELECT、UPDATE、INSERT、DELETE和DDL语句等)。

SCHEMA

SQL操作的数据库名称。

TABLE

SQL操作的表名称或视图名称。

KEYWORD

SQL语句中的关键字。您可以在CCL规则中配置多个关键字,多个关键字之间使用英文分号(;)分隔。

DIGEST

SQL语句进行hash计算得到的字符串,详情请参见STATEMENT_DIGEST()

SQL语句与CCL规则匹配方式

  • 当您设置的CCL规则中DIGEST值为空时,匹配方式如下:

    • DIGEST值为空,TYPE、SCHEMA和TABLE非空时,您的SQL语句中的TYPE、SCHEMA和TABLE需要与CCL规则中的TYPE、SCHEMA和TABLE同时匹配,CCL规则才能生效。

    • DIGEST值为空,SCHEMA和TABLE为空,TYPE非空时,您的SQL语句中的TYPE需要与CCL规则中的TYPE匹配,CCL规则才能生效。

    说明

    若CCL规则中的KEYWORD非空,则还需要对KEYWORD进行校验:

    • 当CCL规则中配置单个KEYWORD时,SQL语句中包含该KEYWORD,则表示匹配成功。

    • 当CCL规则中配置多个KEYWORD时,SQL语句中必须包含CCL规则中配置的所有KEYWORD,才能匹配成功。且匹配CCL规则时,对于SQL语句中的KEYWORD无顺序要求。

  • 当您设置的CCL规则中DIGEST值非空时,您的SQL语句所在的SCHEMA和DIGEST值,需要与CCL规则中的SCHEMA和DIGEST值同时匹配,CCL规则才能生效。

  • 当您设置的CCL规则中SCHEMA为空时,您的SQL语句的DIGEST值与CCL规则中的DIGEST值匹配,CCL规则即可生效。

SQL语句与CCL规则匹配顺序

单条SQL语句只能与单个CCL规则进行匹配,当单条SQL语句同时符合多个CCL规则时,则按照以下顺序选择优先级最高的CCL规则进行匹配,且同等优先级别下,优先匹配ID较小的CCL规则:

  1. 根据DIGEST值匹配。

  2. 根据TYPE、SCHEMA和TABLE匹配。

  3. 仅根据TYPE匹配。

参数说明

您可以在PolarDB控制台修改以下参数,具体操作步骤请参见设置集群参数和节点参数

参数

说明

loose_ccl_mode

超出并发数量时,SQL语句的行为。取值如下:

  • WAIT(默认):排队等待。等待其它SQL语句执行完成后执行该语句。

  • REFUSE:报错。

说明

PolarDB MySQL版 8.0版本支持该参数。5.6和5.7版本直接进行排队等待。

loose_ccl_max_waiting_count

loose_ccl_mode参数设置为WAIT时,符合单个CCL规则的SQL语句排队等待的最大数量,超出该值时会报错。

取值范围:0~65536。默认值为0。

说明

PolarDB MySQL版 5.7和8.0版本支持该参数。

CCL规则表

PolarDB设计了一张系统表concurrency_control用于保存CCL规则,系统启动时会自动创建该表,无需您手动创建。该系统表的创建语句如下:

CREATE TABLE concurrency_control (
  Id bigint AUTO_INCREMENT NOT NULL,
  Type varchar(64),
  Schema_name varchar(64),
  Table_name varchar(64),
  Concurrency_count bigint NOT NULL,
  Keywords text,
  State enum('N','Y') COLLATE utf8_general_ci DEFAULT 'Y' NOT NULL,
  Ordered enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL,
  Digest varchar(64),
  Digest_text longtext,
  Extra mediumtext,
  PRIMARY KEY Rule_id(id)
) Engine=InnoDB STATS_PERSISTENT=0 CHARACTER SET utf8 COLLATE utf8_bin
  comment='Concurrency control' TABLESPACE=mysql;

参数说明请参见下表:

参数

说明

Id

CCL规则ID。

Type

SQL语句类型(如SELECT、UPDATE、INSERT、DELETE和DDL语句等)。

Schema_name

数据库名称。

Table_name

数据库内的表名。

Concurrency_count

并发数量。

说明

您可以将Concurrency_count的值设置为0来实现SQL黑名单功能。以此来禁止执行此类query。

Keywords

关键字,多个关键字使用英文分号(;)分隔。

State

规则是否启用,取值范围如下:

  • Y(默认):启用规则。

  • N:禁用规则。

Ordered

Keywords中配置多个关键字时,是否按顺序匹配CCL规则。取值范围如下:

  • N(默认):Keywords中配置多个关键字时,不需要按顺序匹配CCL规则。

  • YKeywords中配置多个关键字时,需要按顺序匹配CCL规则。

Digest

使用Digest_text进行hash计算时,得到的64个字节的hash字符串。详情请参见STATEMENT_DIGEST()

Digest_text

SQL语句的特征。

Extra

其它信息。

管理CCL规则

为了便捷地管理CCL规则,PolarDBDBMS_CCL中定义了以下六个本地存储过程。详细说明如下:

  • add_ccl_rule:增加根据TYPE、SCHEMA、TABLE和KEYWORD匹配的CCL规则。

    语法

    dbms_ccl.add_ccl_rule('<Type>','<Schema_name>','<Table_name>',<Concurrency_count>,'<Keywords>');

    示例

    • 增加TYPE为SELECT的CCL规则,当并发数量为10时进行排队等待或者报错。

      CALL dbms_ccl.add_ccl_rule('SELECT', '', '', 10, '');
    • 增加TYPE为SELECT,且SELECT语句中出现关键字key1的CCL规则,当并发数量为20时进行排队等待或者报错。

      CALL dbms_ccl.add_ccl_rule('SELECT', '', '', 20, 'key1');
    • 增加TYPE为SELECT,且SELECT语句中出现关键字key1、key2和key3的CCL规则,当并发数量为20时进行排队等待或者报错,关键字出现顺序不限。

      CALL dbms_ccl.add_ccl_rule('SELECT', '', '', 20, 'key1;key2;key3');
    • 增加TYPE为SELECT,SCHEMA为test,TABLE为t的CCL规则,当SELECT语句的并发数量为10时进行排队等待或者报错。

      CALL dbms_ccl.add_ccl_rule('SELECT', 'test', 't', 10, '');
  • add_ccl_digest_rule:增加根据DIGEST值匹配的CCL规则。

    说明

    支持使用add_ccl_digest_rule存储过程的数据库版本引擎为:

    • PolarDB MySQL版为8.0.1版本且内核小版本为8.0.1.1.31及以上。

    • PolarDB MySQL版为8.0.2版本且内核小版本为8.0.2.2.12及以上。

    语法

    dbms_ccl.add_ccl_digest_rule('<Schema_name>', '<Query>', <Concurrency_count>);

    示例

    • 增加SQL语句与SELECT * FROM t1匹配的CCL规则,当并发数量为10时进行排队等待或者报错。

      CALL dbms_ccl.add_ccl_digest_rule("", "SELECT * FROM t1", 10);
    • 增加SCHEMA为test,且SQL语句与SELECT * FROM t1匹配的CCL规则,当并发数量为10时进行排队等待或者报错。

      CALL dbms_ccl.add_ccl_digest_rule("test", "SELECT * FROM t1", 10);
    • 增加SQL语句与SELECT * FROM t1 WHERE col1=1匹配的CCL规则,当并发数量为10时进行排队等待或者报错。

      CALL dbms_ccl.add_ccl_digest_rule("", "SELECT * FROM t1 WHERE col1 = 1", 10);
      说明

      SQL语句中存在常量时,即使常量值不相同,也会进行匹配。如上述CCL规则也能与SQL语句SELECT * FROM t1 WHERE col1 = 2匹配。

  • add_ccl_digest_rule_by_hash:增加根据DIGEST值匹配的CCL规则,直接使用计算完成的DIGEST值而非SQL语句。

    说明

    仅当PolarDB MySQL版 引擎为8.0.1版本且内核小版本为8.0.1.1.31及以上时,支持使用add_ccl_digest_rule_by_hash存储过程。

    语法

    dbms_ccl.add_ccl_digest_rule_by_hash('<Schema_name>', '<Digest>', <Concurrency_count>);

    示例

    • 增加SQL语句的DIGEST值与533c0a9cf0cf92d2c26e7fe8821735eb4a72c409aaca24f9f281d137427bfa9a匹配的CCL规则,当并发数量为10时进行排队等待或者报错。

      CALL dbms_ccl.add_ccl_digest_rule_by_hash('', '533c0a9cf0cf92d2c26e7fe8821735eb4a72c409aaca24f9f281d137427bfa9a', 10);

      其中,533c0a9cf0cf92d2c26e7fe8821735eb4a72c409aaca24f9f281d137427bfa9aSELECT * FROM t1计算得到的DIGEST值。您可以通过SELECT statement_digest("SELECT * FROM t1")命令计算或从其他模块中获取该值。

    • 增加SCHEMA为test,且SQL语句的DIGEST值与533c0a9cf0cf92d2c26e7fe8821735eb4a72c409aaca24f9f281d137427bfa9a匹配的CCL规则,当并发数量为10时进行排队等待或者报错。

      CALL dbms_ccl.add_ccl_digest_rule_by_hash('test', '533c0a9cf0cf92d2c26e7fe8821735eb4a72c409aaca24f9f281d137427bfa9a', 10);
  • del_ccl_rule:删除CCL规则。

    语法

    dbms_ccl.del_ccl_rule(<Id>);

    示例

    删除规则ID为15的CCL规则。

    CALL dbms_ccl.del_ccl_rule(15);

    如果删除的规则不存在,系统会报相应的警告信息,您可以使用SHOW WARNINGS;命令来查看警告内容。示例如下:

    1. 删除规则ID为100的CCL规则。

      CALL dbms_ccl.del_ccl_rule(100);

      执行结果如下:

      Query OK, 0 rows affected, 2 warnings (0.00 sec)
    2. 执行以下命令,查看告警内容。

      SHOW WARNINGS;

      执行结果如下:

      +---------+------+----------------------------------------------------+
      | Level   | Code | Message                                            |
      +---------+------+----------------------------------------------------+
      | Warning | 7517 | Concurrency control rule 100 is not found in table |
      | Warning | 7517 | Concurrency control rule 100 is not found in cache |
      +---------+------+----------------------------------------------------+
    说明

    上述示例中PolarDB MySQL版 8.0版本的Code7517PolarDB MySQL版 5.7版本的Code3267PolarDB MySQL版 5.6版本的Code3045

  • show_ccl_rule:查看内存中已启用的CCL规则。

    语法

    dbms_ccl.show_ccl_rule();

    示例

    CALL dbms_ccl.show_ccl_rule();

    执行结果如下:

    +------+--------+--------+-------+-------+-------+-------------------+---------+---------+----------+----------+
    | ID   | TYPE   | SCHEMA | TABLE | STATE | ORDER | CONCURRENCY_COUNT | MATCHED | RUNNING | WAITTING | KEYWORDS |
    +------+--------+--------+-------+-------+-------+-------------------+---------+---------+----------+----------+
    |   17 | SELECT | test   | t     | Y     | N     |                30 |       0 |       0 |        0 |          |
    |   16 | SELECT |        |       | Y     | N     |                20 |       0 |       0 |        0 | key1     |
    |   18 | SELECT |        |       | Y     | N     |                10 |       0 |       0 |        0 |          |
    +------+--------+--------+-------+-------+-------+-------------------+---------+---------+----------+----------+​
    说明

    其中,MATCHEDRUNNINGWAITTING参数的说明如下:

    • MATCHED:规则匹配成功次数。

    • RUNNING:该规则下正在并发执行的线程数。

    • WAITTING:该规则下正在等待执行的线程数。

  • 您可以使用UPDATE语句来修改CCL规则ID值,以调整目标规则的优先级。

    语法

    UPDATE mysql.concurrency_control SET ID = xx WHERE ID = xx;

    示例

    1. 执行以下命令,查看内存中已启用的CCL规则。

      CALL dbms_ccl.show_ccl_rule();

      执行结果如下:

      +------+--------+--------+-------+-------+-------+-------------------+---------+---------+----------+----------+
      | ID   | TYPE   | SCHEMA | TABLE | STATE | ORDER | CONCURRENCY_COUNT | MATCHED | RUNNING | WAITTING | KEYWORDS |
      +------+--------+--------+-------+-------+-------+-------------------+---------+---------+----------+----------+
      |   17 | SELECT | test   | t     | Y     | N     |                30 |       0 |       0 |        0 |          |
      |   16 | SELECT |        |       | Y     | N     |                20 |       0 |       0 |        0 | key1     |
      |   18 | SELECT |        |       | Y     | N     |                10 |       0 |       0 |        0 |          |
      +------+--------+--------+-------+-------+-------+-------------------+---------+---------+----------+----------+
    2. 执行以下命令,调整ID值为17的CCL规则的优先级,即将ID值修改为20。

      UPDATE mysql.concurrency_control SET ID = 20 WHERE ID = 17;
    3. 执行以下命令,查看修改后的已启用的CCL规则。

      CALL dbms_ccl.show_ccl_rule();

      执行结果如下:

      +------+--------+--------+-------+-------+-------+-------------------+---------+---------+----------+----------+
      | ID   | TYPE   | SCHEMA | TABLE | STATE | ORDER | CONCURRENCY_COUNT | MATCHED | RUNNING | WAITTING | KEYWORDS |
      +------+--------+--------+-------+-------+-------+-------------------+---------+---------+----------+----------+
      |   16 | SELECT |        |       | Y     | N     |                20 |       0 |       0 |        0 | key1     |
      |   18 | SELECT |        |       | Y     | N     |                10 |       0 |       0 |        0 |          |
      |   20 | SELECT | test   | t     | Y     | N     |                30 |       0 |       0 |        0 |          |
      +------+--------+--------+-------+-------+-------+-------------------+---------+---------+----------+----------+
  • flush_ccl_rule: 如果您通过修改表concurrency_control中的内容来修改CCL规则,则您还需要使用如下命令使该规则生效。

    语法

    dbms_ccl.flush_ccl_rule();

    示例

    通过使用UPDATE语句修改CCL规则ID来调整目标规则的优先级。

    UPDATE mysql.concurrency_control SET CONCURRENCY_COUNT = 15 WHERE Id = 18;

    执行结果如下:

    Query OK, 1 row affected (0.00 sec)
    Rows matched: 1  Changed: 1  Warnings: 0

    执行以下命令,使该设置生效。

    CALL dbms_ccl.flush_ccl_rule();

    执行结果如下:

    Query OK, 0 rows affected (0.00 sec)​

功能测试

  1. 分别以三个维度来创建CCL规则:

    CALL dbms_ccl.add_ccl_rule('SELECT', 'test', 'sbtest1', 3, '');  //使用SELECT语句操作test数据库下的表sbtest1,且并发数量为3。
    CALL dbms_ccl.add_ccl_rule('SELECT', '', '', 2, 'sbtest2');       //SELECT语句中包含关键字sbtest2,且并发数量为2。
    CALL dbms_ccl.add_ccl_rule('SELECT', '', '', 2, '');            //SELECT语句,且并发数量为2。
  2. 使用Sysbench进行测试,具体场景如下:

    • 64 threads

    • 4 tables

    • select.lua

  3. 查看规则并发数量,如下:

    CALL dbms_ccl.show_ccl_rule();

    执行结果如下:

    +------+--------+--------+---------+-------+-------+-------------------+---------+---------+----------+----------+
    | ID   | TYPE   | SCHEMA | TABLE   | STATE | ORDER | CONCURRENCY_COUNT | MATCHED | RUNNING | WAITTING | KEYWORDS |
    +------+--------+--------+---------+-------+-------+-------------------+---------+---------+----------+----------+
    |   20 | SELECT | test   | sbtest1 | Y     | N     |                 3 |     389 |       3 |        9 |          |
    |   21 | SELECT |        |         | Y     | N     |                 2 |     375 |       2 |       14 | sbtest2  |
    |   22 | SELECT |        |         | Y     | N     |                 2 |     519 |       2 |       34 |          |
    +------+--------+--------+---------+-------+-------+-------------------+---------+---------+----------+----------+
    3 rows in set (0.00 sec)

    查看RUNNING列,符合预期的并行数量。