背景
NanoProfiler是一個EF Learning Labs出品的免費性能監控類庫(即將開源)。它的思想和使用方式類似於MiniProfiler的。但是,設計理念有較大差異。
MiniProfiler更像是一個面向開發和測試環境的性能監控類庫,它的關注點(我說的不一定對,僅代表一家之言),更多的是提供了對微軟的ASP.NET MVC,EntityFramework,WCF等主流前后端類庫的封裝和整合,如果你的項目恰巧從前端到后端都用到這些類庫,它可以將從前端到后端的性能監控數據合並到一個視圖里,還是挺方便的。它的主要問題是:
- 運行時性能,尤其是並發環境下性能較差,占用的資源較多
- 不能很好的支持多線程和異步代碼的性能監控(事實上,MiniProfiler的核心類都不是線程安全的,只能通過粗暴的全局加鎖來實現部分的多線程和異步線程支持,性能也就可想而知了)
NanoProfiler項目的起源(大約半年前),最初,其實只是希望向MiniProfiler貢獻代碼,彌補以上的缺點,主要是內存數據結構的變化能夠帶來的性能的優化,和對多線程和異步編程模型的支持。不過,很可惜,在提交給他們我們關於如何改進的代碼示例,甚至是直接的Pull Request之后,后續的溝通中(不想背地里談他們團隊的技術水平),只能說,也許是他們的設計理念和關注點,並不在此吧。
所以,首先,上面提到的MiniProfiler的缺點,正是NanoProfiler的優點:
- NanoProfiler實現了對多線程代碼和異步代碼,包括基於PLINQ,Parallel庫在內的各種異步代碼的完美支持
- 性能方面,由於內部實現不需要像MiniProfiler那樣,對每個請求,在內存中維護一個樹形結構的數據結構,而用一個無鎖的隊列存儲每一步性能監控的原始數據,因此,性能上幾乎對被監控應用沒有影響
另一方面,相對於MiniProfiler僅僅滿足於實現一個用於開發環境的類似Fiddler的代碼性能視圖。NanoProfiler,首先,當然,也支持類似的功能,並且提供了更強大和直觀的查看性能數據的UI;同時,我們的設計理念,更偏向大數據和生產環境。說到底,我們認為,只對於開發環境的話,前端也好后端也好,我們有太多可替代的性能監控工具;將性能監控集成到代碼里,真正的優勢,應該是生產環境的大數據。所以,我們希望,不僅僅能監控單個請求的性能瓶頸,也能基於大數據,分析整個應用,應用和應用之間,服務器,甚至集群和集群之間的宏觀性能瓶頸。
舉例來說,如果說MiniProifiler的監控視圖對於一個頁面請求,就像是Fiddler對於一個頁面上所有資源和AJAX請求序列的性能描述;那么,NanoProfiler,除此之外,結合其他大數據分析工具,既能分析生產環境所有頁面產生的Fiddler請求數據,從而知道哪些資源的整體的訪問頻率和消耗最高,從而能夠找到應用,服務器,甚至集群上整體的性能瓶頸;還能,跨應用,跨服務器和集群,分析微觀(如單個請求,或單個用戶的相關請求)或者宏觀的各種性能指標。
安裝
http://nuget.org/packages?q=NanoProfiler
目前,已經上傳到nuget.orgd的至少有以下5個package:
- NanoProfiler - 核心庫,可單獨用於非Web應用,沒有DB性能監控支持
- NanoProfiler.Data - DB性能監控支持
- NanoProfiler.Web - Web項目支持
- NanoProfiler.Unity - 基於Unity IoC的AOP式監控擴展
- NanoProfiler.Wcf - WCF監控支持
如何使用?
對一個典型的Web項目,首先,我們需要在Global.asax.cs的BeginRequest和EndRequest事件處理,添加下面的代碼:
接下來,就可以在代碼里添加類似下面的代碼(類似MiniProfiler,不過MiniProfiler可不支持async),監控制定代碼塊的執行性能:
執行包含這段代碼的請求,然后訪問當前應用下的 ~/nanoprofiler/view 頁面, 應該能看到類似Fiddler視圖的,剛才訪問的請求的每一步的執行性能。
如果你想設置一些全局參數,比如,過濾某些請求,可以這樣:
DB性能監控
DB性能監控的使用方式和MiniProfiler也比較類似,簡單地說,只需要用NanoProfiler提供的ProfiledConnection或者ProfiledDbCommand這樣的類,包裝原有的DbConnection和DbCommand對象。例如,假設你有下面這樣一個DataService:
我們只需要,用ProfiledDbConnection包裝,這個SqlConnection實例:
查看實時性能監控數據
前面說過,默認情況下,訪問~/nanoprofiler/view 就能查看最近的請求的性能監控數據。下面是某個請求的性能視圖示例,紅色是DB請求,綠色是WCF請求,藍色是其他代碼步驟:
如果顯示有問題,比如報treeview-timeline.css 404錯誤,請確保Web.config包含runAllManagedModulesForAllRequests="true":
<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
</modules>
</system.webServer>
如果,想做一些參數定制,可以在application_start事件處理里,通過下面的代碼設置:
ProfilingSession.ProfilingStorage = new CircularBufferedProfilingStorage(100, profiler => false, new JsonProfilingStorage());
默認的查看監控數據的功能是基於CircularBufferedProfilingStorage實現的,它有三個可選參數:
- 第一個參數代表,最多在內存保留多少個最近的請求的監控數據
- 第二個參數是一個Func<IProfiler, bool> delegate,可以指定一個方法,過濾不想顯示的監控結果,比如,只保留請求處理時間大於100ms的數據
- 第三個參數指定一個真正持久化監控數據的provider,比如,默認的JsonProfilingStorage將監控數據,通過任意支持slf4net的類庫(比如log4net),持久化到文件系統或者DB
WCF監控
WCF性能監控主要通過WcfProfilingBehavior這個類,他是一個標准的WCF EndpointBehavior實現,只要通過代碼或者XML配置,將它配到指定的service就行,比如,是一個XML配置的示例:
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IWcfDemoService" />
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:64511/WcfDemoService.svc"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IWcfDemoService"
contract="DemoService.IWcfDemoService" name="BasicHttpBinding_IWcfDemoService" />
</client>
<behaviors>
<serviceBehaviors>
<behavior name="">
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior>
<tinyprofiler />
</behavior>
</endpointBehaviors>
</behaviors>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"
multipleSiteBindingsEnabled="true" />
<extensions>
<behaviorExtensions>
<add name="tinyprofiler" type="EF.Diagnostics.Profiling.ServiceModel.Configuration.WcfProfilingBehaviorElement, NanoProfiler.Wcf"/>
</behaviorExtensions>
</extensions>
</system.serviceModel>
基於Unity AOP的性能監控
Unity擴展,主要提供兩種基於Unity AOP的支持。
第一種,通過ContainerExtension。例如:
上面的代碼,將自動監控所有注冊到Unity容器的接口名稱帶DemoDBService的service的每個方法調用的性能。
第二種,通過Unity的policy injection。簡單地說,可以通過Attribute標注的方式,自動監控方法的執行性能:
要開啟,Unity的policy injection支持,需要在Global.asax.cs,添加下面這樣的初始化代碼:
NanoProfiler的基本功能先講到這兒,下期預告:NanoProfiler - 適合生產環境的性能監控類庫 之 大數據篇
BTW, 發句牢騷,博客園這個Markdown解析器太爛,對於插入代碼翻譯成的HTML很糟糕,所以只能全都插圖片了。