作者:卫通达邱小洁GPS | 来源:互联网 | 2014-05-29 08:43
相对5.1中的线程池,5.5是重新实现,最吸引人的特性是可以根据负谈话自动调整线程数。(不再局限于设置的线程数,以避免线程饥饿,但是线程数还是要比one-thread-per-connection模式下线程要少)。我们为什么想要引入线程池MySQL在活跃线程非常大的情况下
相对5.1中的线程池,5.5是重新实现,最吸引人的特性是可以根据负谈话自动调整线程数。(不再局限于设置的线程数,以避免线程饥饿,但是线程数还是要比one-thread-per-connection模式下线程要少)。
我们为什么想要引入线程池
MySQL在活跃线程非常大的情况下,缺乏自我保护机制。这也是我一直说道的,从去年到今年,没有变过。因为这一点在淘宝体感受特别深。在淘宝的业务场景下,可能达到最大连接数的活跃线程数,导致了:
* 线程因并发事务数限制而在InnoDB的等待队列中,而后被唤醒,导引线程切换额外开销非常大。
也许你不会觉得这有什么,但想像下,线程少时,直接进入InnoDB层,而避免了spin count次,并且免除了sleep
delay时间。
*
在集中型的并发更新时,大量的InnoDB等待队列中的线程是等待记录锁,一旦被唤醒,等待相同记录锁的线程都被唤醒,但只有第一个到达的才能正常的更新,其它的线程还是再次进入等待列队中等待记录锁。
对于淘宝的典型业务场景,引入线程池并不是为了减少线程创建、销毁的额外开销,也不是为减少到InnoDB真正进干活的线程数量,因为这些在淘宝的业务上,都有参数可以缓解,并不是太大的问题。
我们要解决的还是并发量变大后的各种性能不稳定,抖动等“怪异”的现象。
线程池要解决的几个问题
1. 不能引入死锁
2. 不能让个别线程饥饿,即要保证调度算法的公平性
3. 能正常kill会话
4. client异常能处理连接
这几点说起来容易,实现起来要考虑的场景就是很多了。
MariaDB线程池的实现思路
在此只linux平台下的实现,基于libevent来做,
1.
“acceptor”线程只有一个,而不像Oracle官方设计为多个group。接受连接请求后,调用线程调度的回调函数thd_scheduler->add_connection(),将连接加入到线程池中。
2.
线程池中的worker线程调用threadpool_add_connection(),worker线程来初始化线程上下文,连接权限验证,一旦验证成功,线程池开始异步地从连接的socket上读取请求。
3.
客户发起一个查询,关闭连接,异常断开等,由线程池中的worker线程完成,完成后再发起异步读。异常的话,threadpool_remove_connection()将关闭连接并释放与client相关的资源。
简单版本的工作流程可以参考下图: