详解MySQL kill 指令的执行原理

kill 指令有两种写法 " kill query + 线程 id "、" kill connection(可缺省) + 线程 id "。分别表示关闭指定线程正在执行的语句、断开指定线程连接的客户端(如果有正在执行的操作会先停止执行的操作再关闭连接)。但某些情况下使用 kill query 后使用 show processlist 查看 Command 列为 killed(表示 正在等待回收线程回收,还未回收),这是为什么呢?

在解答这个问题前,需要知道服务器端处理请求的线程是如何执行的,以及 kill 命令是如何作用的。

Kill 指令执行原理

指令执行特点

1、 一个语句执行过程中有多处 " 埋点 ",在这些 " 埋点 " 的地方判断线程状态,如果发现线程状态是 THD:KILL_QUERY,才开始进入语句终止逻辑;

2、如果处于等待状态,必须是一个可以被唤醒的等待,否则根本不会执行到“埋点”处;

3、语句从开始进入终止逻辑,到终止逻辑完全完成,是有一个过程的。

kill query 执行原理

kill query 主要进行了两步操作:

1、把线程的运行状态改成 THD::KILL_QUERY(将变量 killed 赋值为 THD::KILL_QUERY);

2、给会话的执行线程发一个信号,退出阻塞状态,处理这个状态。

Kill Connection 执行原理

1、把 12 号线程状态设置为 KILL_CONNECTION;

2、关掉 12 号线程的网络连接。

是否可以被中断判断

1、一般正常执行的语句在执行 kill query 后都会先将状态从 killed 改成 KILL_QUERY,然后执行到 " 埋点 " 处被判断中断执行。

2、如果是处于阻塞的语句,那么需要去查看当前阻塞等待的状态是否可以被唤醒,如果可以被唤醒才有机会中断当前语句。

可以被中断的场景:正常执行或者处于可以被唤醒的阻塞等待状态。

因为等行锁时,使用的是 pthread_cond_timedwait 函数,所以这个等待状态可以被唤醒。可以被 kill query 直接唤醒继续执行直到 "埋点" 判断。

不可以被中断的场景:被阻塞且不能被唤醒。

例子:因并发线程被使用完而造成的阻塞。

将参数 innodb_thread_concurrency(MySQL 的并发线程数)设为 2。然后执行下面的操作:

在 sessionD 执行 kill query C 后 sessionC 并没有退出阻塞。

  • 问题1:为什么使用 kill query 没有中断阻塞?

答:因为这种阻塞从微观上来看并不是阻塞,而是一种循环判断。每隔 10 毫秒判断一下是否可以进入 Innodb 执行,如果不行,就调用 nanosleep 函数进入 sleep 状态。也就是说,虽然线程的状态已经被设置成了 KILL_QUERY(THD::KILL_QUERY),但是在这个等待进入 InnoDB 的循环过程中,并没有执行到 "埋点",也就没有去判断线程的状态,因此根本不会进入终止逻辑阶段。所以也就不会中断。

  • 问题2:如果此时使用 show processlist 来查看,会发现 Command 列为 killed,这是为什么?

答:kill query 语句会将线程状态设为 KILL_QUERY ,这时会因为这个状态而被判断为正在执行中断逻辑,所以 Command 值为 killed。

  • 问题3:为什么使用 kill connection 可以中断阻塞?

答:因为 kill connection 会直接关闭线程的网络连接,强制关闭,所以这时候 session C 收到了断开连接的提示。

  • 问题4:如果只是使用 kill query 什么时候才能中断阻塞?

答:只有等到会话被分配了线程后执行到 “ 埋点 ” 后判断然后执行中断逻辑才会退出。而被分配线程后并不是就一定会中断,如果在执行到 "埋点" 之前让出线程,那么就会再次等待。MySQL 的线程是多路复用的。

其他

1、其实除了上面使用 kill 命令来终止阻塞状态外,还可以直接在该会话中使用 “ ctrl+c ” 来中止阻塞,这又是什么原理呢?

答:首先要知道客户端操作服务端是客户端开启一个线程,让这个线程去处理,发送请求数据,通过网络传输到服务端,服务端再分配线程去处理。而 "ctrl +c " 是让客户端另开一个连接,并发送一个 kill query 的命令。所以虽然我们看来是中断了阻塞,但是处理上一个连接的服务端线程并一定就会被中断。

2、为什么在指定库名连接时会很慢?如下图:

答:这是由于 MySQL 默认开启了自动补全功能(输入表名时可以使用 tab 自动补全)。其实现是在连接数据库多执行一些操作:

1、执行 show databases;
2、切到 db1 库,执行 show tables;
3、把这两个命令的结果用于构建一个本地的哈希表。(最耗时)

这个功能可以在命令中加上 -A 关闭。同时使用 -quick 也可以关闭。但是使用 -quick 可能会使客户端性能降低。这是为什么?这就要说到数据在服务器端与客户端发送的流程了。

服务器线程执行流程

客户端首先与服务器端验证用户名和密码,通过后正式建立连接,然后客户端发送请求,服务器端从线程池中取一个线程来处理。处理的过程:

1、获取一行,写到 net_buffer 中。这块内存的大小是由参数 net_buffer_length 定义的,默认是 16k。
2、重复获取行,直到 net_buffer 写满,调用网络接口发出去。
3、如果发送成功,就清空 net_buffer,然后继续取下一行,并写入 net_buffer。
4、如果发送函数返回 EAGAIN 或 WSAEWOULDBLOCK,就表示本地网络栈(socket send buffer)写满了,进入等待。直到网络栈重新可写,再继续发送。

从上面的流程可以知道,如果一次要发送的数据量超过 socket send buffer 空间,那么就会拆分开来发送,并不会发生 " 内存打爆 " 的情况。由此我们可以知道,MySQL 是边读边发的。

1、如果请求返回的数据量很大,那么在等待返回的过程中使用 show processlist 查看 State 列的值就会为 " Sending to client",表示服务器端的网络栈写满了。

这是因为 Sate 列值的变化是在查询请求到达开始执行就会变为 " Sending data ",如果网络栈写满发就会切换为 " Sending to client ",表示 " 正在等待客户端接收结果 "。" Sending data " 可能处于线程执行过程中的任意阶段,比如因为锁而阻塞的场景。

2、如果 show processlist 的 State 列一直为 " Sending to Client ",那么可以

  1)查看这条SQL,判断是否可以优化,减少返回值。

  2)将 net_buffer_length 设的大一些,来避免或者减少发送阻塞的时间。

客户端执行流程

在开始客户端会创建线程去连接服务器端,然后接收服务端返回的数据,客户端接收服务器端返回的数据有两种方式:

1、本地缓存。在本地开一片内存,先把结果存起来。如果用 API 开发,对应的就是 mysql_store_result 方法。建议在客户端处理量大时使用本地缓存。可以使用 mysql -h$host -P$port -u$user -p$pwd -e "select * from db1.t" > $target_file 将返回的数据保存到指定文件。

2、不缓存,读一个处理一个。如果用 API 开发,对应的就是 mysql_use_result 方法。

回到上面的问题,为什么使用 -quick 可能会导致客户端性能下降?这是因为客户端默认使用缓存来接收,所以在客户端正在处理其他数据时就可以先进行缓存,等到后面直接读取缓存就可以了。而使用 quick 就会使客户端接收不使用缓存,那么如果客户端正在执行其他操作这个数据就会被阻塞,并且服务器端对应的线程也会因为没有收到客户端的反馈而没有中断这次事务,这次事务涉及到的资源锁也没有释放,造成并发问题,影响效率。除此之外, quick 还有三个效果。

1、就是前面提到的,跳过表名自动补全功能。
2、客户端接收数据使用不缓存的方式。而 mysql_store_result 方法需要申请本地内存来缓存查询结果,如果查询结果太大,会耗费较多的本地内存,可能会影响客户端本地机器的性能;
3、不会把执行命令记录到本地的命令历史文件。

以上就是详解MySQL kill 指令的执行原理的详细内容,更多关于MySQL kill 指令的资料请关注我们其它相关文章!

(0)

相关推荐

  • MySQL Slave 触发 oom-killer解决方法

    最近经常有收到MySQL实例类似内存不足的报警信息,登陆到服务器上一看发现MySQL 吃掉了99%的内存,God ! 有时候没有及时处理,内核就会自己帮我们重启下MySQL,然后我们就可以看到 dmesg 信息有如下记录: Mar 9 11:29:16 xxxxxx kernel: mysqld invoked oom-killer: gfp_mask=0x201da, order=0, oom_adj=0, oom_score_adj=0 Mar 9 11:29:16 xxxxxx kerne

  • MySQL kill指令使用指南

    KILL [CONNECTION | QUERY] processlist_id 在Mysql中每个连接都是单独线程运行,可以使用语句 KILL processlist_id statement.来终止语句执行. KILL允许可选 CONNECTION或QUERY 修饰符: KILL CONNECTION ,KILL与无修饰符相同 :终止与给定关联的连接 processlist_id,在终止该连接正在执行的任何语句之后. KILL QUERY终止连接当前正在执行的语句,但保持连接本身不变. 使用

  • MySQL OOM 系统二 OOM Killer

    这里就涉及到一个问题,到底Kill掉谁呢?一般稍微了解一些Linux内核的同学第一反应是谁用的最多,就Kill掉谁.这当然是Linux内核首先考虑的一种重要因素,但是也不完全是这样的,我们查一些Linux的内核方面的资料,可以知道其实Kill谁是由/proc/<pid>/oom_score来决定的,这个值每个进程一个,是由Linux内核的oom_badness()函数负责计算的.那下面我们来仔细读一读badness()函数. 在badness()函数的注释部分,写明了badness()函数的处

  • 批量 kill mysql 中运行时间长的sql

     KILL语法 KILL [CONNECTION | QUERY] thread_id 每个与mysqld的连接都在一个独立的线程里运行,您可以使用SHOW PROCESSLIST语句查看哪些线程正在运行,并使用KILL thread_id语句终止一个线程. KILL允许自选的CONNECTION或QUERY修改符: · KILL CONNECTION与不含修改符的KILL一样:它会终止与给定的thread_id有关的连接. · KILL QUERY会终止连接当前正在执行的语句,但是会保持连接的

  • Mysql误删数据解决方案及kill语句原理

    mysql误删数据 使用delete语句误删数据行 使用drop table或者truncate table误删数据表 使用drop database语句误删数据库 使用rm误删mysql整个实例 对于误删行 使用flashback工具闪回,把数据恢复回来.原理是修改binlog的内容,拿回原库重放,需要确保binlog_format=row和binlog_row_imsge=Full 具体恢复时 如果是insert,将binlog event类型是write_rows event改为delet

  • MySQL OOM 系列三 摆脱MySQL被Kill的厄运

    前面两章,我们分析了Linux内存分配的策略以及Linux通过使用 OOM_Killer的机制解决了"超售"引起的风险,MySQL同其他的应用程序一样,在操作系统允许的范围内也是可以超售的,一般人理解,Innodb_buffer_pool必须小于实际物理内存,否则MySQL会启动失败.其实这是一个误区,这个不是MySQL层控制的,这个是操作系统(OS)层控制的,就是前面提到的/proc/sys/overcommit_memory控制OS是否允许"超售".如果允许&q

  • percona-toolkit之pt-kill 杀掉mysql查询或连接的方法

    pt-kill 是一个非常简单的 杀mysql线程和查询的 工具. 主要是为了防止一些长的查询 长时间占用 系统资源,而对线上业务造成影响的情况. 主要作用: 从show processlist 中获取满足条件的连接或者从包含show processlist的文件中读取满足条件的连接并打印或者杀掉或者执行其他操作. 我们这里主要用来防止某些select操作时间过长,从而影响其他线上SQL. 安装: 安装percona-toolkit即可 使用范例: pt-kill --log-dsn D=tes

  • Mysql使用kill命令解决死锁问题(杀死某条正在执行的sql语句)

    在使用mysql运行某些语句时,会因数据量太大而导致死锁,没有反映.这个时候,就需要kill掉某个正在消耗资源的query语句即可, KILL命令的语法格式如下: KILL [CONNECTION | QUERY] thread_id 每个与mysqld的连接都在一个独立的线程里运行,您可以使用SHOW PROCESSLIST语句查看哪些线程正在运行,并使用KILL thread_id语句终止一个线程. KILL允许自选的CONNECTION或QUERY修改符:KILL CONNECTION与不

  • 详解MySQL kill 指令的执行原理

    kill 指令有两种写法 " kill query + 线程 id "." kill connection(可缺省) + 线程 id ".分别表示关闭指定线程正在执行的语句.断开指定线程连接的客户端(如果有正在执行的操作会先停止执行的操作再关闭连接).但某些情况下使用 kill query 后使用 show processlist 查看 Command 列为 killed(表示 正在等待回收线程回收,还未回收),这是为什么呢? 在解答这个问题前,需要知道服务器端处理

  • 详解MySQL 查询语句的执行过程

    首先先简单的将一个查询语句背后MySQL做了什么捋一捋: 客户端发送一条查询给服务器. 服务器先检查查询缓存,如果命中了缓存,则立刻返回存储在缓存中的结果.否则进入下一个阶段. 服务器端进行SQL解析,预处理,再由优化器生成对应的执行计划. MySQL根据优化器生成的执行计划,调用存储引擎的API来执行查询. 将结果返回给客户端. 接着我们就将这个过程中的这些步骤详细的进行展开. 1.客户端和服务器端之间的通信方式 客户端和服务器之间的通信是一种半双工的通信,即在同一时刻,只能有一方向另一方发送

  • 详解MySQL中事务隔离级别的实现原理

    前言 说到数据库事务,大家脑子里一定很容易蹦出一堆事务的相关知识,如事务的ACID特性,隔离级别,解决的问题(脏读,不可重复读,幻读)等等,但是可能很少有人真正的清楚事务的这些特性又是怎么实现的,为什么要有四个隔离级别. 今天我们就先来聊聊MySQL中事务的隔离性的实现原理,后续还会继续出文章分析其他特性的实现原理. 当然MySQL博大精深,文章疏漏之处在所难免,欢迎批评指正. 说明 MySQL的事务实现逻辑是位于引擎层的,并且不是所有的引擎都支持事务的,下面的说明都是以InnoDB引擎为基准.

  • 详解MySQL中事务的持久性实现原理

    前言 说到数据库事务,大家脑子里一定很容易蹦出一堆事务的相关知识,如事务的ACID特性,隔离级别,解决的问题(脏读,不可重复读,幻读)等等,但是可能很少有人真正的清楚事务的这些特性又是怎么实现的,为什么要有四个隔离级别. 在之前的文章我们已经了解了MySQL中事务的隔离性的实现原理,今天就继续来聊一聊MySQL持久性的实现原理. 当然MySQL博大精深,文章疏漏之处在所难免,欢迎批评指正. 说明 MySQL的事务实现逻辑是位于引擎层的,并且不是所有的引擎都支持事务的,下面的说明都是以InnoDB

  • 一文详解MySQL主从同步原理

    目录 1. MySQL主从同步实现方式 2. MySQL主从同步的作用 一主多从架构 双主多从架构 3. 主动同步的原理 4. 主从同步延迟问题 主从同步延迟的原因有哪些? 主从同步延迟的解决方案? 5. 如何提升主从同步性能 从库开启多线程复制 修改同步模式,改为异步 修改从库Bin Log配置 知识点总结 1. MySQL主从同步实现方式 MySQL主从同步是基于Bin Log实现的,而Bin Log记录的是原始SQL语句. Bin Log共有三种日志格式,可以binlog_format配置

  • 详解MySQL中Order By排序和filesort排序的原理及实现

    目录 1.Order By原理 2.filesort排序算法 3.优化排序 1.Order By原理 MySQL的Order By操作用于排序,并且会有多种不同的排序算法,他们的性能都是不一样的. 假设有一个表,建表的sql如下: CREATE TABLE `obtest` ( `id` BIGINT NOT NULL AUTO_INCREMENT, `a` VARCHAR ( 100 ) NOT NULL, `b` VARCHAR ( 100 ) NOT NULL, `c` VARCHAR (

  • 详解 MySQL 执行计划

    EXPLAIN语句提供有关MySQL如何执行语句的信息.EXPLAIN与SELECT,DELETE,INSERT,REPLACE和UPDATE语句一起使用. EXPLAIN为SELECT语句中使用的每个表返回一行信息.它按照MySQL在处理语句时读取它们的顺序列出了输出中的表. MySQL使用嵌套循环连接方法解析所有连接.这意味着MySQL从第一个表中读取一行,然后在第二个表,第三个表中找到匹配的行,依此类推.处理完所有表后,MySQL输出所选列,并通过表列表回溯,直到找到一个表,其中有更多匹配

  • 详解MySQL连接挂死的原因

    一.背景 近期由测试反馈的问题有点多,其中关于系统可靠性测试提出的问题令人感到头疼,一来这类问题有时候属于"偶发"现象,难以在环境上快速复现:二来则是可靠性问题的定位链条有时候变得很长,极端情况下可能要从 A 服务追踪到 Z 服务,或者是从应用代码追溯到硬件层面. 本次分享的是一次关于 MySQL 高可用问题的定位过程,其中曲折颇多但问题本身却比较有些代表性,遂将其记录以供参考. 架构 首先,本系统以 MySQL 作为主要的数据存储部件.整一个是典型的微服务架构(SpringBoot

  • 详解C++虚函数的工作原理

    静态绑定与动态绑定 讨论静态绑定与动态绑定,首先需要理解的是绑定,何为绑定?函数调用与函数本身的关联,以及成员访问与变量内存地址间的关系,称为绑定. 理解了绑定后再理解静态与动态. 静态绑定:指在程序编译过程中,把函数调用与响应调用所需的代码结合的过程,称为静态绑定.发生在编译期. 动态绑定:指在执行期间判断所引用对象的实际类型,根据实际的类型调用其相应的方法.程序运行过程中,把函数调用与响应调用所需的代码相结合的过程称为动态绑定.发生于运行期. C++中动态绑定 在C++中动态绑定是通过虚函数

  • 详解 Mysql 事务和Mysql 日志

    事务特性 1.原子性(Atomicity):事务开始后所有操作,要么全部做完,要么全部不做,不可能停滞在中间环节. 2.一致性(Consistency):事务开始前和结束后,数据库的完整性约束没有被破坏 .比如A向B转账,不可能A扣了钱,B却没收到. 3.隔离性(Isolation):同一时间,只允许一个事务请求同一数据,不同的事务之间彼此没有任何干扰.比如A正在从一张银行卡中取钱,在A取钱的过程结束前,B不能向这张卡转账. 4.持久性(Durability):事务完成后,事务对数据库的所有更新

随机推荐