mysql kill不生效?

       生产环境出现过多次mysql hang住,写操作的sql堵住的情况,这个时候使用kill来kill所有的连接,但是大部分时候连接kill 后处于freeing item状态,kill在这种场景下基本无效。

       查看官方文档(以下大致翻译):(http://dev.mysql.com/doc/refman/5.5/en/kill.html

       kill执行后,一个线程特定的kill flag会被设置(THD::killed)。大多数情况下,线程消亡可能是需要花一点时间的,因为kill flag是以特定的间隔被检查的:

1、对于select,group by,order by语句,每读取完一块后检查kill flag。如果有kill flag,这个语句就会终止。

2、对于alter table,每次读取一块之前检查kill flag。如果有kill flag,这个语句就会终止,临时表也会被删除。

3、对于update,delete操作,每次读取完一块或每次更新/删除一行后 检查kill flag。

4、insert delayed操作,立即flush内存中已经插入的行,然后终止。

5、如果一个连接处于locked状态,table lock立即终止。

       从文档上看,在mysql hang住的时候,使用kill似乎并不是最佳选择,因为mysql并不会立即kill掉这些session。下面试图从代码上理一下mysql kill的处理逻辑。(5.1.58,其它版本会有差异,不过大致的逻辑没啥变化,最起码5.1和5.5的官方文档对于kill的解释没怎么变化:))

...
/*
  kills a thread and sends response

  SYNOPSIS
    sql_kill()
    thd			Thread class
    id			Thread id
    only_kill_query     Should it kill the query or the connection
*/
void sql_kill(THD *thd, ulong id, bool only_kill_query)
{
  uint error;
  if (!(error= kill_one_thread(thd, id, only_kill_query)))
    my_ok(thd);
  else
    my_error(error, MYF(0), id);
}
...
/**
  kill on thread.

  @param thd			Thread class
  @param id			Thread id
  @param only_kill_query        Should it kill the query or the connection

  @note
    This is written such that we have a short lock on LOCK_thread_count
*/
uint kill_one_thread(THD *thd, ulong id, bool only_kill_query)
{
  THD *tmp;
...
  if (tmp)
  {

    /*
      If we're SUPER, we can KILL anything, including system-threads.
      No further checks.

      KILLer: thd->security_ctx->user could in theory be NULL while
      we're still in "unauthenticated" state. This is a theoretical
      case (the code suggests this could happen, so we play it safe).

      KILLee: tmp->security_ctx->user will be NULL for system threads.
      We need to check so Jane Random User doesn't crash the server
      when trying to kill a) system threads or b) unauthenticated users'
      threads (Bug#43748).

      If user of both killer and killee are non-NULL, proceed with
      slayage if both are string-equal.
    */
    if ((thd->security_ctx->master_access & SUPER_ACL) ||
        thd->security_ctx->user_matches(tmp->security_ctx))
    {
      tmp->awake(only_kill_query ? THD::KILL_QUERY : THD::KILL_CONNECTION);
      error=0;
    }
...
void THD::awake(THD::killed_state state_to_set)
{
...
  killed= state_to_set;
...
      close_active_vio();
...

 sql_parse.cc中sql_kill()调用kill_one_thread(), kill_one_thread()找到对应的threadid,调用awake(),awake()做了2件事:设置标签killed;关闭连接。至此,kill操作就返回了。

 kill flag被检查的点:

update---
      while (!(error=info.read_record(&info)) && !thd->killed)
      {
delete---
  while (!(error=info.read_record(&info)) && !thd->killed &&
	 ! thd->is_error())

 每种操作都会在不同的策略确保kill操作的线程消亡掉。

从mysql kill处理的机制看,在mysql hang住的情况下,大量写操作被阻塞,使用kill并不能立即解决问题,如果想尽快让mysql恢复服务,最快的是主备切换,或直接重启mysql。 

 ps:一些链接

http://www.dbasquare.com/2012/05/15/why-do-threads-sometimes-stay-in-killed-state-in-mysql/

http://www.dbasquare.com/2012/04/04/how-to-selectively-kill-queries-in-mysql/

http://dev.mysql.com/doc/refman/5.5/en/kill.html

猜你喜欢

转载自guduwhuzhe.iteye.com/blog/1856799