zoukankan      html  css  js  c++  java
  • Inception的备份语句生成原理分析

    Inception是对MySQL数据库的线上运维操作进行辅助的一个工具,它能提供SQL的审核、执行、备份的操作,保证运维的可靠性。

    现在为了在公司中使用这个工具来减轻我们的运维工作负担,开始着手使用它。

    问题

    使用之前,我们需要了解这个工具的原理,包括它对一些我们关注的方面的解决方式,以及在出现一些问题时我们应该怎样应对解决。

    • 首先,我们需要用到它的审核SELECT类型SQL功能,那么它的审核功能是怎么实现的?一些审核配置项是怎么发生作用的?
    • 其次,我们还需要用到它的DML操作功能,Inception是怎样完成在审核SQL的同时还能执行?执行完成后是怎么生成反向恢复语句?如果在执行多条语句的时候中途发生了错误,后续的语句还会执行吗?如果在执行过程中网络发生问题,执行结果又是怎样的?
    • 等等。。。

    带着这些问题,我们开始一点点探索它内部的一些细节流程。

    代码分析

    我们先从执行函数的创建阶段开始查找,找到执行流程的具体入口在什么位置,以及这个具体入口是怎样被创建的。

    • 执行流程创建

    通过GDB的定位以及代码的分析,我们可以得到Inception的具体工作是在新创建的工作线程中完成,而这个工作线程的入口钩子函数就是实际的处理函数:

     而钩子函数的挂钩的过程是在进程刚启动时的初始化函数中完成的:

    根据上面两个流程图,我们得到的结论是Inception在启动成功后,一旦接收到SQL语句的请求,就会创建新的线程,而这个创建新线程的钩子函数是指向create_thread_to_handle_connection(), 在这个函数会创建线程来处理对SQL语句块的分析、检查、执行和备份流程。

    • 执行SQL流程分析

    在create_thread_to_handle_connection()函数中,新创建的线程入口函数为handle_one_connection(),从这个函数中,我们可以继续查找到SQL语句块的分析、检查、执行和备份流程以及回滚语句的具体执行位置,执行流程图如下所示:

    上图从左往右的顺序就是函数栈的从上往下的顺序,一直到最底层实现具体逻辑的地方。

    以下内容会对这个图的各个部分进行拆解分析。

    • SQL检查流程

    当Inception监听的端口收到连接请求后,就会调用create_new_thread()函数,其中创建的新线程的入口函数钩子已经在Inception的main函数开始阶段确定下来,它是指向handle_one_connection()函数。

    在handle_one_connection()函数中,会将输入的SQL语句进行处理(语法词法解析、检查规范、执行、备份语句等操作),处理完成后将结果给传回到客户端。

    在一个Inception语句块中,一定会包含多条语句,因为它需要满足以下格式的语句块:

    1 /*--user=inception_user;--password=123456;--host=192.168.1.200;--enable-execute;--port=3363;*/ 
    2 inception_magic_start;
    3 use test_2;
    4 update test set name="aaaaab" where id=20; 
    5 inception_magic_commit;

    第1行是Inception语句块的头信息,放在SQL的注释块中

    第2行是Inception语句块的起始标记

    第3~4行是Inception语句块,客户端需要处理的SQL语句

    第5行是Inception语句块的结束标记

    头信息、开始标记、结束标记必然是需要的,语句块信息也至少是1句SQL,每条语句经过语法解析后,会得到一棵语法树,交由mysql_process_command()进行处理。

    此函数对每个语句生成的语法树都会进行处理,在处理到Inception_magic_commit对应的语法树之前,都是检查的过程,只有在处理完它之后才会进行执行(如果在头信息中指定的是--enable-check而不是--enable-execute后续就不会有执行的操作发生了,只是将得到的检查结果发回给客户端)。

    在mysql_parse()中生成了一条语句的语法树后,会继续执行对这条语句的处理流程,其中检查过程是在mysql_check_command()函数中完成的,包括检查dml语句是否有where条件(inception_check_dml_where)、inception_check_dml_limit、inception_check_dml_orderby、inception_enable_select_star等等检查项。

    • 执行流程

    在对所有语句的检查完成后,会进入到mysql_execute_commit()函数,开始进行所有语句的执行,每条语句按照顺序执行,并且每条语句都是独立的事务,如果中途有一条语句发生错误,后续的语句就不会执行了。

    如果在执行过程中发生网络问题,那么这条语句对应到这个事务是否完成是未知的,但是对于Inception而言,发生网络错误了就相当于这条语句执行失败,后续的语句就不会执行了,当前的这条语句会标记为失败,也就不会有回滚语句备份。

    • 生成回滚语句流程

    在执行过程完成后,就开始对每条语句逐个进行回滚语句解析并备份:

    从下图中可以看出备份是在执行完成之后,在mysql_backup_sql()中逐条解析语句的binlog,对于每个语句在执行的过程中记录了该语句执行之前的binlog pos和之后的binlog pos,以及该连接的thread_id, 使用这三个值可以对每条语句的binlog进行精确定位,从而可以得到这个语句的所有binlog。

    每条语句的binlog中可能包含多个event,每个event可以解析出一条回滚语句。

    如果在binlog的传输过程中发生网络错误,Inception给每条语句的备份流程中进行重试的机会有三次,如果重试次数超过三次,这条语句的回滚语句就会备份失败。

     

    上面这张图是Inception的回滚语句备份流程,会对不同的语句类型执行不同的event解析过程。具体的解析过程后续会有文章再分析。

    结论

    这篇文章从Inception的DML语句的检查、执行、备份的实现流程的角度去分析了它的源码执行流程:

    检查过程是在mysql_check_command()过程中完成的,这个过程发生在每条语句的语法树生成之后,在执行所有语句之前。

    执行过程是在mysql_execute_commit()函数中完成,在这个函数中会在线上服务器上逐条执行每个sql语句,执行结果中会包含执行前的binlog位置和执行后的binlog位置以及thread_id

    备份过程是在执行过程完成之后,逐条语句分析对应的binlog(流式下载到Inception端),然后根据在执行时记录的执行前binlog位置和执行后的binlog位置以及thread_id来得到属于这条语句的所有binlog,解析为回滚语句并备份到备份服务器上。

    通过源码的分析,在后面的使用中如果碰到了一些问题可以很容易定位,如果有需要的话直接上手改也是一个不错的选择,即解决了自己的问题也为开源工具的发展做出一点贡献。

  • 相关阅读:
    如何实现一个教师与学生教学辅助平台?
    面向过程(或者叫结构化)分析方法与面向对象分析方法到底区别在哪里?请根据自己的理解简明扼要的回答。
    2..移动APP开发使用什么样的原型设计工具比较合适?
    new delete和malloc free的区别
    char * 和char[]的区别以及怎样与string类型进行转换
    浅谈const的基本用法
    c++ map按key或value的值分别进行排序
    二叉树及先序,中序,后序遍历
    c++发展趋势
    markdown 的基本操作
  • 原文地址:https://www.cnblogs.com/lifewithlight/p/7563046.html
Copyright © 2011-2022 走看看