one-connection-per-thread
根据scheduler_functions的模板,我们也可以列出one-connection-per-thread方式的几个关键函数。
| static scheduler_functions con_per_functions= { max_connection+1, // max_threads NULL, NULL, NULL, // init Init_new_connection_handler_thread, // init_new_connection_thread create_thread_to_handle_connection, // add_connection NULL, // thd_wait_begin NULL, // thd_wait_end NULL, // post_kill_notification one_thread_per_connection_end, // end_thread NULL // end }; |
1.init_new_connection_handler_thread
这个接口比较简单,主要是调用pthread_detach,将线程设置为detach状态,线程结束后自动释放所有资源。
2.create_thread_to_handle_connection
这个接口是处理新连接的接口,对于线程池而言,会从thread_id%group_size对应的group中获取一个线程来处理,而one-connection-per-thread方式则会判断是否有thread_cache可以使用,如果没有则新建线程来处理。具体逻辑如下:
(1).判断缓存的线程数是否使用完(比较blocked_pthread_count 和wake_pthread大小)
(2).若还有缓存线程,将thd加入waiting_thd_list的队列,唤醒一个等待COND_thread_cache的线程
(3).若没有,创建一个新的线程处理,线程的入口函数是do_handle_one_connection
(4).调用add_global_thread加入thd数组。
3.do_handle_one_connection
这个接口被create_thread_to_handle_connection调用,处理请求的主要实现接口。
(1).循环调用do_command,从socket中读取网络包,并且解析执行;
(2). 当远程客户端发送关闭连接COMMAND(比如COM_QUIT,COM_SHUTDOWN)时,退出循环
(3).调用close_connection关闭连接(thd->disconnect());
(4).调用one_thread_per_connection_end函数,确认是否可以复用线程
(5).根据返回结果,确定退出工作线程还是继续循环执行命令。
4.one_thread_per_connection_end
判断是否可以复用线程(thread_cache)的主要函数,逻辑如下:
(1).调用remove_global_thread,移除线程对应的thd实例
(2).调用block_until_new_connection判断是否可以重用thread
(3).判断缓存的线程是否超过阀值,若没有,则blocked_pthread_count++;
(4).阻塞等待条件变量COND_thread_cache
(5).被唤醒后,表示有新的thd需要重用线程,将thd从waiting_thd_list中移除,使用thd初始化线程的thd->thread_stack
(6).调用add_global_thread加入thd数组。
(7).如果可以重用,返回false,否则返回ture
线程池与epoll
在引入线程池之前,server层只有一个监听线程,负责监听mysql端口和本地unixsocket的请求,对于每个新的连接,都会分配一个独立线程来处理,因此监听线程的任务比较轻松,mysql通过poll或select方式来实现IO的多路复用。引入线程池后,除了server层的监听线程,每个group都有一个监听线程负责监听group内的所有连接socket的连接请求,工作线程不负责监听,只处理请求。对于overscribe为1000的线程池设置,每个监听线程需要监听1000个socket的请求,监听线程采用epoll方式来实现监听。










