MySQL執行緒池

2021-08-17 11:11:39 字數 4423 閱讀 5363

在傳統方式下,mysql執行緒排程方式有兩種:每個連線乙個執行緒(one-thread-per-connection)和所有連線乙個執行緒(no-threads)。在實際生產中,一般用的是前者。即每當有乙個客戶端連線到mysql伺服器,mysql伺服器都會為該客戶端建立乙個單獨的執行緒。連線數越多,則相應的執行緒會越多。

如果大部分執行緒處於空閒狀態,則不會對伺服器的效能造成很大的影響。但如果同時執行的執行緒太多,會導致作業系統頻繁的上下文切換。當有大量請求併發訪問時,一定伴隨著資源的不斷建立和釋放,導致資源利用率低,降低了服務質量。引入執行緒池的目的,就是為了減少同時執行的執行緒的數量,降低上下文切換的次數。

執行緒池是mysql5.6的乙個核心功能,對於伺服器應用而言,無論是web應用服務還是db服務,高併發請求始終是乙個繞不開的話題。執行緒池是一種通用的技術,通過預先建立一定數量的執行緒,當有請求達到時,執行緒池分配乙個執行緒提供服務,請求結束後,該執行緒又去服務其他請求。 通過這種方式,避免了執行緒和記憶體物件的頻繁建立和釋放,降低了服務端的併發度,減少了上下文切換和資源的競爭,提高資源利用效率。所有服務的執行緒池本質都是位了提高資源利用效率,並且實現方式也大體相同。本文主要說明mysql執行緒池的實現原理。

thread_pool_size:表示執行緒池的group個數,一般設定為當前cpu核心數目。理想情況下,乙個group乙個活躍的工作執行緒,達到充分利用cpu的目的。

thread_pool_idle_timeout:當乙個worker空閒一段時間後會自動退出,保證執行緒池中的工作執行緒在滿足請求的情況下,保持比較低的水平。

執行緒池與連線池

連線池通常實現在client端,是指應用(客戶端)建立預先建立一定的連線,利用這些連線服務於客戶端所有的db請求。如果某乙個時刻,空閒的連線數小於db的請求

數,則需要將請求排隊,等待空閒連線處理。通過連線池可以復用連線,避免連線的頻繁建立和釋放,從而減少請求的平均響應時間,並且

在請求繁忙時,通過請求排隊,可以緩衝應用對db的衝擊。

執行緒池實現在server端,通過建立一定數量的執行緒服務db請求,相對於one-conection-per-thread的乙個執行緒服務乙個連線的

方式,執行緒池服務的最小單位是語句,即乙個執行緒可以對應多個活躍的連線。通過執行緒池,可以將server端的服務執行緒數控制在一定的範圍,

減少了系統資源的競爭和執行緒上下文切換帶來的消耗,同時也避免出現高連線數導致的高併發問題。

連線池和執行緒池相輔相成,通過連線池可以減少連線的建立和釋放,提高請求的平均響應時間,並能很好地控制乙個應用的db連線數,

但無法控制整個應用集群的連線數規模,從而導致高連線數,通過執行緒池則可以很好地應對高連線數,保證server端能提供穩定的服務。

執行緒池優化

1.排程死鎖解決

引入執行緒池解決了多執行緒高併發的問題,但也帶來乙個隱患。假設,a,b兩個事務被分配到不同的group中執行,a事務已經開始,並且持有鎖,但由於a所在的group比較繁忙,導致a執行一條語句後,不能立即獲得排程執行;而b事務依賴a事務釋放鎖資源,雖然b事務可以被排程起來,但由於無法獲得鎖資源,導致仍然需要等待,這就是所謂的排程死鎖。由於乙個group會同時處理多個連線,但多個連線不是對等的。比如,有的連線是第一次傳送請求;而有的連線對應的事務已經開啟,並且持有了部分鎖資源。為了減少鎖資源爭用,後者顯然應該比前者優先處理,以達到盡早釋放鎖資源的目的。因此在group裡面,可以新增乙個優先順序佇列,將已經持有鎖的連線,或者已經開啟的事務的連線發起的請求放入優先佇列,工作執行緒首先從優先佇列獲取任務執行。

2.大查詢處理

假設一種場景,某個group裡面的連線都是大查詢,那麼group裡面的工作執行緒數很快就會達到thread_pool_oversubscribe引數設定值,對於後續的連線請求,則會響應不及時(沒有更多的連線來處理),這時候group就發生了stall。通過前面分析知道,timer執行緒會定期檢查這種情況,並建立乙個新的worker執行緒來處理請求。如果長查詢**於業務請求,則此時所有group都面臨這種問題,此時主機可能會由於負載過大,導致hang住的情況。這種情況執行緒池本身無能為力,因為源頭可能是爛sql併發,或者sql沒有走對執行計畫導致,通過其他方法,比如sql高低水位限流或者sql過濾手段可以應急處理。但是,還有另外一種情況,就是dump任務。很多下游依賴於資料庫的原始資料,通常通過dump命令將資料拉到下游,而這種dump任務通常都是耗時比較長,所以也可以認為是大查詢。如果dump任務集中在乙個group內,並導致其他正常業務請求無法立即響應,這個是不能容忍的,因為此時資料庫並沒有壓力,只是因為採用了執行緒池策略,才導致了請求響應不及時,為了解決這個問題,我們將group中處理dump任務的執行緒不計入thread_pool_oversubscribe累計值,避免上述問題。

關鍵介面

1. tp_add_connection[處理新連線]

1)  建立乙個connection物件

2)  根據thread_id%group_count確定connection分配到哪個group

3)  將connection放進對應group的佇列

4)  如果當前活躍執行緒數為0,則建立乙個工作執行緒

2. worker_main[工作執行緒]

1)  呼叫get_event獲取請求

2)  如果存在請求,則呼叫handle_event進行處理

3)  否則,表示佇列中已經沒有請求,退出結束。

3. get_event[獲取請求]

1)  獲取乙個連線請求

2)  如果存在,則立即返回,結束

3)  若此時group內沒有listener,則執行緒轉換為listener執行緒,阻塞等待

4)  若存在listener,則將執行緒加入等待佇列頭部

5)  執行緒休眠指定的時間(thread_pool_idle_timeout)

6)  如果依然沒有被喚醒,是超時,則執行緒結束,結束退出 

7)  否則,表示佇列裡有連線請求到來,跳轉1

備註:獲取連線請求前,會判斷當前的活躍執行緒數是否超過了

thread_pool_oversubscribe+1,若超過了,則將執行緒進入休眠狀態。

4. handle_event[處理請求]

1)  判斷連線是否進行登入驗證,若沒有,則進行登入驗證

2)  關聯thd例項資訊

3)  獲取網路資料報,分析請求

4)  呼叫do_command函式迴圈處理請求

5)  獲取thd例項的套接字控制代碼,判斷控制代碼是否在epoll的監聽列表中

6)  若沒有,呼叫epoll_ctl進行關聯

7)  結束

5.listener[監聽執行緒]

1)  呼叫epoll_wait進行對group關聯的套接字監聽,阻塞等待

2)  若請求到來,從阻塞中恢復

3)  根據連線的優先級別,確定是放入普通佇列還是優先佇列

4)  判斷佇列中任務是否為空

5)  若隊列為空,則listener轉換為worker執行緒

6)  若group內沒有活躍執行緒,則喚醒乙個執行緒

備註:這裡epoll_wait監聽group內所有連線的套接字,然後將監聽到的連線

請求push到佇列,worker執行緒從佇列中獲取任務,然後執行。

6. timer_thread[監控執行緒]

1)  若沒有listener執行緒,並且最近沒有io_event事件

2)  則建立乙個喚醒或建立乙個工作執行緒

3)  若group最近一段時間沒有處理請求,並且佇列裡面有請求,則

4)  表示group已經stall,則喚醒或建立執行緒

5)檢查是否有連線超時 

備註:timer執行緒通過呼叫check_stall判斷group是否處於stall狀態,通過呼叫timeout_check檢查客戶端連線是否超時。

7.tp_wait_begin[進入等待狀態流程]

1)  active_thread_count減1,waiting_thread_count加1

2)設定connection->waiting= true

3)  若活躍執行緒數為0,並且任務佇列不為空,或者沒有監聽執行緒,則

4)  喚醒或建立乙個執行緒

8.tp_wait_end[結束等待狀態流程]

1)  設定connection的waiting狀態為false

2)  active_thread_count加1,waiting_thread_count減1

備註:1)waiting_threads這個list裡面的執行緒是空閒執行緒,並非等待執行緒,所謂空閒執行緒是隨時可以處理任務的執行緒,而等待執行緒則是因為等待鎖,或等待io操作等無法處理任務的執行緒。

2)tp_wait_begin和tp_wait_end的主要作用是由於匯報狀態,即使更新active_thread_count和waiting_thread_count的資訊。

9. tp_init/tp_end

分別呼叫thread_group_init和thread_group_close來初始化和銷毀執行緒池

mysql 執行緒池 Mysql 執行緒池

why 在5.6以前,mysql會對每個連線建立乙個執行緒,請求結束後銷毀執行緒。在高併發的情況下,為了避免頻繁建立和釋放連線,可以通過thread cache將執行緒快取起來,請求來了先嘗試從cache中獲取,重複利用執行緒資源。問題在低併發的情況下,thread cache可以成為乙個有效的優化...

mysql 執行緒池 c MySQL執行緒池

mysql執行緒池 在麼mysql中,執行緒池指的是用來管理處理mysql客戶端連線任務的執行緒的一種機制。如果把執行緒看做系統資源那麼執行緒池本質上是對系統資源的管理,對應作業系統來說執行緒的建立和銷毀是比較消耗系統資源的,頻繁的建立與銷毀執行緒必然給系統帶來不必要的資源浪費,特別是在高負載的情況...

mysql 執行緒池測試 MySQL執行緒池測試

mysql執行緒池 thread pool 的處理 在預設的mysql的連線模型中,乙個連線對應乙個mysql伺服器的執行緒來處理連線請求 很類似於oracle的專用伺服器連線 在某些情況這種配置可能會導致一些問題,比如以下情形 1,伺服器同時太多活動連線線程,而cpu個數有限,會導致context...