2009-09-28 69 views
14

我最近使用進程外會話狀態對ASP.NET應用程序進行了一些性能測試和分析 - 在Web場中使用會話狀態時這是必需的,以便可以檢索狀態任何Web服務器,例如如果隨後的HTTP請求到達不同的服務器,因爲會話不「粘」或原始服務器宕機等等。糟糕的序列化性能的可能解決方案

令我驚訝的是,當我以滿負荷運行Web服務器並分析CPU使用率例如99%的CPU時間花在序列化和反序列化會話狀態上。隨後我們實現了一個定製的'緩存'狀態服務器;這總是序列化狀態,但也保持狀態在內存中,所以如果你使用粘性會話狀態不必大部分時間反序列化。這將服務器吞吐量提高了2倍;但是,序列化仍佔CPU時間的98%或更多。

我們通過在序列化之前「修剪」會話狀態中對象之間不必要的對象引用,進一步提高了速度 - 在序列化之後手動修復了引用。這又提高了10-20%左右的速度。這裏的推理是一些性能損失是由於內置的​​序列化不得不遍歷對象指針的圖形,這隨着更多指針而變成更復雜的任務。

繼續調查,我們爲我們的一些類編寫了定製的序列化例程,而不是依賴.Net的內置序列化。我們發現的性能是大大提高了,減少了約50x。看起來大部分的CPU負載是由內置的.Net序列化引起的,由於依賴於使用反射來遍歷對象指針/圖形和提取字段數據,反過來又很慢。

將網絡服務器的硬件要求降低一個很大的因素(功耗要求較低但仍然很重要),這非常有吸引力,可以將我們的性能提高50倍。目前的選項是:

1)編寫定製的序列化。由於任務的複雜性和它產生的維護開銷,這是一個問題,也就是說,對類狀態的任何改變都需要改變序列化/反序列化例程。

2)一些第三方解決方案。也許有些產品會在構建時自動生成狀態保存/加載代碼,從而無需使用Reflection。

我很想知道是否有人知道第三方解決方案,或者遇到過這個問題,因爲我從互聯網搜索中沒有發現任何提及。

更新: 有些人建議在默認的內置序列化和純定製序列化例程之間的一種中途解決方案。這個想法是,你可以爲最能影響性能的類實現自定義序列化,例如, Overiding ISerializable。這是一個有趣而有前途的方法;但是我仍然認爲有一個完全替代內置序列化的空間,而不必編寫和維護任何自定義代碼 - 這不能在運行時完成,因爲需要Reflection來查詢對象並訪問私有數據。但理論上可以對已經構建的程序集進行後處理,並將其作爲額外的構建步驟注入新的方法。一些分析器使用這種方法在C#編譯器構建完成後將分析代碼注入到程序集中。另外我/我想/我在某處閱讀.Net框架支持向類中注入方法 - 因此所有與IL有關的混亂都可能被處理。

+0

很確定你所說的注入方法是使用部分類。我認爲這個原則是,如果同一個名字空間中的兩個類具有相同的名稱並且一個名稱被標記爲部分。一個DLL是由兩個類的方法和屬性組合而成的。 – Robert 2010-01-26 08:38:44

回答

2

不幸的是,我只知道選項一和tbh,可能會開始非常痛苦的工作。

但它只做你想要的東西,所以它一樣快。

祝你好運。

+0

我接受這個答案是因爲我們發現所有其他解決方案至少比編寫自定義代碼慢10倍。 – redcalx 2010-01-25 23:39:18

1

另一種選擇是在服務器端回發中未觸及的所有控件上積極禁用ViewState。

+0

大部分的狀態都來自我們自己的類,但是會有內置標準ASP.NET控件的狀態,所以這絕對值得關注。謝謝。 – redcalx 2009-09-28 15:42:09

1

您可以通過執行ISerializable來部分定製您的序列化。如果你對最壞的犯罪者這樣做,你不會增加維護量,但仍然會獲得一些加速。

+0

我想補充一點,在我們最近的測試中,我們發現這並沒有提高性能。看起來,性能影響來自走過對象圖的代碼 - 實際的數據處理不是慢速的! – redcalx 2009-11-28 23:14:12

1

有一個第三方的解決方案:

西蒙休伊特的很好的開源庫,請參閱Optimizing Serialization in .NET - part 2

我是using it in my application,並得到了與您一樣的加速 ,20-40次。

它消除了導致減速的原因,但對於列表,它只支持一些本機類型。 因此,對於您自己的類型的Genreric.List,需要在其他類型的地方有明確的代碼 。例如。顯式循環或 更聰明的東西,可以自動執行此操作。在任何情況下,它都是非常簡單的,不應妨礙巨大的收益。

+0

謝謝,這裏有很多有趣的信息。乍一看,它似乎在使用內置(慢)和純定製序列化之間的中間位置。它揹負着內置的序列化,這也是其他答案中的一個。 – redcalx 2009-09-29 10:32:21

0

我們遇到過類似的問題,並設計了幾種提高性能的方法。我們在Persistore內存映射產品(目前爲測試版)中使用其中的一些。在我們的例子中,我們可以簡單地訪問持久數據「原位」,因爲它總是在內存映射堆中。

然而,一個「把戲」是定義會話狀態數據(如果可能)如marshalable類/結構和「連載」,使用.NET編組的支持,這可能是確實非常快,但不會處理'對象'圖。

我們還支持基於二進制序列化的特殊持久性,但我們還提取並保存了元數據,以便託管代碼可以在運行時在內存中設置/獲取持久數據中的字段,而無需反序列化整個對象,這很有用在某些情況下(例如證券和股票價格更新等)。我們最新的測試版支持通過網絡進行序列化,LINQ 匿名類型,這是我知道的第一個。無論如何,我們有興趣推出一些推測ASP.NET和網絡性能問題的新測試版客戶,我們的最新測試版非常令人印象深刻(但尚未準備好,直到nex周)。

如果有人很好奇,請聯繫我們獲取有關產品的最新信息。

休·莫蘭

PS:網站是過時的,產品遠遠超出了在那裏描述。