使用IronPython檢測ASP.NET程序狀況(上)

作者: Jeffrey Zhao  來源: 博客園  發布時間: 2009-03-23 14:17  閱讀: 981 次  推薦: 0   原文鏈接   [收藏]  

  在ASP.NET應用程序運行過程中,很可能會遇到各種意料之外的問題。如果在開發環境下,我們可以設置斷點,對程序狀態一探究竟。但是很顯然,在產品環境中我們幾乎無法使用這樣的狀態。也正因為如此,Dump一個內存快照并進行分析才成為一種“高級技術”,同時在線調試也成為一種需要結合技術能力、分析能力,甚至抗壓能力的工作。對于調試和解決問題的探索永遠不會停止,各成熟的技術團隊幾乎都會有一個豐富工具箱,用于應付生產環境中的各種狀況。

  在維護一些生產環境中的ASP.NET應用程序時,老趙也經常會感到“力不從心”。雖然我們可以建立豐富有效的監控或日志等維護機制,但是調試和分析一次程序經常需要耗費大量的腦細胞。因為我們可以使用的工具大都非常抽象,即使是一個非常微小的問題,也要用較多的時間才能發現“哦,原來是這個變量的值進入了一種奇怪的狀態”。如果我們有一種機制,可以直觀地檢查生產環境中正在運行的程序的狀態,那么一定可以大大方便我們的工作。

  這篇文章記錄的便是老趙的一次探索。

  我們的目的是“在程序運行過程中記錄狀態”。使用ASP.NET的傳統機制,例如HttpModule,Trace,往往需要修改配置和部署新的程序集,這樣一不小心便會造成應用程序的重啟。對于訪問量數據量到了一定規模的時候,冷啟動的消耗也是相當可觀的,不斷地冷啟動會對應用程序造成非常大的影響。可能我們希望的,只是能夠簡單地(在不影響現有系統的情況下)執行一段代碼,并輸出一些內容。要實現這點其實并不難,例如最直接的做法便是提交一段代碼,保存成文件,調用CSC將其編譯成dll,然后在程序中進行加載。這已經不是一種新鮮的技巧了,它已經用在很多地方,得到了一些不錯的效果。

  但是,老趙在這里還是想使用IronPython,一個原因是老趙最近也在嘗試合理地混用各種語言(F#, IronPython, IronRuby, etc.)編寫應用程序以提高生產力,便“順便”地用上了IronPython的現有成果。IronPython已經內置了Python代碼的執行引擎,并且能與.NET程序無縫集成。此外,社區中也已經接受了如Crack.NET等基于IronPython的調試工具1,表明IronPython已經足夠成熟,可以放心使用。關于更多IronPython的信息,可以參考在QCon London 20092中,《IronPython in Action》一書的作者Michael Foord的演講“Real World IronPython”。

  在這里,我們先準備一個簡單的aspx頁面,其中有兩個文本框,以及一個按鈕:

<asp:TextBox ID="txtCode" runat="server" Height="320px" TextMode="MultiLine" 
    Width="640px">asp:TextBox>
<br />
<asp:Button ID="btnExecute" runat="server" onclick="btnExecute_Click" 
    Text="Execute" />
<br />
<asp:TextBox ID="txtOutput" runat="server" Height="320px" TextMode="MultiLine"
    Width="640px">asp:TextBox>

 

  這里,我們希望在點擊按鈕之后,可以執行txtCode中的IronPython代碼,并且將信息顯示在txtOutput中:

protected void btnExecute_Click(object sender, EventArgs e)
{
    ScriptEngine engine = Python.CreateEngine();
    var scope = engine.CreateScope();
    var script = engine.CreateScriptSourceFromString(
        this.txtCode.Text, SourceCodeKind.Statements);
    script.Execute(scope);

    TextWriter writer = new StringWriter();
    scope.SetVariable("logger", writer);

    Action<HttpContext> trace;
    if (scope.TryGetVariable<Action<HttpContext>>("trace", out trace))
    {
        trace(this.Context);
    }

    this.txtOutput.Text = writer.ToString();
}

 

  如果您要使用上面的代碼,則需要引用IronPython、Microsoft.Scripting及Microsoft.Scripting.Core三個程序集。您可能沒有接觸過這部分內容,但是應該也能夠輕易理解上述代碼的含義:

  1. 創建一個ScriptEngine對象,并得到一個ScriptScope。
  2. 將txtCode文本框內的代碼,作為Statements編譯為ScriptSource對象。
  3. 創建一個StringWriter對象,并賦給ScriptScope中的logger變量。
  4. 執行ScriptSource,并從中獲取trace方法成為一個委托。
  5. 將當前HttpContext傳入trace方法執行,并輸出內容。

  于是我們準備一段IronPython代碼,它的作用是輸出當前請求的UserAgent,如下圖:

  只是這么一個簡單的功能,我們便可以做很多事情,例如使用反射改變某個對象的狀態,甚至調用系統中某個方法進行復雜的工作。不過在實際使用時我們可能還需要額外的注意:由于我們基于單個“請求”,因此只能有一臺機器得以動態執行IronPython代碼。如果在產品環境中只有一臺機器,那么自當無事,否則我們就可能需要某種手段來確保我們的代碼是在哪臺服務器上執行的。例如,對于DNS輪詢方式的附載均衡策略,您只需修改本機DNS即可,否則您可能就需要根據您的NLB策略進行其它一些配置。更進一步,如果您需要代碼在所有機器上執行,可能就需要編寫一個遠程調用平臺,可以將代碼發送到所有機器上執行,并將結果進行聚合。

  在下一篇文章中,我們將使用類似的做法,對系統中的請求進行采樣,以獲取更加豐富的數據——那是一件更有意思的事情.

 

注1:Crack.NET是用于分析WinForm和WPF應用程序狀態的工具,可能是由于CLR托管方式的不同,它無法用于ASP.NET或SQL Server等托管程序上。

注2:(廣告時間)QCon北京是中國舉辦的第一次QCon大會,業界各頂尖專家齊聚一堂,如果哪位朋友或所在公司感興趣,請和老趙聯系。

 

0
0
 
標簽:IronPython
 
 

文章列表

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()