CPU 核心和 sys.dm_os_workers
我們最近將 AOAG 集群故障轉移到了次要區域。在第一個區域,我們的盒子有 32 個核心,而在第二個區域,我們有 64 個核心。流量是相似的,但是在更大的盒子上,我們在 sys.dm_os_workers 中執行了更多的工作執行緒(以及 sys.dm_os_threads 中的執行緒)。這是提高 CPU 核心時的預期行為,還是我們應該關注所有這些空閒的工作人員?
我們正在執行 SQL Server 2017 CU 24。
max worker threads
配置為0
(預設值)。
max degree of parallelism
配置為2
在兩個區域中。在目前伺服器中,我們看到以下計數:
我真正想回答的是,當我們增加 CPU 數量時,工人的數量是否會急劇增加?
流量是相似的,但是在更大的盒子上,我們在 sys.dm_os_workers 中執行了更多的工作執行緒(以及 sys.dm_os_threads 中的執行緒)。
在不涉及細節的情況下,核心數量與正常負載下的伺服器程序中的工作執行緒或執行緒數量幾乎沒有關係。
執行緒的使用分為三個不同的類別,第一個是在搶占模式下執行長期永久任務所需的執行緒,例如 AG 設置中的租約、CLR 託管等,或 3rd 方模組項,例如驅動程序提供者。第二個桶是與 SQL 相關的長期永久任務,例如調度程序管理器、lazywriter 和其他 SQL 引導的項目,這些項目往往按numa 節點而不是按核心數進行分區。第三個桶是 SQL 查詢執行相關的項目,例如滿足查詢或登錄。
除了第一個之外,工作人員屬於相同的儲存桶,因為沒有與這些類型的執行緒相關聯的工作人員構造(下面的範例)。
雖然由於前兩個儲存桶假設有更多的 numa 節點,您將擁有更多的執行緒和工作人員,但除非執行緒和工作人員的數量已經很低,否則它不應該是戲劇性的。主要區別在於分配工作的位置。由於每個調度器都會有一定的本地隊列並且工作分佈在更多的調度器上,因此會有更多的工作人員和執行緒,因為即使有一個額外的調度程序也需要一個更多的執行緒和工作人員。
正常的伺服器活動將根據需要啟動和關閉工作程序和執行緒。工作負載或調度更改的周期性峰值可能會使這種影響看起來比預期的要大,但這是正常的。
總的來說,除非你達到最大工作執行緒數,否則這沒什麼好擔心的——在這種情況下,將值更改為其他值將不是作為解決方案的適當行動方案。
範例 - 儲存桶 1:長期存在的非 SQL 永久
sqlservr!DCOMInitThread kernel32!BaseThreadInitThunk ntdll!RtlUserThreadStart
範例 - 儲存桶 2:長期使用的 SQL Bootstrapped
sqlmin!lazywriter sqldk!SOS_Task::Param::Execute sqldk!SOS_Scheduler::RunTask sqldk!SOS_Scheduler::ProcessTasks sqldk!SchedulerManager::WorkerEntryPoint sqldk!SystemThread::RunWorker sqldk!SystemThreadDispatcher::ProcessWorker sqldk!SchedulerManager::ThreadEntryPoint kernel32!BaseThreadInitThunk ntdll!RtlUserThreadStart
範例 - 儲存桶 3:正常 SQL 使用者工作負載
sqllang!CXStmtSelect::XretExecute sqllang!CExecStmtLoopVars::ExecuteXStmtAndSetXretReturn sqllang!CMsqlExecContext::ExecuteStmts<1,0> sqllang!CMsqlExecContext::FExecute sqllang!CSQLSource::Execute sqllang!process_request sqllang!process_commands_internal sqllang!process_messages sqldk!SOS_Task::Param::Execute sqldk!SOS_Scheduler::RunTask sqldk!SOS_Scheduler::ProcessTasks sqldk!SchedulerManager::WorkerEntryPoint sqldk!SystemThread::RunWorker sqldk!SystemThreadDispatcher::ProcessWorker sqldk!SchedulerManager::ThreadEntryPoint kernel32!BaseThreadInitThunk ntdll!RtlUserThreadStart