Windows Azure一些小技巧集合


我最近做了一個Windows Azure上面的項目,自己在做的過程中遇到了很多問題。有的是我自己摸索解決,有的是到網上尋找零碎的信息結合起來解決的。我感覺應當把某些解決方法集中一下,方便我以后查閱,也方便其他人。本文涉及的內容主要是Azure的Cloud Service服務。

 

在Windows Azure中啟用Trace

部署到Windows Azure上的代碼是不能夠用Visual Studio直接調試的,所以保留完善的Trace來診斷問題非常重要。用Windows Azure SDK 2.0建立的項目已經為雲端Trace做好了准備,但並沒有真正啟用。現在我們來看怎么完善最后的工作。

 

Windows Azure Cloud Service項目的Trace是在主項目上集中配置的。打開主項目的Roles文件夾可以看到每個Role的cscfg文件。我們雙擊其中一個打開,默認是這樣的:

Configuration

注意下面的Diagnostics段,勾選的話就打開了Trace。但是默認情況下,Trace使用的Storage Account是“DevelopmentStorage”其實就是本地的Azure模擬器。我們只要為其指定一個真正的Azure Storage Account就可以了。建議專門為Trace建立一個Storage Account,而不要使用其他數據的Account。如圖即可選擇一個Storage Account。

StorageAccount

 

在代碼中,直接使用System.Diagnostics.Trace類的相應的方法,例如WriteLine或者TraceError等即可將Trace寫入指定Storage Account的表格中。因為Azure的存儲是收費的,所以分級使用Trace很重要,推薦使用TraceInformation,TraceError這樣自帶錯誤等級的方法。某些使用Windows Azure SDK老版本或者從其他項目移植為Azure項目時,App.config或者Web.config中可能缺少Trace Listener的設置,這樣也無法在運行時正確寫入Trace。我們可以打開WebRole或者WorkerRole項目自己的.config,確認有這樣一段在configuration段之內:

 

 
  <system.diagnostics>
    <trace>
      <listeners>
        <add type="Microsoft.WindowsAzure.Diagnostics.DiagnosticMonitorTraceListener, Microsoft.WindowsAzure.Diagnostics, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" name="AzureDiagnostics">
          <filter type="" />
        </add>
      </listeners>
    </trace>
  </system.diagnostics>
 

 

WebRole/WorkerRole項目引用的DLL等類庫工程直接使用System.Diagnostics.Trace類即可,無需進行配置。

 

除了使用Trace類之外,Windows Event Log也很重要,因為諸如雲服務運行時異常,崩潰之類的信息是在Windows Event Log當中的。我們可以在前面的Cloud Service主項目的配置頁,單擊Edit按鈕來進行篩選。如果需要諸如性能計數器等額外信息,也可以在此選擇:

image

 

最后是Trace的查看方法。經過以上配置,System.Diagnostics.Trace記錄下來的Trace會保存到設定Storage Account的WADLogsTable表格中;Windows Event Logs記錄到WADWindowsEventLogsTable表格中。在Azure的管理門戶網站上是看不到表格存儲的,需要用代碼來讀取其中的內容。當然,我們也可以用一些現成的第三方工具,比如我用的是這個Azure Storage Explorer

storageExplorer

 

如此一來,從啟用Trace,代碼中記錄Trace到查看Trace的全套流程就都實現了。

 

在WebRole和WorkerRole的VM上安裝Windows Server的功能

我們都知道Azure Cloud Service的WebRole和WorkerRole都是在各自的VM里面執行的,其VM的操作系統以及版本都可以在部署的時候進行指定。例如我們可以選擇Windows Server 2012等系統。但是默認情況下大部分Windows Server的功能都是沒有啟用的。一台本地的服務器我們可以用Windows Server管理工具來安裝新功能/角色,那么在Cloud Service下面怎么安裝呢?答案是使用PowerShell。

 

首先我們需要確定所需功能的名稱。在Windows Server本地的PowserShell中執行Get-WindowsFeature命令。如果沒有本地的Windows Server,可以登錄到Azure的雲服務VM上,或者創建一台單獨的VM,在里面執行。你將會看到如下的功能列表:

image

 

第一列是模擬在GUI模式下看到的樹狀的功能列表,而第二列就是在PowerShell中安裝它所需的名稱。記住這個名稱。下面我們要在Cloud Service虛擬機部署的時候利用部署任務來安裝Windows Feature。在需要該Windows功能的WebRole或者WorkerRole項目中添加一個擴展名是ps1的文件,並且選擇總是拷貝到Output文件夾。

image

 

在ps1中輸入如下代碼。我的例子是安裝了一個Media Foundation功能。注意,安裝該功能是否需要重啟應當提前確定清楚。需要重啟的功能安裝命令后面加-Restart。如果不加的話部署時會卡在那里。


Import-Module Servermanager 
$mf = Get-WindowsFeature "Server-Media-Foundation" 
if (!$mf.Installed) { 
  Add-WindowsFeature -name "Server-Media-Foundation" -Restart 
}
 

 

注意,保存這個文件的時候我們一定要選擇VS文件菜單中的“Save with advanced options”選項,然后按照UTF-8 without signature這個編碼來保存。因為UTF-8的三字節特征字符是PowerShell所不支持的。切記這一步操作!

image

 

接下來再給該項目新加一個bat文件。這個文件當中我們調用PowerShell來執行上述部署命令:


if "%EMULATED%"=="true" goto :EOF
powershell -command "Set-ExecutionPolicy Unrestricted" 2>> error.out
powershell .\installfeatures.ps1 2>> error.out
 

 

第一句首先我們將PowerShell的執行策略改為Unrestricted,因為它默認是Restricted,不能進行Windows功能安裝等任務。我們將這個文件保存為startuptask.bat,同樣要利用高級保存選項將它保存為UTF-8 without signature編碼,而且別忘了選中總是拷貝到Output文件夾。

 

最后一步我們要到Cloud Service主項目的ServiceDefinition.csdef文件中添加執行bat文件的任務。先找到這個文件:

ServiceDefinition

在剛才添加過ps1和bat文件所對應的WebRole或者WorkerRole的配置段中,添加這樣的代碼:


<Startup>
  <Task commandLine="startuptask.bat" executionContext="elevated" taskType="simple">
    <Environment>
      <Variable name="EMULATED">
        <RoleInstanceValue xpath="/RoleEnvironment/Deployment/@emulated"/>
      </Variable>
    </Environment>
  </Task>
</Startup>
 

 

其中我們建立的EMULATED環境變量就是之前bat文件中引用的。利用這個環境變量就可以防止本地調試Azure的時候執行上述ps1腳本。如此一來,只要部署Cloud Service項目,其VM上就會自動安裝上Media Foundation功能。其他經由PowerShell可以實現的VM管理任務也可以照此方法容易地實現。

 

Windows Azure Storage Service使用心得

接下來是一些關於Storage Service的使用心得集合,如果錯誤歡迎指出。

 

調整並發連接數限制

剛建立好的Cloud Service WorkerRole的OnStart()方法中我們能看到這樣一行代碼

ServicePointManager.DefaultConnectionLimit = 12;
建議大家把這個限制改成100甚至更高。因為Azure的存儲服務訪問都要經過網絡訪問,瓶頸出現在連接數限制上是很常見的問題。要注意的是,Azure Storage Service也不能過度並發訪問。如果連接數過高也會返回服務端錯誤。明智的做法是適當進行分組,然后並發地對BlockBlob的各個Block進行訪問;或者並發地對多個Blob進行訪問。我在實踐中選擇的分組大小是10個Block一組,我並沒有測試它是否是最好的分組大小,有興趣的人可以親自去試一下。

 

使用BufferedStream訪問Blob

Windows Azure SDK的Blob對象有一個屬性,叫StreamMinimumReadSizeInBytes。它的默認值是4MB。別被它騙了,實際上Blob的OpenRead和OpenWrite打開的流,如果進行尺寸很小的頻繁讀寫,性能還是非常差的。實際上OpenRead和OpenWrite打開的流比較適合上載和下載整段的數據。當你需要按照訪問本地文件那樣的邏輯訪問Blob的時候,一定要給他套上一個System.IO.BufferedStream。而且記得手工把Buffer的大小改成4MB(默認是4K,對Azure的Blob來說毫無作用)。

 

關於表格存儲中的DateTime類型

我在一個表格存儲所對應的Entity類中使用了DateTime類型的屬性,結果發現插入操作總是失敗。經過我的尋找,發現DateTime類型的屬性不初始化就直接進行插入或者更新操作的話是不行的。因為Azure Table Storage中的時間日期格式與.net的日期格式范圍不同。Azure的日期只能表示從公元1601年開始,而.net的日期不初始化的話是從0001年開始的。這樣一旦提交就是一個非法日期了。那么,如果我真的有必要表示一個日期是未初始化的應該怎么做呢?只要將該字段聲明成DateTime?類型即可(Nullable<DateTime>)。

 

采用Task風格的async/await來訪問Azure Storage Service

Azure storage service的訪問全部都通過網絡來進行,所以充分利用異步操作可以很好地節約本地的線程資源,提高響應性。但是當前的Windows Azure SDK 2.0里面並未提供C#5/VB11的async/await語法能夠訪問的Task風格異步API,而是傳統的Begin/End風格。據說在下一個版本的SDK當中會全面提供Task風格的異步API,在此之前我們只好繞路一下。做法就是利用Task.Factory對象的FromAsync方法。比如說我們希望異步地調用CloudBlockBlob的Delete方法,可以這樣寫:

await Task.Factory.FromAsync(
    blob.BeginDelete(null, null),
    blob.EndDelete);
 

這個方法能夠處理各種有返回值或者沒有返回值的Begin/End系列異步方法。有返回值時需要手動傳入返回值的類型作為泛型參數:

var stream = await Task.Factory.FromAsync<Stream>(
    blob.BeginOpenWrite(null, null),
    blob.EndOpenWrite);

 

以上就是我對Windows Azure開發總結出的一些粗淺的小技巧,希望能夠對大家有所幫助。如果建議或者討論,歡迎到新浪微博上關注 @裝配腦袋


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM