文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

基于MySQL内核的SQL限流设计与实现

2024-11-29 20:33

关注

编写目的

本文详细描述了SQL限流特性的需求设计方案以及使用方式,开发、测试人员可根据本文实现功能的开发、测试,DBA可根据本文合理使用SQL限流功能。

需求概述

生产环境中可能出现由于业务量增长过快或者慢SQL等原因导致CPU使用率打满,当CPU打满时,会影响所有依赖该数据库实例的业务,因此需要有手段限制影响CPU的业务执行,保证其他核心业务不受影响。

SQL限流的目标是在出现CPU使用率打满影响所有业务时,通过限制非核心业务或者慢SQL的业务,实现核心业务的快速恢复。

软件结构

MySQL软件结构如下图所示:

图片

参考资料

MySQL官网:https://dev.mysql.com/doc/refman/5.7/en/

二、概要设计

架构设计

图片

总体架构如图所示,SQL限流的主要功能在执行器工作阶段通过限流规则与查询串的匹配来实现。

流程图

图片

三、详细设计

功能设计

对外接口

针对SQL限流功能设计对外提供管理命令,如下:

图片

用于控制限流功能是否启用。

图片

用于控制限流规则匹配时是否大小写敏感。

图片

限流功能对于预留用户不生效。

预留用户参数以字符串的形式接受输入,如果存在多个预留用户,使用 ',' 进行分隔。

在服务启动时,需格式化该参数,后续在做限流判断时,需要根据格式化之后参数识别是否是预留用户,如果是预留用户,则不进行限流操作,无需进行后续的限流规则匹配。

预留用户参数接受NULL和空串 '',当该参数为NULL或空串时,表明所有用户都不是预留用户。

对于预留用户字符串的处理,与MySQL社区对于用户名的处理逻辑保持一致,即忽略每个用户名前后的无意义字符(如空格、换行等),保留用户名之间的无意义字符。

图片

用于控制限流规则的分隔符。

分隔符不可为空,且长度小于等于1024。

修改分隔符之后,需要重新加载限流规则,对限流规则进行解析,会消耗系统资源,因此不建议在系统负载过高时修改分隔符。

对于预留用户的处理,核心功能如下:

// 更新
static bool update_delimiter(sys_var *self, THD *thd, enum_var_type type)
{
  reload_rules(thd);
}


// 校验
static bool check_delimiter(sys_var *self, THD *thd, set_var *var)
{
  judge(var->value);
  judge(str);
  judge(length);
}

功能模块详细设计

SQL限流使用的场景为CPU负载过高,为了防止加重系统的负担,限流规则应该事先加载到内存中。基于此,需要对内存中的限流规则进行管理,涉及的操作有:规则的读取、移除、解析。

读取

规则读取的场景有:

移除

规则移除的场景有:

解析

用户输入的规则在物理表中的表现是一个字符串,在将其加载到内存时,需要根据限流规则的分隔符将其解析为对应的规则模式串,在模式串中包含的关键字全部被满足时,需要进行限流。解析过程如下:

SQL限流的的流程控制添加在SQL执行阶段,主要的内容有:

启动时:

int mysqld_main(int argc, char **argv)
{
  ...
  load_rules();
  ...
}

执行时:

void dec_conc(THD *thd, int command)
{
  // 根据查询类型在对应链表找节点
  node = find_by_id(list, thd->id);


  // 并发数量减1
  if (node) {
    __sync_sub_and_fetch(&(node->concur), 1);
  }
  
  // 重置状态
  thd->id = 0;
}

关闭时:

关闭服务时,释放限流规则占用的内存资源(遍历规则链表,释放其中每一个节点占用的内存)。

void clean_up()
{
  cleanup();
}

SQL限流的基本功能的实现逻辑为查询串与规则串的匹配,匹配主要的策略如下:

根据DB判断是否是对系统表的查询,如果是对系统表的查询,不做限流。


  if (check_system_table(first_table->db)) {
    return ret;
  }

针对不同的操作类型,在相应的限流规则链表上做模式匹配。

bool check_rule_matched(THD* thd, LIST* list)
{
  while (满足条件,无异常) {
    // 根据大小写开关是否打开,分别进行模式串匹配
    it = find(query_str, item->key_array[nums]);
      
    // 如果it为空,没有匹配到,查看下一个list,否则继续匹配当前限流规则节点
    judge();
  }


  // 匹配成功,或者对下一个节点进行匹配
}

在匹配过程中维护原子变量cur_concur、cur_reject、total_reject,分别表示当前并发数、当前限流次数、总的限流次数,用以判断是否需要进行限流以及在系统运行期间观察SQL限流的执行状态。

用户输入的限流规则保存在限流规则系统表中,在需要读取物理表中的数据时,需要打开表、读取数据、关闭表。

通过创建限流规则表读取类来控制对表的操作,类的定义如下:

class Du_table_access {
public:
  Du_table_access() : m_drop_thd_object(NULL) {}
  virtual ~Du_table_access() {}


  // 初始化打开表的环境、锁表并且打开表
  bool init(THD **thd, TABLE **table, bool is_write);
  
  // 关闭表,清理环境
  bool deinit(THD *thd, TABLE *table, bool error, bool need_commit);
  
  // 设置打开表的策略
  void before_open(THD *thd);
  
  // 如果需要的话创建线程,大部分时候并不需要,因为手动执行读取数据的时候已经在线程中了
  THD *create_thd();
  
  // 如果手动创建了 thd,则需要手动清理
  void drop_thd(THD *thd);
};

读取到的数据以节点的形式保存,并且挂在LIST中进行管理。

限流规则表设计

图片

SET @cmd= "CREATE TABLE IF NOT EXISTS du_flow_control_rules (
    id BIGINT NOT NULL AUTO_INCREMENT COMMENT 'Id of the flow control rules.',
    type ENUM('SELECT', 'UPDATE', 'INSERT', 'DELETE') CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL COMMENT 'Type of flow control rules.',
    max_concur INT NOT NULL COMMENT 'Max concurrent of sql.',
    orig_str VARCHAR(1024) CHARSET SET utf8mb4 COLLATE utf8mb4_bin NOT NULL COMMENT 'Original string of flow control rules.',
    PRIMARY KEY(id)) DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT 'Flow control rules info.'";


SET @str=IF(@have_innodb <> 0, CONCAT(@cmd, ' ENGINE= INNODB;'), CONCAT(@cmd, ' ENGINE= MYISAM;'));
PREPARE stmt FROM @str;
EXECUTE stmt;
DROP PREPARE stmt;

通过存储过程实现权限与格式控制:

DELIMITER $$


CREATE DEFINER='root'@'localhost' PROCEDURE mysql.add_flow_control ( IN sql_type INT, IN str VARCHAR(1024), IN max_num INT )
    COMMENT '
Description
-----------
Basic functions for inserting rules.
It is not recommended to call it directly, but to call it through add_select_flow_control、
add_update_flow_control、add_update_flow_control and add_delete_flow_control.
'
    SQL SECURITY INVOKER
BEGIN
    IF (sql_type = 0) THEN
        INSERT INTO mysql.du_flow_control_rules(type, max_concur, orig_str) VALUES('SELECT', max_num, str);
    ELSEIF (sql_type = 1) THEN
        INSERT INTO mysql.du_flow_control_rules(type, max_concur, orig_str) VALUES('UPDATE', max_num, str);
    ELSEIF (sql_type = 2) THEN
        INSERT INTO mysql.du_flow_control_rules(type, max_concur, orig_str) VALUES('INSERT', max_num, str);
    ELSEIF (sql_type = 3) THEN 
        INSERT INTO mysql.du_flow_control_rules(type, max_concur, orig_str) VALUES('DELETE', max_num, str);
    ELSE
        SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Sql type is error, please input correctly.';
    END IF;
END$$


CREATE DEFINER='root'@'localhost' PROCEDURE mysql.add_select_flow_control (IN str VARCHAR(1024), IN max_num INT )
    COMMENT '
Description
-----------
Used to add select type rules to the current rule table.


Parameters
-----------


str (VARCHAR(1024)):
  The string of select rules entered by user.


max_num (INT):
  The number of queries that can be executed concurrently.


Example
--------


mysql> SELECT * FROM du_flow_control_rules;
Empty set (0.00 sec)


mysql> CALL add_select_flow_control(''select~from~t1'', 100);
Query OK, 1 row affected (0.00 sec)


mysql> SELECT * FROM du_flow_control_rules;
+----+--------+------------+----------------+
| id | type   | max_concur | orig_str       |
+----+--------+------------+----------------+
|  1 | SELECT |        100 | select~from~t1 |
+----+--------+------------+----------------+
1 row in set (0.00 sec)
'
    SQL SECURITY INVOKER
BEGIN
    CALL add_flow_control(0, str, max_num);
END$$
DELIMITER ;

性能设计

当开关关闭时,对于每一个查询在内核中执行,增加了对开关是否打开的判断的消耗,该操作对于整个语句的执行来说影响较小,可以忽略。

当开关打开时,需要将查询字符串与限流规则进行匹配,整个过程是内存操作,且根据类型将限流规则分为不同的链表,加快匹配速度,整个过程对性能的影响与限流规则的数量以及复杂度有关(注:加入SQL限流特性对系统有影响,影响程度与限流规则的数量和复杂度有关,但实际使用场景是针对少部分业务进行限流,且不需要限流的时候不启用该功能,因此该场景对性能的影响不决定最终实现)。

性能设计:

由于分隔符的选择决定了限流规则的不同形式,因此修改分隔符会导致限流规则全部重新加载解析一次,尽量不在业务高峰期修改分隔符。

SQL限流的性能取决于限流规则的数量、关键字数量、查询的单词数量,因此在使用时,应尽量使用较为通用的限流规则。

功能限制

四、总结

本文详细描述了基于MySQL内核的SQL限流功能的整体架构、主要功能模块等关键要素。SQL限流的设计与实现基于原生MySQL的执行原理与字符串匹配规则实现。整体功能对原生MySQL嵌入修改较少,除了对是否进行限流的判断以外,其他功能以独立模块呈现,安全可控。

来源:得物技术内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯