SQLSERVER獨特的任務調度算法"SQLOS"
微軟開發SQLOS的背景:
SQLSERVER作為一個企業級數據庫平台,一個基本的要求就是要有能力順暢地同時處理成百上千的用戶請求,SQLSERVER要使線程調度
得更加適應高並發的數據庫應用。
由於以上背景:
SQLSERVER在Windows的基礎上開發出了一套自己的任務調度機制。所以SQLSERVER作為一個應用程序,又抽象出一般由操作系統代為
管理的功能,例如:
任務調度管理子系統
內存管理
錯誤,異常處理機制
死鎖偵測和解決機制
運行第三方代碼(dll,extended SP等)機制
SQLSERVER的管理功能組件又叫SQLOS SQL OPERATING SYSTEM ,而內存管理和任務調度管理是SQLOS的兩大核心內容
對於SQLSERVER來講,除了從DAC dedicated administrator connection過來的連接,其他用戶連接對SQL來講都是同等重要的,
而這樣的連接在同一個時間點,可能會有成百上千。 所以SQLSERVER完全依賴Windows任務調度是不行的。
SQLSERVER的這一套任務調度機制的特點:
1、只有需要運行任務的連接才會被分配線程。出於空閑狀態的連接,在SQLSERVER里會以一組數據結構表示,所以不會占用線程資源。大大降低
SQLSERVER進程需要的線程數目
2、對於每一個CPU,SQLSERVER內部會有一個調度(scheduler),由這個scheduler決定在某個時間點,到底是哪個SQLSERVER線程去運行。
所以在Windows層面,每個CPU最多只會對應一個處於運行狀態的線程。大大降低Windows層面的上下文切換context switch
實踐證明:很多有着1000~2000個並發用戶的SQLSERVER,線程數也只需要一兩百個。SQLSERVER完成的批處理量每秒鍾可以達到3000~4000個。
SQLOS的幾個概念:
scheduler
對於每個邏輯CPU,SQLSERVER會有一個scheduler與之對應,在SQL層面上代表CPU對象,只有拿到scheduler所有權的任務worker才能在這個邏輯CPU上運行
所謂邏輯CPU,就是SQLSERVER從Windows層面上看到的CPU數目,如果是一個雙核的CPU,那么一個物理CPU在SQL看來就是兩個邏輯CPU。如果系統還使用了
超線程hyper-threaded ,那對SQLSERVER來講就是4個邏輯CPU
規則: 每個scheduler上的最大worker數目等於SQLSERVER的最大線程數除以scheduler的數目 ,在同一個時間點,只能有一個擁有scheduler的worker處於運行
狀態,其他worker都必須處於等待狀態。這樣能降低每個邏輯CPU上的處於正在運行狀態的線程數目,降低context switch,提供可擴展性
scheduler是SQLSERVER的一個邏輯概念,他不與物理CPU相綁定。也就是說,一個scheduler可以被Windows安排一會兒在這個CPU上,一會兒在那個CPU上。
但是,如果在sp_configure里設置了CPU affinity mask,那么scheduler就會固定在某個特定的CPU上
worker
每個worker跟一個線程(或纖程fiber)相對應,是SQLSERVER任務的執行單位。SQLSERVER不直接調度線程/纖程,而是調度worker,使得SQLSERVER能夠控制
任務調度
規則: 每個worker會固定代表一個線程(或纖程),並且和一個scheduler相綁定。如果scheduler是固定在某個CPU上的(通過設置CPU affinity mask),那么
worker也會固定在某個CPU上
每個scheduler有worker的上限值,並且可以根據SQLSERVER工作負荷創建或釋放worker,每次worker都會去運行一個完整的任務(task)。在任務做完之前不會
退出,除非這個任務主動進入等待狀態。
scheduler只在有新任務要運行,而當前沒有空閑的worker的情況下,才會創建新的worker。
某個worker空閑超過15分鍾,scheduler可能會刪除這個worker,以及其對應的線程。當SQLSERVER遇到內存壓力的時,也會大量刪除處於空閑狀態的worker,以
節省multi-page的內存開銷
各種CPU和SQLSERVER版本組合自動配置的最大工作線程數
CPU數 32位計算機 64位計算機
<=4 256 512
8 288 576
16 352 704
32 480 960
task
在worker上運行的最小任務單元。最簡單的task就是一個簡單batch。例如,客戶發過來下面的請求:
1 SELECT @@SERVERNAME 2 GO 3 SELECT GETDATE() 4 GO
那么這兩個batch就分別是兩個task。SQLSERVER會先分配給第一個batch(select @@servername)一個worker,將結果返回給客戶端,再分配第二個batch
(select getdate())一個worker。這兩個worker可能是不同的worker,甚至在不同的scheduler上
只要一個task開始運行,他就不會從這個worker上被移出。例如,如果一個select語句被其他連接阻塞住,worker就不能繼續運行,只能進入等待狀態。但是這個
select task 不會將這個worker釋放,讓他做其他任務。所以結果是這個worker所對應的線程會進入等待狀態
yielding
SQLOS的任務調度算法的核心,就是所有在邏輯scheduler上運行的worker都是非搶占式的 (non-preemptive)。worker始終在scheduler上運行,直到他運行結束,或者主動將scheduler讓出給其他worker為止。這個“讓出”scheduler的動作,我們叫yieding
每個scheduler都會有一個runnable列表,所有等待CPU運行的worker都會在這個列表里排隊,以先進先出的算法,等待SQL分配給他scheduler運行
SQLSERVER定義了很多yieding的規則,約束一個task在scheduler運行的時間。如果task比較復雜,不能很快完成,會保證task在合適的時間點做yieding,不至於占用scheduler太多時間。
常見時間點:
1、當worker每次要去讀數據頁的時候,SQLSERVER會檢查這個worker已經在scheduler上運行了多久,如果已經超過4ms,就做yielding
2、每做64KB的結果集排序,就會做一次yielding
3、在做語句編譯compile的過程中(這個過程比較占CPU資源),經常會有yieding
4、如果客戶端不能及時把結果集取走,worker就會做yieding
5、一個batch里的每一句話做完,都會做一次yieding
正常來講,哪怕一個task要做很久,他使用的worker是會經常做yieding的,不會長時間占用CPU不放。如果在一個scheduler上同時有很多worker要運行,
SQLSERVER通過worker自動yielding的方式調度並發運行。這個比Windows用上下文切換context switch更有效
下面用圖來說明SQLOS的任務調度算法:

總結:
對於每個CPU,SQLSERVER都會有一個scheduler與之對應。在每個scheduler里,會有若干個worker,對應
於每個線程。在客戶端發過來請求之后,SQL會將其分解成一個或多個task。根據每個scheduler的繁忙程度,
task會被分配到某個scheduler上。如果scheduler里有空閑的worker,task就會被分配到某個worker上。
如果沒有,scheduler會創建新的worker,供task使用。如果scheduler里的worker已經到了他的上限值,
而他們都有task要運行,那么新的task只好進入等待worker的狀態
使用下面兩個SQL語句可以查看當前SQLSERVER有多少個workers在工作,有多少個tasks在運行
1 SELECT * FROM sys.dm_os_workers 2 SELECT * FROM sys.dm_os_tasks

----------------------------------------------------------華麗的分割線---------------------------------------------------------
說一下上面的圖的含義
SELECT * FROM sys.dm_os_workers



其他列的解釋大家可以看一下MSDN
http://msdn.microsoft.com/zh-cn/library/ms178626(v=SQL.105).aspx
------------------------------------------------------------------------------------------------------------
SELECT * FROM sys.dm_os_tasks

任務的狀態可以是下列選項之一:
PENDING:正在等待工作線程。
RUNNABLE:可運行,但正在等待接收量程。
RUNNING:當前正在計划程序中運行。
SUSPENDED:具有工作線程,但正在等待事件。
DONE:已完成。
SPINLOOP:陷入自旋鎖
MSDN的解釋:http://msdn.microsoft.com/zh-cn/library/ms174963(v=SQL.105).aspx
很久沒有寫文章了,希望大家看了我的文章能夠更加深入了解SQLSERVER
要睡了,熬不住了~
----------------------------------------------------------
2013-6-3補充
附網上流傳的手稿圖一張

2014-2-2補充:
SQLOS所用的DLL

