MySQL线程池总结(一)

2015-07-16 12:08:32 · 作者: · 浏览: 5

线程池是MySQL5.6的一个核心功能,对于服务器应用而言,无论是web应用服务还是DB服务,高并发请求始终是一个绕不开的话题。当有大量请求并发访问时,一定伴随着资源的不断创建和释放,导致资源利用率低,降低了服务质量。线程池是一种通用的技术,通过预先创建一定数量的线程,当有请求达到时,线程池分配一个线程提供服务,请求结束后,该线程又去服务其他请求。 通过这种方式,避免了线程和内存对象的频繁创建和释放,降低了服务端的并发度,减少了上下文切换和资源的竞争,提高资源利用效率。所有服务的线程池本质都是位了提高资源利用效率,并且实现方式也大体相同。本文主要说明MySQL线程池的实现原理。


在MySQL5.6出现以前,MySQL处理连接的方式是One-Connection-Per-Thread,即对于每一个数据库连接,MySQL-Server都会创建一个独立的线程服务,请求结束后,销毁线程。再来一个连接请求,则再创建一个连接,结束后再进行销毁。这种方式在高并发情况下,会导致线程的频繁创建和释放。当然,通过thread-cache,我们可以将线程缓存起来,以供下次使用,避免频繁创建和释放的问题,但是无法解决高连接数的问题。One-Connection-Per-Thread方式随着连接数暴增,导致需要创建同样多的服务线程,高并发线程意味着高的内存消耗,更多的上下文切换(cpu cache命中率降低)以及更多的资源竞争,导致服务出现抖动。相对于One-Thread-Per-Connection方式,一个线程对应一个连接,Thread-Pool实现方式中,线程处理的最小单位是statement(语句),一个线程可以处理多个连接的请求。这样,在保证充分利用硬件资源情况下(合理设置线程池大小),可以避免瞬间连接数暴增导致的服务器抖动。


调度方式实现


MySQL-Server同时支持3种连接管理方式,包括No-Threads,One-Thread-Per-Connection和Pool-Threads。No-Threads表示处理连接使用主线程处理,不额外创建线程,这种方式主要用于调试;One-Thread-Per-Connection是线程池出现以前最常用的方式,为每一个连接创建一个线程服务;Pool-Threads则是本文所讨论的线程池方式。MySQL-Server通过一组函数指针来同时支持3种连接管理方式,对于特定的方式,将函数指针设置成特定的回调函数,连接管理方式通过thread_handling参数控制,代码如下:


if (thread_handling <= SCHEDULER_ONE_THREAD_PER_CONNECTION)?
? one_thread_per_connection_scheduler(thread_scheduler,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? &max_connections,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? &connection_count);
else if (thread_handling == SCHEDULER_NO_THREADS)
? one_thread_scheduler(thread_scheduler);
else? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? pool_of_threads_scheduler(thread_scheduler, &max_connections,&connection_count);


连接管理流程


1.通过poll监听mysql端口的连接请求
2.收到连接后,调用accept接口,创建通信socket
3.初始化thd实例,vio对象等
4.根据thread_handling方式设置,初始化thd实例的scheduler函数指针
5.调用scheduler特定的add_connection函数新建连接


下面代码展示了scheduler_functions模板和线程池对模板回调函数的实现,这个是多种连接管理的核心。


struct scheduler_functions? ? ? ? ? ? ? ? ? ? ? ?
{?
uint? max_threads;


uint? *connection_count;? ? ? ? ? ? ? ? ? ? ? ? ?
?
ulong *max_connections;? ? ? ? ? ? ? ? ? ? ? ? ?
?
bool (*init)(void);? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
?
bool (*init_new_connection_thread)(void);? ? ? ?


void (*add_connection)(THD *thd);


void (*thd_wait_begin)(THD *thd, int wait_type);


void (*thd_wait_end)(THD *thd);? ? ? ? ? ? ? ? ?


void (*post_kill_notification)(THD *thd);? ? ? ?


bool (*end_thread)(THD *thd, bool cache_thread);


void (*end)(void);
};


?


static scheduler_functions tp_scheduler_functions=? ? ? ? ? ? ? ?


{
? 0,? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? // max_threads
? NULL,
? NULL,? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? tp_init,? ? ? ? ? ? ? ? ? ? ? ? ? ? // init
? NULL,? ? ? ? ? ? ? ? ? ? ? ? ? ? ? // init_new_connection_thread
? tp_add_connection,? ? ? ? ? // add_connection
? tp_wait_begin,? ? ? ? ? ? ? ? // thd_wait_begin? ? ? ? ? ?
? tp_wait_end,? ? ? ? ? ? ? ? ? // thd_wait_end
? tp_post_kill_notification,? // post_kill_notification? ?
? NULL,? ? ? ? ? ? ? ? ? ? ? ? ? ? // end_thread
? tp_end? ? ? ? ? ? ? ? ? ? ? ? ? ? // end


};


线程池的相关参数
1.thread_handling:表示线程池模型。
2.thread_pool_size:表示线程池的group个数,一般设置为当前CPU核心数目。理想情况下,一个group一个活跃的工作线程,达到充分利用CPU的目的。
3.thread_pool_stall_limit:用于timer线程定期检查group是否“停滞”,参数表示检测的间隔。
4.thread_pool_idle_timeout:当一个worker空闲一段时间后会自动退出,保证线程池中的工作线程在满足请求的情况下,保持比较低的水平。
5.thread_pool_oversubscribe:该参数用于控制CPU核心上“超频”的线程数。这个参数设置值不含listen线程计数。
6.threadpool_high_prio_mode:表示优先队列的模式。


线程池实现


上面描述了Mysql-Server如何管理连接,这节重点描述线程池的实现框架,以及关键接口。如图1



每一个绿色的方框代表一个group,group数目由thread_pool_size参数决定。每个group包含一个优先队列和普通队列,包含一个listener线程和若干个工作线程,listener线程