MySQL執行緒池總結(二)
上一篇主要講了執行緒池的原理和實現,感覺有點意猶未盡,這篇文章是對上篇文章的一個補充,主要圍繞以下兩點展開,one-connection-per-thread的實現方式以及執行緒池中epoll的使用。
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方式來實現監聽。
Select,poll,epoll都是IO多路複用機制,IO多路複用通過一種機制,可以監聽多個fd(描述符),比如socket,一旦某個fd就緒(讀就緒或寫就緒),能夠通知程式進行相應的讀寫操作。epoll相對於select和poll有了很大的改進,首先epoll通過epoll_ctl函式註冊,註冊時,將所有fd拷貝進核心,只拷貝一次不需要重複拷貝,而每次呼叫poll或select時,都需要將fd集合從使用者空間拷貝到核心空間(epoll通過epoll_wait進行等待);其次,epoll為每個描述符指定了一個回撥函式,當裝置就緒時,喚醒等待者,通過回撥函式將描述符加入到就緒連結串列,無需像select,poll方式採用輪詢方式;最後select預設只支援1024個fd,epoll則沒有限制,具體數字可以參考cat /proc/sys/fs/file-max的設定。epoll貫穿線上程池使用的過程中,下面我就epoll的建立,使用和銷燬生命週期來描述epoll線上程中是如何使用的。
- 執行緒池初始化,epoll通過epoll_create函式建立epoll檔案描述符,實現函式是thread_group_init;
- 埠監聽執行緒監聽到請求後,建立socket,並建立THD和connection物件,放在對應的group佇列中;
- 工作執行緒獲取該connection物件時,若還未登入,則進行登入驗證
- 若socket還未註冊到epoll,則呼叫epoll_ctl進行註冊,註冊方式是EPOLL_CTL_ADD,並將connection物件放入epoll_event結構體中
- 若是老連線的請求,仍然需要呼叫epoll_ctl註冊,註冊方式是EPOLL_CTL_MOD
- group內的監聽執行緒呼叫epoll_wait來監聽註冊的fd,epoll是一種同步IO方式,所以會進行等待
- 請求到來時,獲取epoll_event結構體中的connection,放入到group中的佇列
- 執行緒池銷燬時,呼叫thread_group_close將epoll關閉。
備註:
1.註冊在epoll的fd,若請求就緒,則將對應的event放入到events陣列,並將該fd的事務型別清空,因此對於老的連線請求,依然需要呼叫epoll_ctl(pollfd, EPOLL_CTL_MOD, fd, &ev)來註冊。
執行緒池函式呼叫關係
(1)建立epoll
tp_init->thread_group_init->tp_set_threadpool_size->io_poll_create->epoll_create
(2)關閉epoll
tp_end->thread_group_close->thread_group_destroy->close(pollfd)
(3)關聯socket描述符
handle_event->start_io->io_poll_associate_fd->io_poll_start_read->epoll_ctl
(4)處理連線請求
handle_event->threadpool_process_request->do_command->dispatch_command->mysql_parse->mysql_execute_command
(5)工作執行緒空閒時
worker_main->get_event->pthread_cond_timedwait
等待thread_pool_idle_timeout後,退出。
(6)監聽epoll
worker_main->get_event->listener->io_poll_wait->epoll_wait
(7)埠監聽執行緒
main->mysqld_main->handle_connections_sockets->poll
one-connection-per-thread函式呼叫關係
(1) 工作執行緒等待請求
handle_one_connection->do_handle_one_connection->do_command->
my_net_read->net_read_packet->net_read_packet_header->net_read_raw_loop->
vio_read->vio_socket_io_wait->vio_io_wait->poll
備註:與執行緒池的工作執行緒有監聽執行緒幫助其監聽請求不同,one-connection-per-thread方式的工作執行緒在空閒時,會呼叫poll阻塞等待網路包過來;
而執行緒池的工作執行緒只需要專心處理請求即可,所以使用也更充分。
(2)埠監聽執行緒
與執行緒池的(7)相同
參考文件
http://www.cnblogs.com/Anker/p/3265058.html
http://blog.csdn.net/zhanglu5227/article/details/7960677
相關文章
- MYSQL執行緒池總結(一)MySql執行緒
- Java執行緒池二:執行緒池原理Java執行緒
- 多執行緒:執行緒池理解和使用總結執行緒
- 二. 執行緒管理之執行緒池執行緒
- 【多執行緒總結(二)-執行緒安全與執行緒同步】執行緒
- Java-ThreadPool執行緒池總結Javathread執行緒
- 多執行緒(三)、執行緒池 ThreadPoolExecutor 知識點總結執行緒thread
- Android執行緒篇(二)Java執行緒池Android執行緒Java
- MySQL中介軟體之ProxySQL(5):執行緒、執行緒池、連線池MySql執行緒
- 案例分析|執行緒池相關故障梳理&總結執行緒
- 簡單的執行緒池(二)執行緒
- 淺談執行緒池(上):執行緒池的作用及CLR執行緒池執行緒
- 執行緒和執行緒池執行緒
- 多執行緒【執行緒池】執行緒
- 執行緒 執行緒池 Task執行緒
- 走進Java Android 的執行緒世界(二)執行緒池JavaAndroid執行緒
- Java8執行緒池理解(二)Java執行緒
- 執行緒池執行緒
- 淺談執行緒池(中):獨立執行緒池的作用及IO執行緒池執行緒
- Java多執行緒——執行緒池Java執行緒
- Java執行緒總結Java執行緒
- java執行緒池趣味事:這不是執行緒池Java執行緒
- 執行緒池以及四種常見執行緒池執行緒
- 多執行緒程式設計基礎(二)-- 執行緒池的使用執行緒程式設計
- Android執行緒篇(四)深入理解Java執行緒池(二)Android執行緒Java
- Java執行緒池總結和常用開源庫的使用Java執行緒
- 執行緒池關閉的小結執行緒
- java--執行緒池--建立執行緒池的幾種方式與執行緒池操作詳解Java執行緒
- java多執行緒9:執行緒池Java執行緒
- kuangshenshuo-多執行緒-執行緒池執行緒
- 執行緒的建立及執行緒池執行緒
- JavaThread多執行緒執行緒池Javathread執行緒
- Java多執行緒18:執行緒池Java執行緒
- 多執行緒之手撕執行緒池執行緒
- 執行緒池管理(1)-為什麼需要執行緒池執行緒
- 執行緒與執行緒池的那些事之執行緒池篇(萬字長文)執行緒
- 執行緒池 Executor執行緒
- Java執行緒池Java執行緒