Сообщений 10    Оценка 245        Оценить  
Система Orphus

Кто сегодня самый удалённый :o)

DCOM vs. .NET Remoting

Автор: Игорь Ткачёв
The RSDN Group

Источник: RSDN Magazine #2
Опубликовано: 15.03.2003
Исправлено: 13.03.2005
Версия текста: 1.0.1
Как и что мы тестировали
DCOM
.NET Remoting
TCP + Binary, HTTP + SOAP
IIS
Итого

Исходные тексты

Так что же всё-таки лучше? Сомнительное новое или ещё не совсем забытое, проверенное временем, отлаженное и надёжное старое? Хорошее или его неизменный враг – лучшее? Баталиям на эту тему, похоже, нет и никогда не будет ни начала, ни конца. Иногда они будут на время затихать, затем возобновляться с новой силой, но, по всей видимости, этот процесс будет продолжаться вечно. 10-12 лет назад скептики утверждали, что мэйнфреймы будут доминировать по жизни, а IBM PC есть жалкая пародия на компьютер, и MS DOS даже не имеет права называться операционной системой, пусть даже дисковой. 6-7 лет назад они говорили, что Windows – это всего лишь жалкая, прожорливая и никому не нужная графическая оболочка, и DOS будет рулить всегда, особенно если к ней прикрутить многозадачность. Сегодня...

Впрочем, сегодня мы не будем делать однозначных выводов – что лучше, а что хуже, сегодня мы рассмотрим и сравним две родственные технологии для построения распределённых систем – DCOM и её преемницу .NET Remoting. В первую очередь нас будут интересовать скорость вызова методов и время создания (соединения) удалённого объекта.

Как и что мы тестировали

Тестирование производилось на следующем оборудовании.

Сервер: Compaq ProLiant ML370, 2 x Intel PIII, 1.1 GHz, 1.2 GB RAM.

Клиент: IBM NetVista, Intel PIII, 1 GHz, 512 MB RAM.

В качестве подопытных мы взяли следующие объекты, написанные на ATL VC++ 7.0 и на C#.

ATL VC++ 7.0:

__interface ICOMObject : IDispatch
{
  [id(1)] HRESULT Method1(void);
  [id(2)] HRESULT Method2([in] LONG p, [out,retval] LONG* ret);
  [id(3)] HRESULT Method3([in] BSTR p, [out,retval] BSTR* ret);
  [id(4)] HRESULT Method4([in] VARIANT p, [out,retval] VARIANT* ret);
  [id(5)] HRESULT Method5([in] VARIANT p, [out,retval] VARIANT* ret);
};

class ATL_NO_VTABLE CCOMObject: public ICOMObject
{
public:
  STDMETHODIMP Method1()
  {
    return S_OK;
  }
  STDMETHODIMP Method2(LONG p,LONG* ret)
  {
    *ret = p;
    return S_OK;
  }
  STDMETHODIMP Method3(BSTR p,BSTR* ret)
  {
    return CComBSTR(p).CopyTo(ret);
  }
  STDMETHODIMP Method4(VARIANT p,VARIANT* ret)
  {
    CComSafeArray<LONG> sa(p.parray);
    return CComVariant(sa).Detach(ret);
  }
  STDMETHODIMP Method5(VARIANT p,VARIANT* ret)
  {
    CComSafeArray<BSTR> sa(p.parray);
    return CComVariant(sa).Detach(ret);
  }
};

C#:

using System;
using System.Runtime.Remoting.Messaging;

namespace RSDN
{
  public class Test: MarshalByRefObject
  {
    public void Method1()
    {
    }
    public int Method2(int p)
    {
      return p;
    }
    public string Method3(string p)
    {
      return p;
    }
    public int[] Method4(int[] p)
    {
      int [] ar = new int[p.Length];
      p.CopyTo(ar,0);
      return ar;
    }
    public string[] Method5(string[] p)
    {
      string [] ar = new string[p.Length];
      p.CopyTo(ar,0);
      return ar;
    }
  }
}
ПРИМЕЧАНИЕ

Заметьте, текст C# объекта приведён практически полностью, в то время, как его ATL-собрата – в сильно урезанном варианте.

Итого, мы имеем:

  1. Method1 без параметров и без возвращаемого значения.
  2. Method2, принимающий и возвращающий целое число.
  3. Method3, принимающий и возвращающий строку длиной 10 символов.
  4. Method4, принимающий массив из 100 целых чисел и возвращающий его же в случае .NET Remoting и новую копию для DCOM.
  5. Method5, то же, что и Method4, только в данном случае передаётся и принимается массив из 100 строк по 10 символов каждая.

Серверные объекты тестировались в двух режимах. Мы условно назвали их ‘call’ и ‘connect’. Под моделью ‘call’ мы будем понимать следующий алгоритм тестирования:

void Method1Call ()
{
    Test o = new Test();
    for (int i=0; i<1000; i++)
    {
        o.Method1();
    }
}

Т.е. мы создаём объект и вызываем один из его методов определённое количество раз, замеряя тем самым накладные расходы на каждый вызов.

Для варианта ‘connect’, объект создаётся при каждом вызове метода. Таким образом, мы можем замерить время создания и соединения с объектом.

void Method1Connect()
{
    for (int i=0; i<1000; i++)
    {
        Test o = new Test();
        o.Method1();
    }
}

Каждый подобный метод вызывается клиентом одновременно из 10 потоков, т.е. в общем случае каждый метод вызывается 10,000 раз. Засекается время от начала активизации первого потока и до тех пор, пока не отработают все десять.

К сожалению, тестирование в локальной сети даёт различные результаты для различных прогонов. Часто результаты одних и тех же тестов различаются в несколько раз. В связи с этим тест прогонялся многократно, после чего выбирался наилучший результат для каждого случая. Тем не менее, на небольшие отклонения всё же лучше не обращать внимания – для такого числа вызовов разница в 10 секунд равна всего лишь одной миллисекунде на вызов.

DCOM

Тест DCOM включает следующие 4 вида объектов:

На рисунке 1 приведены результаты для ‘call’ модели.


Рисунок 1. DCOM ‘call’.


Рисунок 2. DCOM ‘connect’.

Рисунок 2 демонстрирует результаты теста для варианта ‘connect’. Здесь мы тоже видим практически полную идентичность результатов. В дальнейших тестах мы будем использовать их для сравнения с результатами тестирования .NET Remoting.

.NET Remoting

Технология Remoting в .NET Framework, с одной стороны, намного проще, чем COM, с другой – гораздо гибче и многограннее.

Мы можем использовать различные протоколы передачи данных. Сейчас доступны TCP и HTTP, на подходе Pipe и SMTP. Если же нам не нравится ни один из данных протоколов, мы можем написать свой собственный.

Мы можем использовать разные форматеры для упаковки передаваемых данных. Microsoft реализовала SOAP-форматер и свой собственный бинарный. Если они нам не подходят, это тоже поправимо.

Число моделей удалённых объектов также расширено. Сейчас в нашем распоряжении имеются следующие:

Последний вариант мы тестировать не стали.

Мы добавим к нашим тестам ещё и XML Web Services, которые хотя и похожи на Singlecall-объекты, для которых используется протокол HTTP + SOAP-форматер, но всё же имеют иную природу.

TCP + Binary, HTTP + SOAP

В качестве хост-сервера для наших объектов может выступать любое .NET-приложение или Internet Information Server. В первом случае мы можем использовать все доступные протоколы и форматеры в любых возможных комбинациях. С IIS можно использовать только протокол HTTP, использование форматеров не ограничено.

Первыми мы представим результаты тестирования, где в качестве сервера выступает обычное приложение .NET, исходный код которого приведён ниже:

using System;
using System.Runtime.Remoting;

namespace NETServer
{
  class Server
  {
    [STAThread]
    static void Main(string[] args)
    {
      RemotingConfiguration.Configure("NETServer.exe.config");
      Console.WriteLine("Press Enter to exit");
      Console.ReadLine();
    }
  }
}

Весьма лаконично, не правда ли? На самом деле вся работа делается внутри метода RemotingConfiguration.Configure, который и занимается всей инициализацией и настройкой. Для этого мы ему передаём конфигурационный файл примерно следующего содержания:

<configuration>
  <system.runtime.remoting>
    <application name="RemotingTest">
      <service>
        <wellknown 
          mode="Singleton"
          type="RemoteObject.SingletonTest, RemoteObject"
          objectUri="SingletonTest.rem" />
        <wellknown
          mode="SingleCall"
          type="RemoteObject.SingleCallTest, RemoteObject"
          objectUri="SingleCallTest.rem" />
        <activated
          type="RemoteObject.ClientTest, RemoteObject" />
      </service>
      <channels>
        <channel ref="tcp" port="8008">
          <serverProviders>
            <formatter ref="binary" />
          </serverProviders>
          <serverProviders>
            <formatter ref="soap" />
          </serverProviders>
        </channel>
        <channel ref="http" port="8009"/>
      </channels>
    </application>
  </system.runtime.remoting>
</configuration>

Мы тестировали все возможные комбинации протоколов и форматеров, но представим только наиболее интересные варианты. Это протокол TCP + Binary-форматер и протокол HTTP + SOAP-форматер. Первый вариант по всем признакам должен быть наиболее быстрым, последний – самым медленным из возможных. На рисунке 3 приведены результаты для модели ‘call’.


Рисунок 3. TCP/Binary и HTTP/SOAP ‘call’

Первым оказался DCOM, уступив TCP/Binary тесту только на 5-м методе. Из этого можно сделать вывод, что вызов методов в Remoting работает помедленнее, чем DCOM, но вот binary-форматер совсем неплохо справляется с большими объёмами данных и делает это даже лучше, чем стандартный COM-маршалинг. Связка HTTP + SOAP, как и положено, оказалась самой медленной. Столь резкое падение производительности при передаче массивов (4-й и 5-й методы) тоже вполне объяснимо. Дело в том, что SOAP передаёт массивы как набор отдельных xml-элементов, например:

<array>
  <item>1</item>
  <item>2</item>
  <item>3</item>
  <item>4</item>
  <item>5</item>
</array>

Безусловно, такой подход увеличивает объём передаваемых данных во много раз и существенно замедляет обмен. Этот факт как раз и наблюдается на приведённых диаграммах. Единственным исключением является передача массива байтов. В этом случае SOAP-форматер пакует массив как одну строку в формате base64.


Рисунок 4. TCP/Binary и HTTP/SOAP ‘connect’

Тест модели ‘connect’ (рисунок 4) оказался весьма интересным. Прежде всего обратите внимание на то, что в сравнении с предыдущей диаграммой Singleton- и Singlecall-варианты как для TCP, так и для HTTP остались на своём прежнем месте. В данном случае так и должно быть. В момент, когда клиент создаёт у себя экземпляр серверного объекта, создаётся только прокси-объект, объект на сервере всё ещё отсутствует. Фактическое создание объекта на сервере происходит только в момент первого вызова одного из методов объекта. К тому же для singleton-объекта на сервере не важно, сколько прокси-объектов создаёт клиент, один или тысячу, singleton всегда один, и все вызовы сервер переадресует ему. Singlecall-объекты тоже особо не озабочены подобными вопросами, сервер создаёт новую копию объекта при каждом вызове любого из его методов. Соответственно, разделение на условные модели, которые мы ввели, в данном случае не играют абсолютно никакой роли.

Исходя из этого можно сделать вывод, что модель активизации объектов в Remoting реализована эффективнее. Но если DCOM-объект используется в режиме ‘call’ (рисунок 3), вызов методов COM происходит значительно быстрее по уже установленному соединению.

Теперь перейдём к Client Activated объектам. Как мы уже упоминали ранее, временем жизни таких объектов управляют клиентские приложения и, соответственно, они во многом похожи на своих DCOM-собратьев. Так же, как и в случае DCOM, клиент создаёт объект на сервере в момент создания самого прокси-объекта. Разница состоит лишь в том, что COM-объект умирает сразу же, как только удаляется последняя ссылка на него, а Remoting-объект подчиняется другим законам, и его время жизни определяется... его временем жизни (lifetime), которое устанавливается по умолчанию в пять минут для вновь созданных объектов и продлевается ещё на две после каждого вызова любого из его методов.

Результат тестирования Client Activated объектов для протокола TCP (рисунок 4) очень близок к DCOM. Но скорее всего, это просто совпадение. В предыдущем тесте (рисунок 3) результат был таким же, как и для других Remoting-объектов, но там мы использовали модель ‘call’, то есть только один серверный объект. В этом же тесте мы создаём новый объект при каждом вызове. При этом, как мы уже знаем, клиент обращается к серверу не только в момент вызова, но и в момент создания объекта, что безусловно не ускоряет наш тест. Кроме того, поскольку время жизни объекта по умолчанию равно пяти минутам, к концу окончания теста у нас в памяти будут находиться все 10,000 только что созданных объектов.

И ещё один момент. Обратите внимание на результат тестирования Client Activated объектов для HTTP. Но не ищите его на диаграмме, его там нет, так как он просто не попал в приемлемый диапазон. Этот факт не понятен и необъясним. Можно было бы предположить, что при работе с объектом Remoting каким-либо образом сохраняет ссылку на форматер, в свою очередь SOAP-форматер для работы использует кучу памяти, на которую также всё ещё хранит ссылки, в результате память начинает забиваться ненужными объектами и т.д. и т.п. Но всё это только предположения. Понятно одно – Client Activated объекты не предназначены для столь интенсивного использования. Будем надеяться, что это просто баг, и Microsoft исправит его в ближайшее время.

IIS

Internet Information Server представляет собой готовый хост-сервер для .NET объектов. К его достоинствам можно отнести лёгкую настройку безопасности удалённых приложений и возможность изменения конфигурации приложения без перезапуска сервера. Главным недостатком, о котором мы уже упоминали, является возможность использования только более медленного протокола HTTP.


Рисунок 5. IIS/HTTP Binary и SOAP ‘call’

Рисунок 5 демонстрирует результаты тестирования ‘call’ модели объектов с использованием binary-форматера и IIS в качестве хост-сервера.

DCOM, как и ожидалось, опять оказался первым. Remoting не смог его догнать даже на 5-ом методе, где был лидером в предыдущем ‘call’ тесте (рисунок 3). SOAP-форматер вновь не продемонстрировал ничего хорошего, показав худшие результаты.

Пожалуй, наиболее интересным в данном тесте является появление на сцене ещё одного игрока – веб-сервиса. Функционально веб-сервисы похожи на singlecall-объекты, т.е. они так же создаются при каждом вызове любого из их методов. Но хост-сервером для них может выступать только интернет-сервер и в качестве формата передачи данных они используют протокол SOAP.

Несмотря на уже сложившееся общественное мнение о веб-сервисах как о медленной и, соответственно, слабо применимой в локальной сети технологии, наш веб-сервис показал себя совсем не плохо. Он, конечно, отстал от лидера (DCOM) более, чем на порядок, тем не менее это был не самый худший результат.


Рисунок 6. IIS/HTTP Binary и SOAP ‘connect’

В следующем же ‘connect’ тесте (рисунок 6) веб-сервис и вовсе был не хуже DCOM на первых трех методах. Причину же падения производительности SOAP-форматера на 4 и 5 методах мы уже разобрали.

Тесты Client Activated объектов опять оказались худшими, причём разрыв увеличился ещё больше. Что тут можно сказать? Только то, что парням из Рэдмонда ещё есть над чем работать.

Итого

Подведём итоги.


Рисунок 7. Результаты ‘call’ теста

В ‘call’ тесте лидером стал DCOM, что совсем неплохо для “старичка”. Remoting смог вырваться вперёд только при приёме/передаче массива строк, что говорит о хорошем качестве binary-форматера. Третьим был опять же binary-форматер, но только для варианта с IIS в качестве хост-сервера.

Интересна разница между TCP/Binary и IIS/HTTP/Binary вариантами. Если использовать абсолютные единицы, то у нас получится примерно 2.5 миллисекунды на вызов. Ровно столько у нас забрали IIS и протокол HTTP.

Далее в нашем тесте идёт веб-сервис, обогнав обоих своих SOAP-собратьев. При тестировании 5-го метода HTTP+SOAP без IIS был немного быстрее. Получается, что для больших объёмов передаваемых данных с использованием SOAP-форматера IIS вносит свои коррективы в результат. Интересно, почему?


Рисунок 8. Результаты ‘connect’ теста

В ‘connect’ тесте первым был вариант TCP с Binary-форматером. Фактически, в сравнении с предыдущим тестом он остался на том же месте. Далее следует IIS всё с тем же binary-форматером.

DCOM показал в общем зачёте третий результат, хотя веб-сервис при тестировании первых трех методов был даже чуть быстрей. Как мы уже говорили, по всей видимости, модель активизации объектов в Remoting реализована эффективнее чем в DCOM. Не исключено, что это происходит ещё и из-за того, что .NET клиент знает о создаваемом объекте гораздо больше, чем его DCOM-аналог. Недаром эти объекты называются well-known.

На последнем месте в нашем ‘connect’ тесте оказались оба Remoting-объекта, использующие SOAP-форматер, что, в общем-то, и не удивительно.

Итак, какие же мы можем сделать выводы?

DCOM всё ещё хорош в случае, когда используется постоянное соединение с объектом. Это совсем не означает, что у Remoting нет никаких шансов. Как мы уже говорили, архитектура Remoting очень гибка. Вполне возможно, что вскоре появятся ещё более быстрые протоколы и форматеры, которые превзойдут по производительности DCOM. Но пока мы имеет то, что имеем.

Интересно отметить также тот факт, что COM+-объект, написанный на C#, ничем не уступает своим DCOM-собратьям и демонстрирует идентичные результаты.

Remoting, напротив, показал себя хорошо в тестах, где не требуется постоянное соединение с объектом, и, по всей видимости, эта модель наиболее предпочтительна для приложений .NET. А вот к выбору Client Activated варианта нужно подходить осторожно.

В дополнение, учитывая тот факт, что развитие технологий стремительно вырывается из уз локальной сети, можно отметить что .NET предлагает вполне простые, удобные и эффективные решения для Интернет. Если вас не заботит совместимость с приложениями, написанными в других средах, то конфигурация IIS+HTTP+Binary позволить вам построить высокопроизводительную и надёжную систему.

Веб-сервисы можно использовать не только в Интернет, но и в локальной сети, например, для взаимодействия старого клиентского кода и нового серверного во время переходного периода. Очевидно, что при этом следует стараться делать меньшее количество вызовов и передавать как можно меньше данных.


Эта статья опубликована в журнале RSDN Magazine #2. Информацию о журнале можно найти здесь
    Сообщений 10    Оценка 245        Оценить