本文章是由機器翻譯。

預測:雲端

在 Windows Azure 中進行以效能為基礎的調整

Joseph Fultz

下載代碼示例

毫無疑問,雲計算受到了眾多關注,其實際應用正在成為各種技術平臺和整個業內的推動力。雲計算並非一個全新的或革命性的概念;實際上,它已經以共用託管和其他類似服務的形式存在了多年。而現如今,隨著技術的進步以及人們在伺服器和服務運行上積累的多年經驗,使得雲計算不單具有技術可行性,同時也使越來越多的消費者和提供商對其產生了興趣。

雲計算方面的發展將會超出 IT 行業的範疇,在公司中,從硬體和服務管理人員,到開發人員和架構師,乃至於負責審核預算和結算的高級管理人員,雲計算將無所不在。現在是時候進行準備了。

本期專欄主要面向那些需要在工作中瞭解和利用雲計算的開發人員和架構師。本文將針對如何完成特定任務提供一些指南,這包括有關架構的注意事項及其對成本和性能的影響。希望讀者能提供對於本文所涉及主題的回饋,更重要的是,告訴我您特別關注雲計算的哪些主題。

播雲

對於雲計算,人們最關注的優點之一是,應用程式所有者不必為基礎結構的安裝、配置或維護操心。實事求是的說,這的確吸引眼球。

但是我認為,更應當關注的是根據應用程式所有者的需求來擴大或縮小規模的能力,從而不以犧牲性能或浪費資源為代價來創造更高效的成本模型。根據我的經驗,不論所討論的平臺如何,所有關于雲計算的話題都會涉及到需求彈性問題。

在這一部分中,我將演示使用運行角色的效能計數器資料來實現特定 Web 角色實例數的自動增減過程的方法。為此,我將介紹 Windows Azure 功能中最具代表性的一部分,包括 Windows Azure Compute、Windows Azure Storage 和 REST 管理 API。

概念非常簡單:根據閾值測試收集到的性能資料,然後相應地增減實例數。本文不會詳細討論診斷資料的收集,請讀者自行瞭解或我將以後另外撰文。本文中,我將檢查轉儲到 Windows Azure Storage 的表中的效能計數器資料,以及執行 REST 調用以更改配置中的實例數所需的代碼和設置。此外,可供下載的代碼示例中將包含一個進行 REST 管理調用的簡單頁面,用於根據使用者輸入強制更改實例數。該方案類似于圖 1 所繪。

图 1 基于性能的缩放

專案設置

作為開始,我創建了包含一個工作者角色和一個 Web 角色的 Windows Azure 雲服務專案。將該 Web 角色配置為從其發佈效能計數器資料(特定為處理器時間百分比),並將資料每隔 20 秒推送到存儲。使用代碼在 WebRole::OnStart 方法內部實現這一操作,類似于以下所示:

var performanceConfiguration = 
  new PerformanceCounterConfiguration();
performanceConfiguration.CounterSpecifier = 
  @"\Processor(_Total)\% Processor Time";
performanceConfiguration.SampleRate = 
  System.TimeSpan.FromSeconds(1.0);
            
// Add the new performance counter to the configuration 
config.PerformanceCounters.DataSources.Add(
  performanceConfiguration);
config.PerformanceCounters.ScheduledTransferPeriod = 
  System.TimeSpan.FromSeconds(20.0);

此代碼註冊效能計數器,設置資料的收集時間間隔,然後將資料推送到存儲。此處所用時間間隔值很適合於本例,但並不代表我會在生產系統中使用相同的值。在生產系統中,收集時間間隔將會長許多,因為此時需要考慮的是全天候操作。另外,為減少針對 Windows Azure 存儲的交易處理數量,推送到存儲的時間間隔也應延長。

接下來,我將創建自簽章憑證,將其用於進行 Azure REST 管理 API 調用。每個請求都必須經過驗證,而證書則是完成驗證的方法。我按照 TechNet 庫的“在 IIS 7 中創建自簽名的伺服器憑證”(technet.microsoft.com/library/cc753127(WS.10))一文中創建自簽章憑證的說明操作。我匯出了一個 .cer 檔和一個 .pfx 檔。.cer 檔將用於對發送到管理 API 的請求籤名,.pfx 檔將通過管理介面導入到計算角色中(請參見圖 2)。

图 2 导入证书

稍後,我將回到此處並獲取指紋以將其置入所創建的 Web 角色和工作者角色的設置中,使得這些角色可以訪問憑證存放區和檢索證書。

最後,要將其在 Windows Azure 中投入使用,還需要一個計算專案,以便發佈兩個角色以及一個將性能資料傳輸到的存儲專案。準備好這些元素之後,可以進入正題了。

運行過忙還是過閑?

現在,我已經配置了 Web 角色並添加了代碼用於發佈效能計數器資料,下一步是提取該資料並將其與閾值進行比較。我將創建 TestPerfData 方法,該方法從表檢索資料並對值進行測試。我編寫了類似于下文的 LINQ 語句:

double AvgCPU = (
  from d in selectedData
  where d.CounterName == 
    @"\Processor(_Total)\% Processor Time"
  select d.CounterValue).Average();

通過比較平均利用率可以確定當前應用程式性能。如果實例運行過忙,則添加實例。如果運行過閑,則表明實例的運行不必要,浪費資源也就是浪費金錢,則可以減少實例數。

有關訪問效能計數器表資料所需代碼和設置的深入討論,可參見我寫的博客文章 blogs.msdn.com/b/joseph_fultz/archive/2010/06/30/querying-azure-perf-counter-data-with-linq.aspx。我使用了一個簡單的 if-then-else 塊來評估狀態並確定所需的操作。相關內容將在創建更改運行服務配置所需的函數之後詳細介紹。

使用 REST 管理 API

在完成 TestPerfData 方法之前,還有一些工作要做。此處需要一些方法來説明找到指定角色的實例數、為該角色創建一個帶有經過調整的實例數的新有效服務配置,並最終允許更新配置。

為此,我在專案中已添加一個類檔並創建了六個靜態方法,如圖 3 所示。

图 3 配置方法

方法 說明
GetDeploymentInfo 檢索部署配置,包括編碼服務配置。
GetServiceConfig 從部署資訊檢索和解碼服務配置。
GetInstanceCount 提取指定角色的實例數。
ChangeInstanceCount 更新服務配置並返回完整 XML。
ChangeConfigFile 使用提供給函數的服務配置更新服務配置。
LookupCertificate 將包含指紋的環境設置傳入並從憑證存放區檢索證書。

與 REST 管理 API 交互的調用必須包含證書。為此,將證書添加到託管服務中,並將指紋添加到角色配置,用於在運行時提取證書。正確配置服務和角色之後,我使用以下代碼從憑證存放區獲取證書:

string Thumbprint = 
  RoleEnvironment.GetConfigurationSettingValue(
  ThumbprintSettingName);
X509Store certificateStore = 
  new X509Store(StoreName.My, StoreLocation.LocalMachine);
certificateStore.Open(OpenFlags.ReadOnly);
X509Certificate2Collection certs = 
  certificateStore.Certificates.Find(
  X509FindType.FindByThumbprint, Thumbprint, false);

這是 LookUpCertificate 方法的主要代碼,在用來與 REST API 交互的方法中調用。 我將回顧 GetDeploymentInfo 函數作為如何構建調用的示例。 對於本例,我在其中硬編碼了一些訪問 REST API 時所需的變數:

string x_ms_version = "2009-10-01";
string SubscriptionID = "[your subscription ID]";
string ServiceName = "[your service name]";
string DeploymentSlot = "Production";

此處需要使用正確的 URI 創建 HttpWebRequest,設置請求標頭並將證書添加到其中。 這裡,我構建了 URI 字串並用它創建了新的 HttpWebRequest 物件:

string RequestUri = "https://management.core.windows.
net/" + 
  SubscriptionID + "/services/hostedservices/"+ 
  ServiceName + "/deploymentslots/" + DeploymentSlot;

HttpWebRequest RestRequest = 
  (HttpWebRequest)HttpWebRequest.Create(RequestUri);

為了使調用有效,必須在標頭中包括版本。 因此,我創建了名稱/值集合,添加了版本金鑰和資料,並將這些內容添加到請求標頭集合中:

NameValueCollection RequestHeaders = 
  new NameValueCollection();
RequestHeaders.Add("x-ms-version", x_ms_version);
if (RequestHeaders != null) {
  RestRequest.Headers.Add(RequestHeaders);
}

準備這個特殊的請求的最後一步是將證書添加到請求中:

X509Certificate cert = LookupCertificate("RESTMgmtCert");
RestRequest.ClientCertificates.Add(cert);

最後,執行請求並讀取回應:

RestResponse = RestRequest.GetResponse();
using (StreamReader RestResponseStream = new StreamReader(RestResponse.GetResponseStream(), true)) {
  ResponseBody = RestResponseStream.ReadToEnd();
  RestResponseStream.Close();
}

這是我在構建對 REST 管理 API 的請求時使用的通用模式。 GetServiceConfig 函數使用如下所示的 LINQ to XML 語句從部署配置中提取服務配置:

XElement DeploymentInfo = XElement.Parse(DeploymentInfoXML);
string EncodedServiceConfig = 
  (from element in DeploymentInfo.Elements()
where element.Name.LocalName.Trim().ToLower() == "configuration"
select (string) element.Value).Single();

在我的代碼中,GetServiceConfig 的返回結果傳遞到 GetInstanceCount 和/或 ChangeInstance 計數函數,以提取資訊或進行更新。 ChangeInstance 函數提供的返回結果是更新後的服務配置,該配置傳遞給 ChangeConfigFile。 接下來,通過構建與上一個請求(用於提取部署資訊)類似的請求,ChangeConfigFile 將更新推送到服務,但其中存在以下重要區別:

  1. 將“/?comp=config”添加到了 URI 的末尾
  2. 使用動詞 PUT 而非 GET
  3. 更新的配置作為請求正文進行傳送

綜合講述

準備好函數用於查找和更改服務配置,並做好其他準備工作(如設置計數器、配置存儲的連接字串設置以及安裝證書)之後,可以開始實施 CPU 閾值測試。

Visual Studio 範本生成每 10 秒喚醒一次的工作者角色以執行代碼。 為了簡化起見,我沒有這麼做,而是添加了每 5 分鐘運行一次的單獨計時器。 在計時器中,使用一條簡單的條件陳述式測試利用率高於還是低於 85%,我將創建兩個 Web 角色實例。 採用這種方法,可以確保實例數毫無疑問地會從初始的兩個減少為一個。

在工作者角色內部,有一個聲明和產生實體計時器的 Run 方法。 在計時器用時處理常式中添加了一個對之前創建的 TestPerfData 函數的調用。 對於本例,我跳過了 greater-than 條件的實施,因為已知 CPU 利用率不會如此高。 將 less-than 條件設置為低於 85%,因為我確信計數器平均值將低於這個數值。 通過設置這些精心準備的條件,我可以通過 Web 管理主控台或通過 Visual Studio 中的伺服器資源管理器查看變化。

在 less-than-85-percent 塊中,我檢查了實例計數,修改了服務配置並更新了運行服務配置,如圖 4 中所示。

圖 4 Less-Than-85-Percent 塊

else if (AvgCPU < 85.0) {
  Trace.TraceInformation("in the AvgCPU < 25 test.");
  string deploymentInfo = 
    AzureRESTMgmtHelper.GetDeploymentInfo();
  string svcconfig = 
    AzureRESTMgmtHelper.GetServiceConfig(deploymentInfo);
  int InstanceCount = 
    System.Convert.ToInt32(
    AzureRESTMgmtHelper.GetInstanceCount(
    svcconfig, "WebRole1"));
  if (InstanceCount > 1) {
    InstanceCount--;
    string UpdatedSvcConfig = 
      AzureRESTMgmtHelper.ChangeInstanceCount(
      svcconfig, "WebRole1", InstanceCount.ToString());
    AzureRESTMgmtHelper.ChangeConfigFile(UpdatedSvcConfig);
  }
}

我需要確保在調低實例計數值之前對其進行檢查,因為不希望該值為零,零不是有效配置,會導致故障。

運行示例

現在我已準備就緒,可以執行示例並演示 Windows Azure 中的彈性。我知道自己設計的代碼總能 一次成功,因此我直接按右鍵“雲服務專案”並按一下“發佈”。此對話方塊提供用於配置憑據的選項,這一步我已經完成(請參見圖 5)。

图 5 发布项目

按一下“確定”,此時只需等待套裝程式的複製和部署。部署完成後,我切換到 Web 管理主控台,看到有兩個 Web 角色和一個工作者角色在運行,如圖 6 中所示。

圖 6 兩個 Web 角色和一個工作者角色

我等待計時器事件的觸發,執行確定 CPU 平均利用率低於 85% 的代碼,然後遞減 WebRole1 實例數。出現此情況後,管理頁將刷新,以反映對部署的更新。

由於我使用的是小型 VM,只將計數值更改了一,並且應用程式是輕型的(一個 .aspx 頁面),更新無需多長時間,我將看到如圖 7 所示的最終自動收縮部署。

圖 7 現在只有一個 Web 角色和一個工作者角色

前瞻

關於示例,我希望在考慮實際實施的情況下分享一些最後的想法。有幾個要點需要注意。

首先,測試是簡單化且理想化的。在實際實施中,需要評估的內容遠不止簡單的 CPU 利用率,並且需要考慮進行收集的時間片。

此外,您需要評估使用 Windows Azure 存儲的成本。根據解決方案,理想方法是僅在表中清理感興趣的記錄。您可以減少上載時間間隔以降低交易處理成本,或者可以將資料移動到 SQL Azure 以使成本最低。

您還需要考慮在更新期間發生的情況。直接更新將導致使用者丟失連接。而將新實例在暫存中啟動,然後切換到虛擬 IP 位址會好一些。但是,在任何一種情況下,您將面臨會話和視圖狀態問題。更好的解決方案是進入無狀態並在規模調整時禁用測試。

以上就是我在 Windows Azure 中的彈性實施。請下載代碼示例並立即試用。

Joseph Fultz  是達拉斯 Microsoft 技術中心的架構師,協助企業客戶和 ISV 設計和製作軟體解決方案以滿足商業和市場需求。他在 Tech•Ed 及類似的內部培訓活動中做過講座。

*衷心感謝以下技術專家對本文的審閱:*Suraj Puri