寫這篇文章的目的是想記錄此次的撰寫文章的經歷,其實一篇技術文章來得並不容易,以前本身寫博客的隨意性很強,排版能夠根據本身喜愛,可是一篇文章要被你們所接受,讓你們願意讀完實際上是一件很難的事情,因此排版仍是挺重要的,這裏我想提示下IT168的編輯,個人SQL代碼實際上是有高亮的,可是編輯發出來後發現高亮不見,閱讀起來的確很不爽,估計你們也有一樣的感受。再者就是講講此次的技術內容,其實在SQL Server 2014以前就有資源調控器這個功能了,因此網上也很多這方面的資料,因此要寫這個主題就須要找到一些新的亮點(新功能+通俗類比),這也是讀者感興趣的地方。我對寫這篇文章還有一個感覺就是,你須要不斷修改、完善你文章的內容,包括總體文章的架構是否合理?語言描述是否通順?邏輯是否清晰?內容是否豐富?測試案例是否全面等等。因此這篇文章給我最大的感覺是:一篇憑良心出品的文章的確來之不易。html
2014年5月7日,從宋沄劍宋大俠得知有一個爲IT168和微軟撰寫SQL Server 2014新功能文章的機會,撰寫的內容爲:SQL Server 2014的資源調控器(Resource Governor),這裏再次感謝宋大俠的推薦。sql
特此說明:因爲版權的緣由,這裏的正文爲引用IT168的稿件地址:http://tech.it168.com/a2014/0526/1627/000001627131_all.shtml數據庫
【IT168 專稿】在數據庫服務器上,有三種硬件資源一直是影響數據庫性能好壞的關鍵,甚至會影響到整個生產系統的使用,這三種資源分別是內存、CPU和物理IO。當數據庫服務器上掛載了多個數據庫的時候,極有可能發生資源的爭奪,如何能保證重要數據庫在擁有足夠資源的前提下再把多餘的資源提供給其它數據庫呢?資源調控器應運而生。api
在SQL Server 2014中已經增長了對物理IO資源的控制,這個功能在私有云的數據庫服務器上的做用體現得尤其重要,它可以爲私有云用戶提供有效的控制、分配,並隔離物理IO資源。服務器
在講述SQL Server 2014的資源調控器(Resource Governor)以前,讓咱們來找一找生活中資源調控器的影子。你們都知道一線城市的交通能夠用擁堵一詞來形容,你時常能夠見到如圖1所示的路面情況。框架
爲了緩解擁堵的交通,北京、上海、廣州等城市都修建了一個稱之爲BRT的交通設施,BRT的全稱爲Bus Rapid Transit,意爲快速公交,就是在擁堵的公路上分配一條專門提供給公交車使用的車道,儘可能保證大部分人出行的通暢。BRT專用車道的大體狀況如圖2所示。性能
交通部門規定:在出行高峯期,BRT專用道只供公交車使用,其它機動車只能使用BRT專用道以外的車道資源。人有專門的人行道,自行車有自行車道。根據這個邏輯,能夠得出如圖3所示的人與車在使用道路資源的邏輯結構圖:
瞭解了生活中的資源調控器以後,咱們立刻進入今天的主題:SQL Server資源調控器,它與生活中的資源調控器有着驚人的類似之處。
SQL Server 2014的資源調控器默認包含了兩個工做負荷組(internal、default)和兩個資源池(internal、default),在沒有手動設置資源調控器的狀況下,建立的數據庫會默認放到default資源池當中。
SQL Server資源調控器接收到會話請求後,經過用戶定義的分類器函數把會話進行劃分並路由到相應的工做負荷組,再經過工做負荷組找到對應的資源池,由資源池中設置的內存、CPU和物理IO資源的閥值來決定會話請求的資源分配。根據描述,能夠得出如圖4所示的SQL Server資源調控器邏輯結構圖:
理解了SQL Server資源調控器的原理以後,接着講述資源調控器在CPU方面的運用場景:假設數據庫服務器上有一個重要的數據庫ImportantDB和一個普通的數據庫GeneralDB,從業務出發,但願服務器上的資源在知足了ImportantDB以後才考慮分配多餘的資源給GeneralDB,保證重要業務系統的正常運行。
須要說明的是:筆者的機器是Azure上的虛擬機,機器的配置如圖5所示,下面的測試都是基於這個環境的,因此讀者在自行測試的時候應該根據本身的機器環境進行調整。
假設GeneralDB 數據庫佔用的CPU最大值爲10%,ImportantDB數據庫佔用的CPU最大值爲90%,實現這個需求的步驟以下:
1. 建立測試數據庫
--建立重要業務數據庫 CREATE DATABASE ImportantDB GO --建立普通業務數據庫 CREATE DATABASE GeneralDB GO
2. 建立並配置新的資源池和工做負荷組
--建立重要業務數據庫的資源池 CREATE RESOURCE POOL rpImportantDB WITH ( MAX_CPU_PERCENT = 90, MIN_CPU_PERCENT = 10 ) GO --建立重要業務數據庫的工做負荷組 CREATE WORKLOAD GROUP wgImportantDB WITH ( IMPORTANCE = MEDIUM ) USING rpImportantDB GO --建立普通業務數據庫的資源池 CREATE RESOURCE POOL rpGeneralDB WITH ( MAX_CPU_PERCENT = 10, MIN_CPU_PERCENT = 0 ) GO --建立重要業務數據庫的工做負荷組 CREATE WORKLOAD GROUP wgGeneralDB WITH ( IMPORTANCE = LOW ) USING rpGeneralDB GO
3. 更新內存中資源調控器的配置
--更新內存中的配置 ALTER RESOURCE GOVERNOR RECONFIGURE GO
4. 查詢資源調控器中資源池和工做負荷組的配置信息,返回結果如圖6所示:
--查詢獲取資源池和工做負荷組配置 USE master SELECT * FROM sys.resource_governor_resource_pools SELECT * FROM sys.resource_governor_workload_groups GO
5. 建立分類器函數,這是一個用戶自定義函數 (UDF),它供資源調控器用來對會話進行分類,以便將它們路由到對應的工做負荷組中,函數返回工做負荷組的名稱;
--建立分類器函數 CREATE FUNCTION fn_Classifier() RETURNS SYSNAME WITH SCHEMABINDING AS BEGIN DECLARE @strGroupName SYSNAME IF ORIGINAL_DB_NAME()='ImportantDB' SET @strGroupName='wgImportantDB' ELSE IF ORIGINAL_DB_NAME()='GeneralDB' SET @strGroupName='wgGeneralDB' ELSE SET @strGroupName='default' RETURN @strGroupName END GO
6. 將分類器函數fn_Classifier註冊到資源調控器並更新內存中的配置
--註冊分類器函數到資源調控器並更新內存中的配置 ALTER RESOURCE GOVERNOR WITH (CLASSIFIER_FUNCTION = dbo.fn_Classifier) ALTER RESOURCE GOVERNOR RECONFIGURE GO
7. 接下來就是對CPU進行測試,建立能佔用CPU的測試腳本,把下面的腳本分別保存爲GeneralDB.sql和ImportantDB.sql:
--測試CPU DECLARE @Counts INT WHILE 1=1 BEGIN SELECT @Counts=COUNT(*) FROM SYS.COLUMNS A,SYS.COLUMNS B END
8. Windows操做系統爲SQL Server資源調控器提供了大量的性能計數器幫助瞭解資源的使用狀況,查看SQLServer:Resource Pool Stats對象下的CPU usage%計數器,裏面包括四個對象實例:default、internal和剛剛建立的rpGeneralDB、rpImportantDB,如圖7所示:
9. 由於分類器函數fn_Classifier 經過函數ORIGINAL_DB_NAME()返回用戶在數據庫鏈接字符串中指定的數據庫名稱,因此能夠經過使用SQLCMD來模擬用戶輸入,SQLCMD調用GeneralDB.sql和ImportantDB.sql腳本的命令以下:
SQLCMD -S . -d GeneralDB -i GeneralDB.sql
SQLCMD -S . -d ImportantDB -i ImportantDB.sql
10. 性能計數器CPU usage%記錄了在測試過程當中CPU的使用狀況,結果如圖8所示:
執行GeneralDB.sql後,藍色實例rpGeneralDB佔用了25%左右的CPU;接着在另外的窗口執行ImportantDB.sql後,紫色實例rpImportantDB一樣佔用了25%左右的CPU,以一樣的方式繼續增長紫色實例rpImportantDB的CPU佔用量,當佔用量超過了設置的90%,能夠發現藍色實例rpGeneralDB佔用CPU百分比立刻降低了。從這個測試的結果來看,SQL Server資源調控器已經達到咱們預期對CPU資源的規劃效果。
值得一提的是,你們可能已經發現rpImportantDB資源池的CPU usage%計數器的最新值高達97.470%,資源池不是設置了MAX_CPU_PERCENT = 90嗎?怎麼會超過這個限制呢?其實這是由於rpGeneralDB資源池的MIN_CPU_PERCENT = 0,因此在沒有其它最小CPU的限制的話,rpImportantDB資源池佔用的CPU是有可能達到100%的。
前面講述關於CPU資源的控制更多的是爲下面講述SQL Server 2014在IO資源上的調控作鋪墊,上面的例子是以數據庫爲單位規劃各個庫佔用CPU的百分比,下面的例子咱們就將以登錄用戶來劃分磁盤的IOPS;
假設generalUser用戶佔用的IOPS最大值爲10,importantUser用戶佔用IOPS的最大值爲20,實現這個需求的步驟以下:
1. 首先,解除分類器函數與資源調控器註冊關係;
USE [master] GO --解除分類器函數註冊 ALTER RESOURCE GOVERNOR WITH (CLASSIFIER_FUNCTION = NULL) GO
2. 接着,修改rpImportantDB、rpGeneralDB資源池,添加MAX_IOPS_PER_VOLUME和MIN_IOPS_PER_VOLUME兩個屬性值;
--修改重要業務數據庫的資源池 ALTER RESOURCE POOL rpImportantDB WITH ( MAX_CPU_PERCENT = 90, MIN_CPU_PERCENT = 10, MAX_IOPS_PER_VOLUME = 20, MIN_IOPS_PER_VOLUME = 0 ) --修改普通業務數據庫的資源池 ALTER RESOURCE POOL rpGeneralDB WITH ( MAX_CPU_PERCENT = 10, MIN_CPU_PERCENT = 0, MAX_IOPS_PER_VOLUME = 10, MIN_IOPS_PER_VOLUME = 0 ) GO
3. 接着修改分類器函數fn_Classifier(),把它修改爲按照登錄用戶:importantUser和generalUser(這兩個登錄用戶請自行建立,爲了方便測試,這兩個用戶都是管理員身份)返回對應的工做負荷組名稱;
--修改分類器函數 ALTER FUNCTION fn_Classifier() RETURNS SYSNAME WITH SCHEMABINDING AS BEGIN DECLARE @strGroupName SYSNAME IF SUSER_SNAME()='importantUser' SET @strGroupName='wgImportantDB' ELSE IF SUSER_SNAME()='generalUser' SET @strGroupName='wgGeneralDB' ELSE SET @strGroupName='default' RETURN @strGroupName END GO
4. 從新把分類器函數fn_Classifier()註冊到資源調控器並更新內存中的配置;
--註冊分類器函數到資源調控器並更新內存中的配置 ALTER RESOURCE GOVERNOR WITH (CLASSIFIER_FUNCTION = dbo.fnClassifier) ALTER RESOURCE GOVERNOR RECONFIGURE GO
5. 在GeneralDB數據庫中建立一個名爲TestIOPS的表,並向表中插入10000行記錄;
USE [GeneralDB] GO --建立表 CREATE TABLE [dbo].[TestIOPS]( [Id] [int] IDENTITY(1,1) NOT NULL, [MyStr] [nchar](450) NULL ) ON [PRIMARY] GO --插入測試數據 SET NOCOUNT ON; GO DECLARE @count INT = 0; WHILE (@count < 10000) BEGIN INSERT INTO [GeneralDB].[dbo].[TestIOPS](MyStr) VALUES(REPLICATE('a',450)); SET @count += 1; END GO
6. 使用generalUser用戶登錄SSMS,經過在TestIOPS表的MyStr字段建立一個非彙集索引來測試IOPS,在執行建立索引的腳本以前,打開性能計數器幫助監控建立索引時的IOPS,找到SQLServer:Resource Pool Stats對象下的Disk Write IO/sec計數器,計數器監控的結果如圖9所示:
USE [GeneralDB] GO --建立索引 CREATE NONCLUSTERED INDEX idx_MyStr_1 ON [GeneralDB].[dbo].[TestIOPS] ([MyStr]); GO
從圖9能夠看出資源池rpGeneralDB 中Disk Write IO/sec計數器的最大值爲10,發生Disk Write IO/sec的時間從22:54:52持續到22:55:02,持續時間大概爲20秒;
7. 接着,使用importantUser用戶登錄SSMS,建立上一步驟中同樣的索引結構,只須要修改索引名稱便可,一樣須要監控SQLServer:Resource Pool Stats對象下的Disk Write IO/sec計數器,計數器監控的結果如圖10所示:
USE [GeneralDB] GO --建立索引 CREATE NONCLUSTERED INDEX idx_MyStr_2 ON [GeneralDB].[dbo].[TestIOPS] ([MyStr]); GO
從圖10能夠看出資源池rpImportantDB 中Disk Write IO/sec計數器的最大值爲20,發生Disk Write IO/sec的時間從22:59:52持續到23:00:11,持續時間大概爲9秒;
經過上面資源調控器的IOPS的測試,能夠發現即便兩個用戶執行了相同操做,但IOPS卻能夠根據不一樣用戶而有所區別,這徹底歸功於資源調控器對IO資源的控制,這將爲數據庫主機或者私有云上運行IO密集型工做負載提供解決方案。
資源調控器(Resource Governor)在沒有資源爭奪的時候,那麼運用能夠分配到100%資源,若是達到了分類器函數的臨界值,會按照預先分配的比例進行調配,從而保證重要業務在資源緊缺的狀況下順利進行,加強對數據庫的管理性。SQL Server 2014的新功能中提供了一個很是重要的IO資源控制,這將爲私有云用戶提供更人性化的管理和服務。
陳暢亮,微軟SQL Server最有價值專家,目前就任於廣州某互聯網公司任數據庫團隊Leader,專一於數據庫解決方案與性能調優。