为了确保 MySQL 实例在面对突发请求流量、高资源消耗语句和 SQL 访问模型变化时的稳定运行,阿里云提供了基于语句规则的并发控制(CCL)及相应的工具包(DBMS_CCL)。通过 DBMS_CCL,您可以限制特定类型 SQL 语句的最大并行执行数量。当指定 SQL 的并行执行数达到设定的限额后,额外的 SQL 语句则会进入等待状态,直到 SQL 的并行数量小于设定的限额。
前提条件
实例版本如下:
-
MySQL 8.0(内核小版本 20190816 或以上)
-
MySQL 5.7(内核小版本 20200630 或以上)
参数说明
参数 |
说明 |
ccl_max_waiting_count |
命中同一条
CCL
规则的
SQL
中,最多能处于
|
ccl_wait_timeout |
处于
|
注意事项
-
CCL 的操作不产生日志,所以 CCL 的操作只影响当前实例。例如主实例进行 CCL 操作,不会同步到备实例、只读实例或灾备实例。
-
CCL 提供超时机制以应对 DML 导致事务锁死锁,等待中的线程也会响应事务超时和线程 KILL 操作以应对死锁。
功能设计
CCL 规则定义了如下四个维度的特征:
-
SQL command
SQL 命令类型,例如 SELECT、UPDATE、INSERT、DELETE 等。
-
Object
SQL 命令操作的对象,例如 TABLE、VIEW 等。
-
keywords
SQL 命令的关键字。
-
Template
SQL 命令的模板。
创建 CCL 规则表
AliSQL 设计了一个系统表(concurrency_control)保存 CCL 规则,系统启动时会自动创建该表,无需您手动创建。这里提供表的创建语句供您参考:
CREATE TABLE `concurrency_control` (
`Id` bigint NOT NULL AUTO_INCREMENT,
`Type` enum('SELECT','UPDATE','INSERT','DELETE','TEMPLATE') CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT 'SELECT',
`Schema_name` varchar(64) COLLATE utf8mb3_bin DEFAULT NULL,
`Table_name` varchar(64) COLLATE utf8mb3_bin DEFAULT NULL,
`Concurrency_count` bigint NOT NULL,
`Keywords` text COLLATE utf8mb3_bin,
`State` enum('N','Y') CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT 'Y',
`Ordered` enum('N','Y') CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT 'N',
`Digest` varchar(64) COLLATE utf8mb3_bin DEFAULT NULL,
`SQL_template` longtext COLLATE utf8mb3_bin,
PRIMARY KEY (`Id`)
) /*!50100 TABLESPACE `mysql` */ ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_bin STATS_PERSISTENT=0 COMMENT='Concurrency control'
参数 |
说明 |
Id |
CCL 规则 ID。 |
Type |
SQL command,即 SQL 命令类型。 |
Schema_name |
数据库名。 |
Table_name |
数据库内的表名。 |
Concurrency_count |
并发数。当并发数设置为
0,会拒绝所有匹配该规则的
SQL
执行并返回错误码
|
Keywords |
关键字,多个关键字用英文分号(;)分隔。 |
State |
本规则是否启用。 |
Ordered |
Keywords 中多个关键字是否按顺序匹配。 |
Digest |
根据 SQL_template 进行 Hash 计算得到的 64 字节的 Hash 字符串。 |
SQL_template |
SQL 语句的模板。 |
管理 CCL 规则
为了便捷地管理 CCL 规则,AliSQL 在 DBMS_CCL 中定义了四个本地存储规则。详细说明如下:
-
add_ccl_rule
增加规则。命令如下:
dbms_ccl.add_ccl_rule('<Type>','<Schema_name>','<Table_name>',<Concurrency_count>,'<Keywords>');
示例:
增加 SQL 命令规则,SELECT 语句的并发数为 10。
mysql> call dbms_ccl.add_ccl_rule('SELECT', '', '', 10, '');
增加关键字规则,SELECT 语句中出现关键字 key1 的并发数为 20。
mysql> call dbms_ccl.add_ccl_rule('SELECT', '', '', 20, 'key1');
增加完整规则,test.t 表且出现关键字 key2 的 SELECT 语句的并发数为 20。
mysql> call dbms_ccl.add_ccl_rule('SELECT', 'test', 't', 20, 'key2');
-
add_ccl_template_rule
增加模板规则。命令如下:
dbms_ccl.add_ccl_rule('<Type>','<Schema_name>','<Table_name>',<Concurrency_count>,'', 'Template_sql');
说明-
Table_name 无需填写。Template_sql 不能为空并且只能填写一条 SQL。
-
可以通过 STATEMENT_DIGEST_TEXT 内置函数查看 SQL 对应的 SQL 模板。
-
仅适用于 MySQL 8.0 版本(小版本为 20230630 及之后版本)。
示例:
增加模板规则,test 数据库下,SQL 模板为
'SELECT c FROM t1 WHERE id=?'
的并发数为 30。call dbms_ccl.add_ccl_rule('TEMPLATE', 'test', '', 30, '', 'SELECT c FROM t1 WHERE id=4');
说明-
在匹配限流规则时,每条 SQL 语句只能匹配一条限流规则。
-
规则匹配的优先级顺序如下:模板规则 > 完整限流规则 > 关键字规则 > SQL 命令规则。依次检查每个规则集,以确定是否存在匹配的限流规则。
-
-
del_ccl_rule
删除规则。命令如下:
dbms_ccl.del_ccl_rule(<Id>);
示例:
删除规则 ID 为 15 的 CCL 规则。
mysql> call dbms_ccl.del_ccl_rule(15);
说明如果删除的规则不存在,系统会报相应的警告,您可以使用
show warnings;
查看警告内容。mysql> call dbms_ccl.del_ccl_rule(100); Query OK, 0 rows affected, 2 warnings (0.00 sec) mysql> show warnings; +---------+------+----------------------------------------------------+ | Level | Code | Message | +---------+------+----------------------------------------------------+ | Warning | 7514 | Concurrency control rule 100 is not found in table | | Warning | 7514 | Concurrency control rule 100 is not found in cache | +---------+------+----------------------------------------------------+
-
show_ccl_rule
查看内存中已启用规则。命令如下:
dbms_ccl.show_ccl_rule();
示例:
mysql> 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
此规则下正在等待执行的线程数。
-
flush_ccl_rule
如果您直接操作了表 concurrency_control 修改规则,规则不能立即生效,您需要让规则重新生效。命令如下:
dbms_ccl.flush_ccl_rule();
示例:
mysql> 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 mysql> call dbms_ccl.flush_ccl_rule(); Query OK, 0 rows affected (0.00 sec)
功能测试
-
测试规则
设计如下三条规则对应三个维度:
-- SELECT命令操作表sbtest1并发数为3 call dbms_ccl.add_ccl_rule('SELECT', 'test', 'sbtest1', 3, ''); -- SELECT命令关键字sbtest2并发数为2 call dbms_ccl.add_ccl_rule('SELECT', '', '', 2, 'sbtest2'); -- SELECT命令并发数为2 call dbms_ccl.add_ccl_rule('SELECT', '', '', 2, '');
-
测试场景
使用 sysbench 进行测试,场景如下:
-
64 threads
-
4 tables
-
select.lua
-
-
测试结果
查看规则并发数情况如下:
mysql> 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 列,符合预期的并行数量。