Проблема эффективности обслуживаемого компонента .NET 2 (COM +) - PullRequest
1 голос
/ 13 июня 2011

Впервые я создаю обслуживаемый компонент .NET (COM +), и у меня возникают некоторые проблемы, связанные с масштабируемостью. Я протестировал его до 4000 пользователей, но он все еще не может превзойти производительность исходного решения.

Основная идея заключается в том, что COM + содержит статический класс, содержащий словарь в памяти, а ASP-страница вызывает компонент для извлечения объекта из словаря. В словаре одновременно может содержаться от 6000 до 12000 наименований.

Класс статического словаря выглядит следующим образом:

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

Класс ServicedComponent, доступный для COM +, выглядит следующим образом:

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;
    }
}

И компонент COM + вызывается со страницы ASP, например, так ...

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 ]

2 голосов
/ 15 июня 2011

Issue

Я думаю, что вы видите, это побочный продукт использования серверного приложения и возврата класса .NET.Когда вы вызываете MenuManager, вы делаете вызов вне процесса для возврата объекта MenuPage.Однако MenuPage - это , возвращаемое ссылкой - объект находится в памяти внутри процесса приложения вашего сервера.Чтобы убедиться, что это действительно так, поместите некоторый код в один из методов получения MenuPage:

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

Вы увидите, что идентификатор процесса - это идентификатор процесса вашего серверного приложения.

Для другого теста поместите сон после возврата MenuPage, а затем после сна получите свойство MenuPage.Перед завершением сна вручную отключите серверное приложение в COM + Explorer.Вы получите сообщение о том, что удаленный сервер не существует или недоступен.

Таким образом, для каждой страницы вы будете выполнять удаленный вызов вне процесса, чтобы получить MenuPage плюс еще один вызов вне процесса.за каждое свойство, которое вы вызываете на MenuPage.

Улучшения

Используете ли вы Серверное приложение в целях безопасности?Если нет, то попробуйте перейти в приложение библиотеки, чтобы вызовы не были вне процесса.Это могло бы помочь.

Я бы также изменил свой компонент, чтобы он не возвращал MenuPage, а вместо этого возвращал примитивные типы (если это возможно), которые можно маршалировать по значению (string, int и т.Наконец, я бы использовал JIT для деактивации объекта сразу после возврата метода.Поскольку вы деактивируете процесс сервера, вам не нужно вызывать Dispose на странице ASP.

Я не уверен, как выглядит ваш класс 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, только если вам нужно.
  • Используйте библиотечные приложения, если это возможно.
  • Рассмотрите DLL и классовые отношения.
  • Используйте распределенные транзакции, только если вам нужно.
  • Использование пула объектов для сокращения накладных расходов на создание объектов.
  • Проектирование объединенных объектов на основе шаблонов вызовов.
  • Использование явных интерфейсов.
  • Разработка менее чутких интерфейсов.
  • Разработка компонентов без сохранения состояния.

Общие сведения о службах предприятия (COM +) в .NET - отличная статья о COM +.

0 голосов
/ 19 февраля 2013

По моему опыту, вы должны настроить COM для запуска "в том же процессе, что и клиент"это один из параметров в консоли обслуживания компонентов.Скорость как минимум в тысячу раз быстрее.

0 голосов
0 голосов
/ 13 июня 2011

Попробуйте пометить свой COM + следующими атрибутами

[JustInTimeActivation]

и

[Transaction(TransactionOption.Disabled)]

Думаю, если отключить транзакцию COM +, вызов COM + может работать быстрее. Также я могу предложить вам добавить запись в серверную и клиентскую части. После этого вы можете проанализировать, где худшая производительность в вызовах COM + или Dictionary.TryGetValue

...