thread_pool(线程池),是指mysql 创建若干工作线程来共同处理所有连接的用户请求,用户的请求的方式不再是 ‘one thread per connection’,而是多个线程共同接收并处理多个连接的请求,在数据库的底层处理方面(mysql_execute_command),单线程的处理方式和线程池的处理方式是一致的。
thread_pool 的工作原理
启动 thread_pool 的mysql 会创建thread_pool_size 个thread group , 一个timer thread, 每个thread group 最多拥有thread_pool_oversubscribe个活动线程,一个listener线程,listener线程负责监听分配到thread group中的连接,并将监听到的事件放入到一个queue中,worker线程从queue中取出连接的事件并执行具体的操作,执行的过程和one thread per connection 相同。timer threaad 则是为了监听各个threadgroup的运行情况,并根据是否阴塞来创建新的worker线程。
thread_pool 建立连接的堆栈如下:
mysqld_main handle_connections_sockets create_new_thread tp_add_connection queue_putthread group中的 worker 处理请求的堆栈如下:
0 mysql_execute_command
1 0x0000000000936f40 in mysql_parse
2 0x0000000000920664 in dispatch_command
3 0x000000000091e951 in do_command
4 0x0000000000a78533 in threadpool_process_request
5 0x000000000066a10b in handle_event
6 0x000000000066a436 in worker_main
7 0x0000003562e07851 in start_thread ()
8 0x0000003562ae767d in clone ()
其中worker_main函数是woker线程的主函数,调用mysql本身的do_command 进行消息解析及处理,和one_thread_per_connection 是一样的逻辑; thread_pool 自行控制工作的线程个数,进而实现线程的管理。
thread_pool中线程的创建:
1. listener线程将监听事件放入mysql放入queue中时,如果发现当前thread group中的活跃线程数active_thread_count为零,则创建新的worker 线程;
2. 正在执行的线程阻塞时,如果发现当前thread group中的活跃线程数active_thread_count为零,则创建新的worker 线程;
3. timer线程在检测时发现没有listener线程且自上次检测以来没有新的请求时会创建新的worker线程,其中检测的时间受参数threadpool_stall_limit控制;
4. timer线程在检测时发现没有执行过新的请求且执行队列queue 不为空时会创建新的worker线程;
worker线程的伪码如下:
thread_pool中线程的销毁:
当从队列queue中取出的connection为空时,则此线程销毁,取connection所等待的时间受参数thread_pool_idle_timeout的控制; 综上,thread_pool通过线程的创建及销毁来自动处理worker的线程个数,在负载较高时,创建的线程数目较高,负载较低时,会销毁多余的worker线程,从而降低连接个数带来的影响的同时,提升稳定性及性能。同时,threadpool中引入了Timer 线程,主要做两个事情。
1. 定期检查每个thread_group是否阻塞,如果阻塞,则进行唤醒或创建线程的工作;
2. 检查每个thread_group中的连接是否超时,如果超时则关掉连接并释放相应的资源;
threadpool在使用中存在的问题:
1. 由于threadpool严格控制活跃线程数的限制,如果同时有多个大查询同时分配到了同一个thread group,则会造成此group中的请求过慢,rt 升高,最典型的就是多个binlog dump 线程同时分配到了同一个group内;
2. 开启了事务模式时,非事务模式的请求会放入低优先级队列,因此可能在较长时间内得不到有效处理,极端情况下,会导致实例hang 住,例如某个连接执行了 flush tables with read lock ,并且此连接的后续请求都会放入低优先级,那么有可能会造成实列hang住;
3. 较小并发下,threadpool 性能退化的问题;
MySQL· 性能优化·并行复制外建约束问题背景: