为了应对突发的数据库请求流量、资源消耗过高的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规则:
根据DIGEST值匹配。
根据TYPE、SCHEMA和TABLE匹配。
仅根据TYPE匹配。
参数说明
您可以在PolarDB控制台修改以下参数,具体操作步骤请参见设置集群参数和节点参数。
参数 | 说明 |
loose_ccl_mode | 超出并发数量时,SQL语句的行为。取值如下:
说明 仅PolarDB MySQL版 8.0版本支持该参数。5.6和5.7版本直接进行排队等待。 |
loose_ccl_max_waiting_count | 当 取值范围: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 | 并发数量。 说明 您可以将 |
Keywords | 关键字,多个关键字使用英文分号(;)分隔。 |
State | 规则是否启用,取值范围如下:
|
Ordered | Keywords中配置多个关键字时,是否按顺序匹配CCL规则。取值范围如下:
|
Digest | 使用 |
Digest_text | SQL语句的特征。 |
Extra | 其它信息。 |
管理CCL规则
为了便捷地管理CCL规则,PolarDB在DBMS_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);
其中,
533c0a9cf0cf92d2c26e7fe8821735eb4a72c409aaca24f9f281d137427bfa9a
为SELECT * 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;
命令来查看警告内容。示例如下:删除规则ID为100的CCL规则。
CALL dbms_ccl.del_ccl_rule(100);
执行结果如下:
Query OK, 0 rows affected, 2 warnings (0.00 sec)
执行以下命令,查看告警内容。
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版本的
Code
为7517
、PolarDB MySQL版 5.7版本的Code
为3267
、PolarDB MySQL版 5.6版本的Code
为3045
。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 | | +------+--------+--------+-------+-------+-------+-------------------+---------+---------+----------+----------+
说明其中,MATCHED、RUNNING和WAITTING参数的说明如下:
MATCHED:规则匹配成功次数。
RUNNING:该规则下正在并发执行的线程数。
WAITTING:该规则下正在等待执行的线程数。
您可以使用UPDATE语句来修改CCL规则ID值,以调整目标规则的优先级。
语法
UPDATE mysql.concurrency_control SET ID = xx WHERE ID = xx;
示例
执行以下命令,查看内存中已启用的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 | | +------+--------+--------+-------+-------+-------+-------------------+---------+---------+----------+----------+
执行以下命令,调整ID值为17的CCL规则的优先级,即将ID值修改为20。
UPDATE mysql.concurrency_control SET ID = 20 WHERE ID = 17;
执行以下命令,查看修改后的已启用的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)
功能测试
分别以三个维度来创建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。
使用Sysbench进行测试,具体场景如下:
64 threads
4 tables
select.lua
查看规则并发数量,如下:
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列,符合预期的并行数量。