虽然这几个参数我以前也有学习过,但是一直没有在源码级别进行证明,所以一直也没有写,但是今天群里有朋友问到,所以先按照官方手册的加上我自己的理解进行一下解释,以后一定要在源码级别进行下补充
使用MySQL版本:5.7.14
OS平台: CentOS release 6.5 (Final) 64bit
一、理论基础
首先要理解几个参数我们必须要先知道下面的内容,注意下面内容并不深入,而且只是我自己的理解
1、什么是多线程
实际上MySQL中的多线程就是POSIX那一套,比如也就是我们说的pthread族函数比如pthread_create、pthread_join、pthread_mutex_lock等等,相信有多线程编程基础的朋友不会陌生,线程也叫轻量级进程(LWP)那么多线程有什么好处,相对于进程而言多线程共享了很多东西比如
1.文件描述符表
2.每种信号的处理方式
3.当前工作目录
4.用户ID和组ID
5.除栈以外的内存空间
其实我们在编程的时候多线程通信都是通过非栈以外的内存进程的,比如堆空间,既然线程能够共享这麽多资源,不管是线程的创建、上下文切换、线程间通信都变得方便了(注意共享是方便了但是对临界区的管理需要使用类似mutex rwlock之类的锁来实现)。接下来我们就要来讲讲线程间上下文切换
同时要记住一点线程是CPU调度的最小单位、进程是资源分配的最小单位。配上一张图
2、线程的上下文切换
我们知道LINUX是一个多批道多用户分时操作系统,它允许多个任务同时进入内存CPU通过时间轮片的方式进行调度,我们举例如果我有2核的CPU,但是我当前有4个同等优先级的MYSQL线程进入了就绪队列,那么我们同一时刻能够并行(注意用词的准确性不是并发是并行)执行的MYSQL线程其实是2个,另外2个呢?当然就处于就绪队列,等待获得CPU时间来完成工作,等到正在执行的2个线程时间轮片用完以后这个时候需要保留处理器现场,其实就是保存寄存器的值到内存,然后放弃CPU,进入就绪态,这个时候在就绪队列的2个线程可以进入CPU进行工作了,这种4个线程并发执行但是只有2个线程获得时间轮片并行执行(获得CPU轮片)在这种不断需要获得CPU轮片-->>工作-->>保存寄存器值到内存-->>放弃CPU轮片的方式中我们将保存寄存器值到内存这种动作叫做线程上下文切换,这是有一定代价的,当然 我的理解也许很片面因为我毕竟不是搞LINUX内核的。如果同时需要并发执行的线程越多这种上下文切换的频率就越大,这也是为什么我们在LINUX负载高的时候能够观察到更多上下文切换的原因(vmstat就可以看到),那么我们说如果限制同一时刻并发执行的线程数上下文切换将会减少,某种意义说就是长痛不如短痛,与其让你不断的进行上文切换还不如把你处于睡眠态放弃CPU使用权,这里简单说一下线程的缺点:
线程不稳定(库函数实现)
线程调试比较困难(gdb支持不好)
信号使用非常困难
3、小事物线程饥饿问题
如果有过多线程编程使用过MUTEX,这种抢占试锁的朋友,一定不会忘记在某个线程释放MUTEX后,其他线程会以抢占的方式来获得,某些线程可能运气不好老是抢不到,如果换成 同优先级线程之间,OS在调度的时候如果不均衡,那么某些可能任务量小的线程老是得不到CPU轮片,而大任务线程老是获得CPU轮片,这依赖于OS的线程调度策略,这样就可能形成小任务线程饥饿问题,与其依赖OS的调度策略不如自己设置一种规则,让用到了一定时间轮片的线程先处于睡眠态放弃CPU的使用。
二、参数解释
好了有了上面的理论知识可以进行这几个参数的解释了
其实这三个参数就是来解决上面的问题
1、innodb_thread_concurrency
同一时刻能够进入innodb层次并发执行的线程数(注意是并发不是并行),如果超过CPU核数,某些线程可能处于就绪态而没有获得CPU时间轮片,如果SERVER层的线程大于这个值,对不起多余的线程将会被放到一个叫做wait queue的队列中,而不能进入INNODB层次,进不到innodb层当然也就不能干活了,谈不上获得CPU。既然是一个队列那么它必然满足先进入先出的原则。这也是前面说的长痛不如短痛,与其让你不断的进行上文切换还不如把你处于睡眠态放弃CPU使用权,默认这个值是0,代表不限制。
2、innodb_concurrency_tickets
这个参数设置为一种tickets,默认是5000,我也不清楚到底它代表多久,从官方文档来看它和事物处理的行数有关,大事物需要处理的行数自然更多,小事物当然也就越少至少我们可以想成获得CPU的时间,干活期间他会不断减少,如果减少到0,这个线程将被提出innodb层次,进入前面说的等待队列,当然也就在队尾部了,这里假设有一个小的事物正在排队进入innodb层,又或者它已经进入了innodb层没有获得CPU时间轮片,突然一个大的事物tickets耗尽被提出了innodb层,那么这个小事物就自然而然能够获得CPU轮片干活,而小事物执行非常快,执行完成后
另外的事物又能尽快的获得CPU干活,不会由于OS线程调度不均匀的问题而造成的小事物饥饿问题,这很好理解。也就是前面我说的与其依赖OS的调度策略不如自己设置一种规则,让用到了一定时间轮片的线程先处于睡眠态放弃CPU的使用。
3、innodb_thread_sleep_delay
这个参数从官方手册来看,是代表当事物被踢出innodb层次后自己睡眠的时间,等待睡眠完成后再次进入wait que队列5.6.3以后可以设置innodb_adaptive_max_sleep_delay,来自动调整innodb_thread_sleep_delay,这就更为方便,因为这个值很难讲多少合适,其单位是microseconds,从某种意义上来讲这个值加剧了大事物执行的时间,小事物也就更加容易进入INNODB层次获得CPU时间来干活。