这是我第一次创建.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秒才能解析。但是,在负载下,它实际上比原来的更差。
我真正需要知道的是,我错误地做了什么,以至于在缩放时性能未能按预期进行改善!?!?!
任何帮助都将不胜感激。
答案 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设置为“在与客户端相同的进程内”运行。它是组件服务控制台中的设置之一。 速度至少快了千倍。