高並發是服務端應用永恆的主題。MySQL 5.6 前採用 One-Connection-Per-Thread 模式:每個連接獨佔一線程,請求結束銷毀線程。雖有 thread_cache 緩解創建銷毀開銷,但無法解決連接數暴增帶來的問題:
Thread Pool 將處理單位從「連接」細化為「語句」,一個 Worker 線程可服務多個連接的請求。配合合理的 thread_pool_size(通常設為 CPU 核心數),在硬件資源可控範圍內實現高吞吐、低延遲、穩定的服務能力。
MySQL 通過 thread_handling 參數支持三種模式:
核心是 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);
};
線程池模式的實現 tp_scheduler_functions:
static scheduler_functions tp_scheduler_functions = {
0, // max_threads (動態)
NULL, NULL,
tp_init, // init: 初始化線程池
NULL, // init_new_connection_thread: 線程池無需
tp_add_connection, // add_connection: 分發連接到 Group
tp_wait_begin, // thd_wait_begin: 進入等待狀態統計
tp_wait_end, // thd_wait_end: 結束等待狀態統計
tp_post_kill_notification, // post_kill_notification: Kill 通知
NULL, // end_thread: 線程池無線程緩存概念
tp_end // end: 銷毀線程池
};
poll 監聽端口,accept 新連接。thread_handling 設置 THD 的 scheduler 函數指針。scheduler->add_connection(thd) 進入具體調度邏輯(線程池即 tp_add_connection)。| 參數 | 含義 | 建議值 |
|---|---|---|
| thread_handling | 調度模式:pool-of-threads 啟用線程池 | pool-of-threads |
| thread_pool_size | Group 數量,通常 = CPU 核心數 | CPU 核心數 |
| thread_pool_stall_limit | Timer 線程檢測 Group 停滯的間隔(毫秒) | 500-1000 |
| thread_pool_idle_timeout | Worker 空閒超時退出時間(秒) | 60 |
| thread_pool_oversubscribe | 每 Group 允許的活躍 Worker 上限(不含 Listener) | 10-1000 視負載 |
| threadpool_high_prio_mode | 優先隊列模式:transactions/statements/none | transactions |

每個綠色方框為一個 Group,包含:
oversubscribe 限制)全局一個 Timer 線程巡檢所有 Group,防止停滯、處理超時連接。
thread_id % group_count 確定目標 Group。get_event 獲取請求。handle_event 處理。epoll_wait 阻塞監聽。pthread_cond_timedwait 休眠 thread_pool_idle_timeout。oversubscribe + 1,超過則強制休眠。do_command 執行。epoll_ctl ADD;已註冊 → epoll_ctl MOD 重置事件。epoll_wait 監聽 Group 內所有連接 FD。epoll_event 取出 Connection。wait_timeout/interactive_timeout)。用於維護 active_thread_count 與 waiting_thread_count,供 Timer 線程決策。注意:waiting_threads 隊列存的是「空閒可執行線程」,非「等待鎖/I/O 的阻塞線程」。
分別調用 thread_group_init 初始化所有 Group(含 Epoll 創建)與 thread_group_close 銷毀。

場景:事務 A 持有鎖但在繁忙 Group 排隊;事務 B 依賴 A 釋放卻在閒置 Group 被調度卻因鎖阻塞。
解決:Group 內引入優先隊列,將「已持有鎖」或「已開啟事務」的連接請求置入優先隊列,Worker 優先消費,加速鎖釋放。
問題:大查詢(如 Dump)佔滿 Worker 導致正常業務請求無法調度(Group Stall)。Timer 雖會創建新 Worker,但若全是大查詢會拖垮整機。
解決:識別 Dump 類任務(如 SELECT * INTO OUTFILE、特定用戶/線程標記),其 Worker 不計入 thread_pool_oversubscribe 限制,確保業務 Worker 名額不被佔用。