本節提供關於判斷線程池效能最佳組態的指南,使用每秒交易次數等指標來衡量。
最重要的線程池線程群組數量,可以使用 --thread-pool-size
選項在伺服器啟動時設定;這無法在執行階段變更。此選項的建議值取決於使用的主要儲存引擎是 InnoDB
還是 MyISAM
如果主要儲存引擎是
InnoDB
,建議的線程池大小值是主機上可用的實體核心數,最多為 512。如果主要儲存引擎是
MyISAM
,線程池大小應該相當低。最佳效能通常會出現在值介於 4 到 8 之間。較高的值往往對效能有輕微負面但非戲劇性的影響。
線程池外掛程式可以處理的並行交易數上限由 thread_pool_max_transactions_limit
的值決定。此系統變數的建議初始設定值是實體核心數乘以 32。您可能需要從這個起始點調整值以適合特定的工作負載;此值的合理上限是預期的最大並行連線數;Max_used_connections
狀態變數的值可以作為判斷此值的指南。一個好的方法是以設定為這個值的 thread_pool_max_transactions_limit
開始,然後在觀察對輸送量的影響時向下調整。
線程群組中允許的最大查詢線程數由 thread_pool_query_threads_per_group
的值決定,這可以在執行階段調整。此值與線程池大小的乘積大約等於可用於處理查詢的線程總數。獲得最佳效能通常表示在 thread_pool_query_threads_per_group
與線程池大小之間為您的應用程式取得適當的平衡。thread_pool_query_threads_per_group
的較大值,當工作負載同時包含長時間與短時間執行的查詢時,會降低線程群組中的所有線程同時執行長時間執行查詢,同時封鎖較短的查詢的可能性。您應該記住,當使用較小的線程池大小與較大的 thread_pool_query_threads_per_group
值時,每個線程群組的連線輪詢操作負擔會增加。因此,我們建議 thread_pool_query_threads_per_group
的起始值為 2;將此變數設定為較低的值通常不會提供任何效能優勢。
為了在正常情況下獲得最佳效能,我們也建議您將 thread_pool_algorithm
設定為 1 以實現高並行。
此外,thread_pool_stall_limit
系統變數的值決定了如何處理被阻塞和長時間運行的語句。如果所有阻塞 MySQL 伺服器的呼叫都被回報給執行緒池,那麼執行緒池將始終知道執行緒何時被阻塞,但這可能並不總是正確的。例如,阻塞可能發生在尚未使用執行緒池回呼函式進行檢測的程式碼中。對於這種情況,執行緒池必須能夠識別看起來被阻塞的執行緒。這是透過由 thread_pool_stall_limit
的值所決定的逾時來完成的,這可以確保伺服器不會完全被阻塞。thread_pool_stall_limit
的值表示 10 毫秒的時間間隔數,因此 600
(最大值)表示 6 秒。
thread_pool_stall_limit
也使執行緒池能夠處理長時間運行的語句。如果允許長時間運行的語句阻塞一個執行緒群組,則分配給該群組的所有其他連線將被阻塞,並且在長時間運行的語句完成之前無法開始執行。在最糟糕的情況下,這可能需要數小時甚至數天的時間。
thread_pool_stall_limit
的值應選擇為使執行時間長於此值的語句被視為停滯。停滯的語句會產生許多額外的開銷,因為它們會涉及額外的上下文切換,在某些情況下甚至會產生額外的執行緒建立。另一方面,將 thread_pool_stall_limit
參數設定得太高,意味著長時間運行的語句會不必要地阻塞許多短時間運行的語句更長的時間。較短的等待值允許執行緒更快地開始。較短的值也更適合避免死鎖情況。較長的等待值適用於包含長時間運行語句的工作負載,以避免在當前語句執行時啟動過多新的語句。
假設伺服器執行一個工作負載,其中 99.9% 的語句在 100 毫秒內完成,即使伺服器負載很高,剩餘的語句則在 100 毫秒到 2 小時之間平均分佈。在這種情況下,將 thread_pool_stall_limit
設定為 10 (10 × 10ms = 100ms) 是合理的。預設值 6 (60ms) 適用於主要執行非常簡單語句的伺服器。
可以於執行時變更 thread_pool_stall_limit
參數,以便您可以找到適合伺服器工作負載的平衡點。假設已啟用 tp_thread_group_stats
表格,您可以使用以下查詢來判斷已執行的停滯語句所佔的比例
SELECT SUM(STALLED_QUERIES_EXECUTED) / SUM(QUERIES_EXECUTED)
FROM performance_schema.tp_thread_group_stats;
這個數字應該盡可能低。為了減少語句停滯的可能性,請增加 thread_pool_stall_limit
的值。
當語句到達時,它在實際開始執行之前,最長可以被延遲多久?假設適用以下條件
低優先順序佇列中有 200 個語句在排隊。
高優先順序佇列中有 10 個語句在排隊。
thread_pool_prio_kickup_timer
設定為 10000(10 秒)。thread_pool_stall_limit
設定為 100(1 秒)。
在最糟糕的情況下,10 個高優先順序語句代表 10 個長時間持續執行的交易。因此,在最糟糕的情況下,沒有語句可以移至高優先順序佇列,因為其中始終已包含等待執行的語句。10 秒後,新的語句符合移至高優先順序佇列的資格。但是,在它能夠移動之前,它之前的所有語句也必須移動。這可能需要另外 2 秒,因為每秒最多有 100 個語句移動到高優先順序佇列。現在,當語句到達高優先順序佇列時,前面可能會有許多長時間運行的語句。在最糟糕的情況下,這些語句中的每一個都會停滯,並且在從高優先順序佇列中檢索下一個語句之前,每個語句需要 1 秒。因此,在這種情況下,新語句需要 222 秒才能開始執行。
這個範例顯示了應用程式的最糟糕情況。如何處理它取決於應用程式。如果應用程式對回應時間有很高的要求,則它很可能應在較高的層級上自行限制使用者。否則,它可以使用執行緒池配置參數來設定某種最大等待時間。