.NET 2服务组件(COM +)效率问题

时间:2011-06-13 12:35:03

标签: c# asp.net .net-2.0 com+

这是我第一次创建.NET服务组件(COM +),而且在可扩展性方面我遇到了一些问题。我已经对最多4000个用户进行了压力测试,但它仍未能超过原始解决方案的性能。

它背后的基本思想是COM +在内存中包含一个包含字典的静态类,ASP页面调用该组件从字典中检索一个对象。在任何时候字典中都有6000到12000个项目。

静态字典类如下所示:

public class Menus
{
    public static Dictionary<string, MenuPage> MenuPages { get; set; }
}

暴露给COM +的ServicedComponent类如下所示:

public class MenuManager : ServicedComponent
{
    public MenuPage GetMenuPage(string PubCode, int Page)
    {
        MenuPage ReturnMenuPage;
        Menus.MenuPages.TryGetValue(String.Concat(PubCode, Page.ToString()), out ReturnMenuPage);
        return ReturnMenuPage;
    }
}

从这样的ASP页面调用COM +组件......

Dim MenuManager : Set MenuManager = Server.CreateObject("MenuManager.MenuManager")
Dim MenuPage : Set MenuPage = MenuManager.GetMenuPage(UCase(sBook), iPage)

If (Not MenuPage Is Nothing) Then
    //Retrieve values from class
Else
    Set MenuPage = Nothing
    Set MenuManager = Nothing
    Throw404()
End If

Set MenuPage = Nothing
Set MenuManager = Nothing

COM +作为本地服务运行,并在AssemblyInfo中设置以下选项:

[assembly: ApplicationActivation(ActivationOption.Server)]
[assembly: ApplicationAccessControl(false, AccessChecksLevel = AccessChecksLevelOption.ApplicationComponent)]

在单个测试实例下,当前解决方案需要0.03秒才能解析,新组件需要0.0003秒才能解析。但是,在负载下,它实际上比原来的更差。

我真正需要知道的是,我错误地做了什么,以至于在缩放时性能未能按预期进行改善!?!?!

任何帮助都将不胜感激。

4 个答案:

答案 0 :(得分:2)

问题

我认为您所看到的是使用服务器应用程序并返回.NET类的副产品。当您调用MenuManager时,您正在进行进程外调用以返回MenuPage对象。但是MenuPage 是通过引用返回的 - 对象位于服务器应用程序进程的内存中。要验证这是真的,请将一些代码放在MenuPage getter方法之一中:

System.Diagnostics.Trace.TraceInformation(
  System.Diagnostics.Process.GetCurrentProcess().Id.ToString()
);

您将看到进程ID是服务器应用程序的进程ID。

对于另一个测试地点,在返回MenuPage后休眠,然后在睡眠后检索MenuPage的属性。在睡眠完成之前,在COM + Explorer中手动关闭服务器应用程序。您将收到一条消息,指出远程服务器计算机不存在或不可用。

因此,对于每个页面,您将进行远程进程外调用以检索MenuPage以及您在MenuPage上调用的每个属性的另一个进程外调用。

改进

您是否出于安全目的使用服务器应用程序?如果没有,那么尝试转到库应用程序,以便调用不会在进程中。这可能有所帮助。

我还会将我的组件更改为不返回MenuPage,而是返回可以按值封送的基本类型(如果可能)(字符串,整数等)。

最后,我会使用JIT在方法返回后立即停用对象。由于您在服务器进程中停用,因此您无需从ASP页面调用Dispose。

我不确定你的MenuPage类看起来像什么,但代码看起来像:

[JustInTimeActivation(true)]
public class MenuManager : ServicedComponent
{
    public void GetMenuPageInfo(string PubCode, 
         int Page, 
         out string menuPageUrl, 
         out int menuCode)
    {
        ContextUtil.DeactivateOnReturn = true;

        menuPageUrl = null;
        menuCode = 0;

        MenuPage ReturnMenuPage;
        if (Menus.MenuPages.TryGetValue(
                String.Concat(PubCode, Page.ToString()), out ReturnMenuPage))
        {
            menuPageUrl = ReturnMenuPage.MenuPageUrl;
            menuCode = ReturnMenuPage.Code;
        }
    }
}

希望这会提高可扩展性。

查看Enterprise Services Design Considerations

  
      
  • 仅在您需要时使用企业服务。
  •   
  • 尽可能使用库应用程序。
  •   
  • 考虑DLL和类关系。
  •   
  • 仅在您需要时使用分布式事务。
  •   
  • 使用对象池来减少对象创建开销。
  •   
  • 根据调用模式设计池化对象。
  •   
  • 使用显式接口。
  •   
  • 设计不那么繁琐的界面。
  •   
  • 设计无状态组件。
  •   

Understanding Enterprise Services (COM+) in .NET是关于COM +的精彩文章。

答案 1 :(得分:0)

尝试使用以下属性标记您的COM +

[JustInTimeActivation]

[Transaction(TransactionOption.Disabled)]

我认为如果你禁用COM +事务调用COM +可以更快地工作。 此外,我可以建议您添加日志记录到服务器和客户端部分。在此之后,您可以分析COM +调用或Dictionary.TryGetValue

中性能较差的位置

答案 2 :(得分:0)

答案 3 :(得分:0)

根据我的经验,您应该将COM设置为“在与客户端相同的进程内”运行。它是组件服务控制台中的设置之一。 速度至少快了千倍。