談談我的微軟特約稿:《SQL Server 2014 新特性:IO資源調控》
一.本文所涉及的內容(Contents)
二.背景(Contexts)
寫這篇文章的目的是想記錄這次的撰寫文章的經歷,其實一篇技術文章來得並不容易,之前自己寫部落格的隨意性很強,排版可以根據自己喜好,但是一篇文章要被大家所接受,讓大家願意讀完其實是一件很難的事情,所以排版還是挺重要的,這裡我想提示下IT168的編輯,我的SQL程式碼其實是有高亮的,但是編輯發出來後發現高亮不見,閱讀起來的確很不爽,估計大家也有同樣的感覺。再者就是講講這次的技術內容,其實在SQL Server 2014之前就有資源調控器這個功能了,所以網上也不少這方面的資料,所以要寫這個主題就需要找到一些新的亮點(新功能+通俗類比)
2014年5月7日,從宋沄劍宋大俠得知有一個為IT168和微軟撰寫SQL Server 2014新功能文章的機會,撰寫的內容為:SQL Server 2014的資源調控器(Resource Governor),這裡再次感謝宋大俠的推薦。
三.撰寫經歷(Experience)
- 接到任務的時候在忙公司的事情,簡單看了看這個功能在網上的介紹,大概瞭解下之後就繼續忙其它工作了;
- 過了幾天,感覺是時候動手撰寫這篇文章了,繼續查資料,簡單做了下構思,就動手搭了文章的基本框架;
- 框架搭建完,寫了部分的描述,這需要一個環境進行測試,馬上想到了在Azure建立一個帶有SQL Server 2014的虛擬機器,簡單的測試了Resource Governor的CPU控制功能;
- 繼續寫內容,突然有個靈感,我想把生活中的BRT引用到文中來,因為他們之間有著許多的共同點,而且可以作為開篇,讓讀者一下子就能在生活中找到共鳴;
- 努力找BRT的圖片當中;
- 看到MSDN上關於Resource Governor的架構圖,感覺有些不妥,於是就自己畫了一個新的,而且我也可以畫一個關於BRT的架構圖,把公路資源這種畫到圖裡面去,更加能通過BRT架構圖引出Resource Governor的架構圖;
- 對Resource Governor的IO進行了測試和場景的設計與分析;
- 繼續對文章的架構進行調整,組織語言,初稿出來了;
- 把文章發給宋沄劍,希望能得到一些建議,首先得到了他的肯定,同時他建議在開頭和結尾加入雲服務的概念,馬上動手,確定後,再發一次給他,他轉發給了IT168的編輯,在期待中煎熬度過;
- 過了幾天,想了想,為了避免編輯的修改建議,繼續對文章進行再一次的修改,無論從語言、結構、描述等等方面繼續完善,看得都感覺要吐了,再次轉發給宋沄劍了;
- 2014年5月27日,從宋沄劍那裡得知,文章一次性通過了IT168和微軟的稽核了,爽了;
- 2014年5月28日,文章在IT168的首頁釋出了;
四.特約稿正文(Content-body)
【IT168 專稿】在資料庫伺服器上,有三種硬體資源一直是影響資料庫效能好壞的關鍵,甚至會影響到整個生產系統的使用,這三種資源分別是記憶體、CPU和物理IO。當資料庫伺服器上掛載了多個數據庫的時候,極有可能發生資源的爭奪,如何能保證重要資料庫在擁有足夠資源的前提下再把多餘的資源提供給其它資料庫呢?資源調控器應運而生。
在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資源調控器,它與生活中的資源調控器有著驚人的相似之處。
SQL Server 2014的資源調控器預設包含了兩個工作負荷組(internal、default)和兩個資源池(internal、default),在沒有手動設定資源調控器的情況下,建立的資料庫會預設放到default資源池當中。
SQL Server資源調控器接收到會話請求後,通過使用者定義的分類器函式把會話進行劃分並路由到相應的工作負荷組,再通過工作負荷組找到對應的資源池,由資源池中設定的記憶體、CPU和物理IO資源的閥值來決定會話請求的資源分配。根據描述,可以得出如圖4所示的SQL Server資源調控器邏輯結構圖:
三、SQL Server資源調控器運用場景—CPU
理解了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%的。
四、SQL Server資源調控器運用場景—IO
前面講述關於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,專注於資料庫解決方案與效能調優。