ITPub博客

首页 > 数据库 > MySQL > mysql并发线程控制之innodb_thread_concurrency的改进

mysql并发线程控制之innodb_thread_concurrency的改进

原创 MySQL 作者:myownstars 时间:2015-03-08 11:38:51 0 删除 编辑

innodb_thread_concurrency算法介绍

1、server层到innodb层读写数据是一条一条记录进行的,每次读写都会进/出一次InnoDB层(row_search_for_mysql),进入InnoDB层的时候会检查当前并发线程数目,当超过innodb_thread_concurrency时,线程将尝试spin和sleep并再次检查,如果并发数还是超过innodb_thread_concurrency,线程将进入到一个FIFO中等待被唤醒,读写记录结束后退出InnoDB层时会将当前并发线程数减1,并检查其是否低于innodb_thread_concurrency,如果是的话,从FIFO中唤醒一个等待的线程,保证并发线程不会超过innodb_thread_concurrency参数。

2、当线程进入InnoDB层后,但在获取数据时由于锁请求无法得到满足而需要挂起时,线程将强制退出InnoDB层,当锁请求满足后,线程继续运行并强制进入到InnoDB层,这会导致实际并发线程数不是严格控制在innodb_thread_concurrency之内

 

 

代码调用逻辑

主要函数:

innodb_srv_conc_enter_innodb

innodb_srv_conc_exit_innodb

srv_conc_force_enter_innodb

srv_conc_force_exit_innodb

 

调用逻辑

进入/退出InnoDB层

ha_innobase::index_read

ha_innobase::general_fetch

row_check_index_for_mysql

                ...

                innodb_srv_conc_enter_innodb(prebuilt->trx);

 

                ret = row_search_for_mysql((byte*) buf, mode, prebuilt,  match_mode, 0);

 

                innodb_srv_conc_exit_innodb(prebuilt->trx);

                ...

 

 

锁等待逻辑:

srv_suspend_mysql_thread

                ...

                if (trx->declared_to_be_inside_innodb) {

 

                                was_declared_inside_innodb = TRUE;

 

                                /* We must declare this OS thread to exit InnoDB, since a

                                possible other thread holding a lock which this thread waits

                                for must be allowed to enter, sooner or later */

                                srv_conc_force_exit_innodb(trx);

                }

 

                /* Suspend this thread and wait for the event. */

 

                thd_wait_begin(trx->mysql_thd, THD_WAIT_ROW_LOCK);

                os_event_wait(event);

                thd_wait_end(trx->mysql_thd);

 

                if (was_declared_inside_innodb) {

 

                                /* Return back inside InnoDB */

                                srv_conc_force_enter_innodb(trx);

                }

 

 

5.6的改进

从5.6开始,默认编译会使用GCC atomic,可避免热点锁srv_conc_mutex的频繁加锁/释放。

Pre-5.5如果超过并发限制时,就给其线程分配一个slot,让其进入信号量等待,原子操作则无需使用信号量。

function srv_conc_enter_innodb:

ifdef HAVE_ATOMIC_BUILTINS

    srv_conc_enter_innodb_with_atomics(trx);

#else

    srv_conc_enter_innodb_without_atomics(trx);

#endif /* HAVE_ATOMIC_BUILTINS */

 

5.6引入adaptive sleep,允许innodb根据系统负载进行自适应调整,当innodb_adaptive_max_sleep_delay>0, innodb_thread_sleep_delay则 会动态调整(以前者为上限)。

ada还ptive 的算法是:

  如果sleep了当前值以后还是不能进入,就把sleep时间+1;

  如果还有线程在sleep时,已经有了空闲线程,就把当前值的sleep 时间减半。

innodb_thread_sleep_delay降低比增加的更快,这样在并发线程数很高时,当限制并发数早就达到,其他线程的每次sleep时间会缓慢拉长。而当Innodb层很空闲时,sleep时间又会快速降到非常低

调整sleep到一个优化值的目的是,过小的sleep值可能会产生太多的线程切换,但过长的sleep时间,在并发比较空闲的时候又会影响性能。新的并发控制策略有利于随着负载的变化而做自适应调整。


 

Innodb_thread_concurrency不足

1线程因为锁等待而退出innodb层,当获取锁时可以直接重入innodb(跳过此参数检查),因此系统并发执行的线程数可能大于此参数值。

2代码路径靠后,此时线程已经开始执行命令,进入到ha_innobase,应该在mysql_start_query前限制即thread_running。

为此好多技术高手开发了相应patch,从server层控制并发执行的线程数,下文将做描述。

 

 

参考文章

 http://www.gpfeng.com/?p=488

http://mysqllover.com/?p=496&utm_source=tuicool

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/15480802/viewspace-1452232/,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2010-03-18

  • 博文量
    375
  • 访问量
    3095232