您的位置:首页 > 数据库 > MySQL

Innodb内核线程并发机制

2013-10-11 18:45 344 查看
Innodb内核线程并发

Innodb内部并发工作机制。

Innodb_thread_concurrency变量是内部最大线程数,还有另外两个重要的参数
Innodb_thread_sleep_delay
Innodb_concurrency_tickets

解释一下他们是如何工作的

Mysql工作模式和其他数据库系统不一样,它是插件式存储引擎结构的,通常包含解析,优化和存储引擎。我们以存储引擎为出发点看看mysql是如何工作的,相比研究整个MYSQL要更容易一些。

Mysql调用存储引擎的方法:
read_row
这样的方法有好几个,例如:readby index(有序读)sequentialread(连续读)randomread(随机读)

write_row;
update_row;
delete_row; 具体函数参见源码。

要执行这些方法(函数),innodb需要检查innodb内部的线程计数,如果内部线程计数超过innodb_thread_concurrency,就等待innodb_thread_sleep_delay变量设置的微妙后再尝试进入。如果第二次仍然不成功-进入线程队列sleep(FIFO)。

为什么innodb使用两次尝试?
减少线程等待计数和降低上下文切换。

一但线程ENTERED(进入),就会得到innodb_concurrency_tickets票数,以便以后的innodb_concurrency_tickets变量次数线程都不会再次检测,可以免check进入。
该参数保持默认的500即可,没有太多意义,除非是在特定场合,比如你的数据库只有极少几个SQL,并且他们都以极高的并发线程在运行,那么出现重复的可能性才会超过500,而实际上,这几乎是不太可能的。

就像下面的代码描述一样:
这是国外的mysql牛人简化过的代码
if(thread->n_tickets_to_enter_innodb > 0)
{
thread->n_tickets_to_enter_innodb–;
ENTER;
}
retry:
if (entered_thread <innodb_thread_concurrency)
{
entered_threads++;
thread->n_tickets_to_enter_innodb = innodb_concurrency_tickets;
ENTER;
}
if (innodb_thread_sleep_delay > 0)
{
thread_sleep(innodb_thread_sleep_delay);
}
goto retry; // (only once)
WAIT_IN_FIFO_QUEUE;
thread->n_tickets_to_enter_innodb =innodb_concurrency_tickets;
ENTER;

完整的代码路径:srv_conc_enter_innodb function in innobase/srv/srv0srv.c
Same sql源码如此描述,一旦线程在获得ticket(srv_conc_enter_innodb)后,允许进入innodb内核执行同样SQL的次数。在这个次数内不会再次进行check验证。通过这种方式节约大量的信号操作。

说到这里不得不提一下INNODB的关闭:
如果下面的参数被设置为1,在关闭前我们不运行净化和插入缓冲合并。如果设置为2,关闭时不会把缓冲池刷新到数据文件:我们采用有效的手段使INNODB“崩溃”(但不丢失任何未提交的事务)。
ulint srv_fast_shutdown = 0; (源代码里面默认值是0,数据库默认值是1)

细细品味过这段代码,你会发现,对控制文件合理调整使用,再请一位善于控制SQL的DBA来审核代码,数据库是不会发生崩溃这么变态的事情的,负载过高的,顶多是慢一些。(加服务器呗,还想啥呢–)

那么什么是innodb_thread_concurrency最佳值?
这个值依赖许多因素,包括你的负载量,跑在什么样的硬件的软件上。如果你有1-2个CPU,你经常能做的很好,可以禁用它(innodb_thread_concurrency=0,从5.0.19开始还有更多的默认值)。多个CPU(4+CPU)的情况又有所不同。

MYSQL5.1以后对多核CPU支持改进了很多,将该值设置为0,或者2*CPU是一个比较好的注意。

waiting in InnoDB queue状态频繁出现,说明数据库并发太大,需要分析引起并发太大的原因或者增加数据库服务器(假设你根据硬件精确计算了该值)。

理论上你可以使用2*(NUMCPU+NUMDISKS)计算值以便能够激活2倍于CPU加磁盘的资源。然后在实际环境中,实践被证明,这个值并不是最优的。
如果正在使用innodb,这个值设置的小于CPU数量,mysql将不会利用到所有的CPU资源。

关于innodb_commit_concurrency
如你所见innodb_commit_concurrency仅用来保护行访问,使用内部结构和锁定分阶段提交,他仍是为保护变量。他限制innodb内核激活线程的commit。一个最佳的值也依赖很多其他因素。但是从5.1.36开始mysql不允许将该值设置为非0,该值只能为默认值0,mysql不限制并发提交。

如果没有电池保护,设置为innodb_flush_logs_at_trx_commit=1,但你可能想使用2或0。如果二进制日志被开启,他通常不重要,innodb会进行同步操作。

unix平台测试的结果:
日志刷新方法设置为O_DIRECT
innodb_flush_logs_at_trx_commit改参数的调整对性能和崩溃恢复数据丢失至关重要
1 2 0
提升130% 提升10

一般设置为2是一种平衡的方法,崩溃丢失1-2秒的数据,1只丢一条,但是十分影响性能,如果是在要求十分安全的应用中,建议为1,并且设置日志同步sync_log。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息