Анализ методов повышения эффективности распределенных приложений в стандарте CORBA.

Р.С. Шевченко

Институт программных систем НАН Украины, 03187, Киев, просп.
Глушкова 40, ruslan@shevchenko.kiev.ua

Работа посвящена способам создания эффективных распределенных производственных программных комплексов, основанных на стандарте CORBA. Дан анализ методов оптимизации распределенных приложений и предложена аналитическая модель для их производительности. Рассматриваются практические методы оптимизации приложений, типичные для промышленных систем, вместе с примерами их применения в системе GradDOC.

This work is devoted to ways of creating efficient distributed enterprise applications based on CORBA standard. An analysis of optimization methods of distributed applications is given and analytical model for their performance is proposed. Common practical optimization patterns and techniques being used in enterprise systems along with their application in the GradDOC system are presented.

Введение

CORBA (Common Object request Broker Architecture) - это стандарт, определяющий архитектуру распределенных объектов, с помощью которой организовывается взаимодействие между объектами в гетерогенных сетях [1].

Основными элементами модели CORBA являются:

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

Целью данной работы: является аналитический обзор методов построения эффективно работающих распределенных объектных приложений, пригодных для практического использования в промышленных программных комплексах. Работа основана на опыте создания промышленной системы GradDOC, разработанной в рамках объектной модели CORBA.

Единого определения понятия эффективности, пригодного для всех возможных применений, существовать не может, и в каждом конкретном случае это скорее комплекс критериев, зачастую противоречащих друг другу: Так, например, повышение времени реакции приложения в целом уменьшает общую скорость выполнения задачи, а улучшение использования процессорного времени как правило сопровождается накладными расходами на организацию передачи объемов данных. Набор критериев эффективности может быть разным для разного класса приложений (диалоговый и пакетный режим) и даже для одного приложения в разных условиях его использования. Можно сказать, что программный комплекс работает эффективно, если он отвечает некоторому набору требований (ограничений) на технические характеристики выполнения операций. В этой работе, в основном, мы будем рассматривать временные характеристики, главными из которых являются:

При анализе распределенных приложений (РП) следует учитывать особенности класса решаемых задач. Существуют некоторые характерные черты РП, которые оказывают существенное влияние на методы повышения эффективности:

1. Наличие многоуровневой схемы.

Как правило, РП строятся на основе стандартной многоуровневой схемы, с циркулированием информации от серверов верхнего уровня к набору промежуточных серверов с фиксированными потоками данных между серверами. Наиболее распространенной является 3-х уровневая архитектура, изображенная ниже на Рис. 1. , где на первом уровне находится система постоянного хранения (БД), на 2-м - сервер приложений, а на 3-м - клиентские приложения.

shem1.gif (1584 bytes)

Рис. 1. 3-уровневая архитектура распределенных приложений.

2. Параллельная работа нескольких клиентов.

Существует поток запросов к серверу, при этом сервер должен параллельно обрабатывать несколько запросов клиентов. В частности это означает, что каждая точка входа сервера не должна иметь внутренних блокировок; состояние сервера не должно зависит от состояния клиентов.

3. Наличие системы постоянного хранения.

Большинство потоков информации организованы по схеме [считывание - преобразование - обработка данных на клиенте] либо [прием данных от клиента - преобразование - запись на постоянный носитель]. В качестве системы постоянного хранения обычно выступает база данных (БД) (объектная или реляционная). При этом операции записи и чтения с БД - более медленные относительно скорости преобразования.

Анализ протоколов передачи сообщений в стандарте CORBA.

Как специфицировано в [1] CORBA-совместимые брокеры объектных запросов (ORB) работают в соответствии с архитектурой OMA [2].

(Рис 2)

shem2.gif (2741 bytes)

Рис. 2. Вызов удаленного метода в архитектуре ОМА

Эта архитектура накладывает следующие ограничения на характер взаимодействий клиента и сервера:

Структурой запроса клиента предусматривается следующие этапы выполнения запроса [2]:

  1. Кодирование (marshalling) запроса. На этом этапе набор параметров удаленного метода, вместе с ключом вызываемого объекта и именем метода преобразуется в поток байтов. В этот потоку байтов может включаться также и контекст запроса, который несет в себе информацию, общую для взаимодействий (о текущей транзакции или кодировке символов).
  2. Передача запроса. Поток байтов, полученный на предыдущем этапе, пересылается на удаленный компьютер с помощью низлежащих сетевых сервисов в смысле стека протоколов.
  3. Декодирование запроса. На компьютере-приемнике запроса полученный поток байтов декодируется в параметры, имя метода и ключ объекта.
  4. Определение объекта вызова. (hashing) Сервер по ключу объекта определяет соответствующий сервант, имеющийся в объектной модели языка сервера. При этом соответствие между сервантом и объектом не обязательно фиксировано в течение всего времени выполнения приложений.
  5. Возможная активация объекта вызова. Если сервант не существует в данном процессе, сервер, в зависимости от режима работы, может его активировать с помощью правил, заданных программистом.
  6. Определение вызываемого метода. По имени метода объекта ORB определяет машинный адрес соответствующего метода серванта.
  7. Вызов метода серванта. ORB вызывает соответствующий метод серванта с принятыми параметрами. Во время выполнения этого метода сервант может генерировать другие запросы.
  8. Кодирование результатов. Результаты метода серванта опять преобразуются в поток байт, для передачи обратно.
  9. Передача результата. Результат передается обратно на клиент, ORB подсистема клиента принимает запрос по тому же соединению, которое было установлено в начале запроса.
  10. Декодирование результатов. Результат запроса декодируется и помещается в среду клиентской программы.

Из этого перечня этапов можно сделать вывод, что эффективность брокера запросов во многом определяется набором следующих функций:

1. Функция кодирования/декодирования запроса.

Пусть - функция кодирования запроса x,- функция декодирования. Заметим, что:

где - конкатенация и ,- количество байтов, выравнивающих у до 4-х байт после х.

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

где - время, затрачиваемое на добавлений выравнивающих байт - мало, по сравнению с временем кодирования запросов.

Размер соответствующей GIOP последовательности также растет пропорционально размеру параметра, поэтому можно сказать, что:

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

Наконец, заметим, что время декодирования приблизительно равно времени кодирования.

2. Функция поиска в таблице объектов. Заметим, что основной параметр, от которого зависит эта функция - количество одновременно поддерживаемых объектов в системе. Пусть время выполнения этой функции:

(тут - объект, - размер таблицы активных объектов в системе.)

  1. Функция поиска в таблице методов:

(где - метод, - размер таблицы удаленных методов объекта .)

4. Функция активации объекта и вызова метода: , в которую входит время вызова сервера и инициализации, при необходимости, его потока исполнения. Эта функция зависит от загрузки операционной системы, стратегии обработки параллельных вызовов и от количества поддерживаемых соединений.

5. Функция сетевой среды, которая еще добавляет время на пересылку данных:

где - среднее время пересылки одного байта .

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

Пусть имеется программный код y=m(x), выполняемый в контексте c. Тогда приближенное время вызова в нашей модели можно определить, выполнив следующие шаги вычислений.

  1. Время кодирования запроса:
  2. Время пересылки запроса:
  3. Время декодирования:
  4. Время поиска объекта, соответствующего метода, активации объекта и собственно вызова метода:
  5. Время передачи ответа:
  6. Время декодирования ответа:

Суммируя время, полученное в -, получаем :

переобозначая константу , получаем:

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

Интересно сравнить эту оценку с основными тестами по критериям эффективности ORB, приведенными в [3]:

1. Время вызова операции (или частота вызовов в секунду) между одним клиентом и одним сервером. Этот тест измеряет производительность в модели взаимодействия типа "точка-точка". В нашей модели аналогичным критерием выступает измерение скорости передачи данных и скорость алгоритма маршаллинга.

2. Масштабируемость ORB, т.е. зависимость времени вызова операции от увеличения количества клиентов. Этот тест измеряет эффективность стратегии демультиплексирования вызовов и соответствует поведению функций в зависимости от количества клиентов.

3. Количества операций связывания в секунду. Этот тест измеряет время, за которое клиент получает объектную ссылку от сервера. Фактически это в точности проверка

4. Время и частота вызова операций между m клиентами и n серверами. Этот тест измеряет "смешанную" производительность системы. В нашей модели это зависимость от характеристик среды, таких как загрузка процессора. Заметим, что этот тест может трактоваться по разному, и давать разные результаты в зависимости от конфигурации системы.

5. Количество операций распределения памяти и объем выделяемой памяти для разных конфигураций. Это смешанный тест производительности брокера запросов и менеджера памяти операционной системы. Эти измерения имеют смысл для оценки масштабируемости приложений.

6. Те же измерения при смене модели параллельных вычислений на клиенте и сервере. Этот тест измеряет производительность таких моделей как поток-на-запрос (thread-per-request), пул потоков (thread-pool). Так как при смене модели параллельных вычислений меняется только , то этот тест дает нам относительное ранжирование в зависимости от выбранной модели.

7. Измерение степени закрузки ЦПУ и кеша процессора для разной загрузки и разной конфигурации моделей параллельной обработки. Эти измерения тоже имеют смысл для оценки масштабируемости приложений, которая остается за рамками данной работы.

Методы повышения эффективности распределенных приложений

Для получения эффективных распределенных приложений необходимо учитывать некоторые основные особенности распределенной объектной модели. Во-первых, это рекурсивная алгебра типов данных, т. е. существование композиционных типов данных. Из этого следует, что для любого вызова метода невозможно определить длину набора байтов соответствующего запросу, и. поэтому ORB должен динамически распределять память во время каждого вызова удаленного метода. Во-вторых, это наличие общих типов (Any, Object), из которого следует необходимость хранения и передачи метаинформации о типах объектов, которая может быть неизвестна во время компиляции программы. И в-третьих, это работа в гетерогенной среде, что влечет за собой необходимость поддержки машинно-независимого представления данных в двоичном потоке. Поэтому алгоритмы маршаллинга не сводятся к копированию параметров в одну область памяти.

Факторы среды выполнения CORBA-приложения, влияющие на его эффективность, включают: 1)скорость работы и объем памяти набора процессоров, на котором выполняется приложение и 2) скорость установления соединений и скорость передачи данных в среде передачи сообщений.

Естественно, для разных сред выполнения эффективным будет разный набор оптимизаций. К примеру, стандартный протокол CORBA GIOP (General InterORB protocol) ориентирован на высокоскоростные сети, где скорость установления соединения и передачи данных велика по сравнению с затратами времени на маршаллинг/демаршаллинг запросов. Поэтому в этом случае размер сообщения в несколько раз больше, чем объем данных, но сообщение построено так, чтобы обеспечить максимально быстрое кодирование/раскодирование на современных архитектурах (выравнивание данных на 4 байта, передачи вместе с запросом флага расположения байт в слове, избежание битовых операций). Поэтому GIOP/IIOP хорошо работает в высокоскоростных локальных сетях, но плохо применим для глобальных сетей и коммутируемых линий. В большинство доступных на рынке брокеров объектных запросов встроена возможность выбора транспортного протокола. Например, авторы ILU [4], (ORB, разработанная в лаборатории Xerox), реализовали протокол передачи данных основанный на HTTP-NG, где минимизируется длинна cообщения, а не скорость кодирования.

Ниже рассмотрены основные методы повышения эффективности распределенных приложений, охватывающие достаточно широкий круг вопросов оптимизации приложений по времени их выполнения. Они сформулированы как шаблоны проектирования (design patterns, [7]), выведенные из небольшого количества фундаментальных идей.

1. Минимизация количества вызовов. Применения составных операций

Пусть у нас есть код вида:

y1=o.req1(x1);

y2=o.req2(x2);

Тогда имеет смысл определить на объекте операцию req1_2(rq1,rq2) как композицию операций req1 и req2. Оценим Y эффект применения такого преобразования. Согласно время последовательного выполнения операций будет:

а после применения этого преобразования, получаем:

Учитывая, что время поиcка в таблице методов при добавлении метода изменяется мало, получаем что мы сэкономили на величину:

что составляет как раз время удаленного пустого вызова типа void f(void). При наличии связи между двумя операциями, например, if (o.m1(x)) o.m2(x); else o.m3(x); эффект от подобной оптимизации становится более ощутимым.

Наконец, особенно ценным является элиминация циклов типа:

for(ULong i=0; i<x.length();++i) r[i]=o.m(x[i]);

В случае работы с однородными массивами данных для каждой операции необходимо определить операцию Примеры этой оптимизации можно найти в CORBA Collection Services [16], где определены композитные операции для часто встречающихся последовательностей оперирования коллекциями.

Исходя из предыдущих выкладок, можно сформуоировать простое эмпирическое правило:

Если для выполнения какой-либо операции необходимо делать последовательность вызовов методов удаленного объекта, то необходимо определить эту последовательность вызовов на сервере как составную операцию.

Это правило применимо, когда и в текущем режиме вычислений являются главными составляющими. На практике это означает, что эту оптимизацию надо применять всегда, когда возможно межпроцессное взаимодействие.

2. Погружение интерпретирующего языка в серверный процесс

Суть метода состоит в том, что при последовательности вызовов удаленных методов, затраты на передачу данных могут превысить стоимость интерпретации некоторого языка вызовов этих методов. В таком случае в сервер встраивается интерпретатор встроенного языка, клиент передает на сервер предложения на этом языке и считывает результат интерпретации, а не вызывает их непосредственно. Это правило применимо, когда - основная составляющая времени выполнения запроса, т. е. при использовании СORBA в относительно низкоскоростных сетях, например Internet.

3. Разделение управляющей и информационной составляющих

Это преобразование применяется тогда, когда нам необходимо минимизировать время реакции программы. Пусть у нас есть операция m, выполняющаяся на сервере, которая требует большого объема вычислений и (или) передачи данных. Тогда разумно не блокировать интерфейс клиента на время выполнения этой операции, а определить операцию start_m на клиенте, которая создает параллельный поток выполнения, где собственно выполняется операция m и, при необходимости, выполняется уведомление о конце операции. Стандартный шаблон для преобразования кода, на языке Java приведен ниже:

Исходный код: y=o.m(x); ShowY(Y);

Результирующий код:

Thread m_th = new Thread() {
public void run()
{ y=o.m(x); invokeLater(showY(Y)); }
}; m_th.start();

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

4. Распараллеливание коммуникационной и вычислительной составляющей

Дальнейшее развитие этой идеи позволяет выделить в типичной структуре сервера приложений несколько потоков обмена данными и получить набор методов сокращения времени отклика. Исходя из свойств типичного сервера приложений, можно выделить следующие потоки данных (см. рисунок ниже): 1) поток управления между клиентом и сервером; 2) поток передачи собственно данных между клиентом и сервером; 3) поток передачи данных между сервером и системой постоянного хранения (обычно - реляционной БД) и 4) внутренние потоки для организации работы сервера - создание и удаление объектов.

Применяя к ним шаблоны проектирования, основанные на распараллеливании, получаем следующие приемы оптимизации:

4.1. Использование альтернативного транспорта для передачи потока данных

Пусть у нас есть поток данных, выражаемых операцией y=o.m(x); где объем передаваемых данных достаточно велик и ведется постоянно и применение GIOP кодирования для этих случаев - неэффективно. Типичный пример такой операции: передача потока видеоинформации. Схема проиллюстрирована на рис. 3

shem3.gif (3595 bytes)

Тогда разумно видоизменить стандартную схему выполнения запроса следующим образом:

y_reader = createYReader();
x_writer = createXWriter();
m_callback = createRetryCallback(o,m);
start_m(y_reader,x_writer,m_callback);

Область применения метода составляет случай, когда и существует постоянный поток данных. Классическим примером применения этого метода являются спецификации на передачу аудио и видео информации консорциума OMG. (т. н. A/V Streaming ), изложенные в [4], [5].

4.2. Перенос инициализации и закрытия серверных структур

Еще один источник применения оптимизации методом распараллеливания: вывести из времени ответа на запрос поток вычислений, необходимый для организации внутренних ресурсов сервера. Обычно это создание и удаление сервантов и сохранения их состояния в постоянной памяти. Этот тип оптимизации сокращает , и уменьшает время реакции за счет использования времени ожидания. Действительно, типичный профиль загрузки процессора при одном серверном процессе без этой выглядит, как нахождение в состоянии ожидания, с пиками активности в момент обращений клиентов. Применение этой оптимизации сокращает составляющую нашей формулы за счет загрузки процессоров в ранее неиспользованное время ожидания. Область применения метода включает случаи, когда необходимо повысить время реакции и загрузка сервера неравномерна. Другие примеры оптимизирующих преобразований, основанных на применении асинхронных событий, можно найти в [7],[8].

5. Применение собственного формата кодирования (custom marshalling [18])

Этот способ заключается в том, что бы вместо GIOP кодирования применять в "узких местах" системы свою кодировку, более эффективную чем GIOP для применяющегося в данном случае типа передаваемых данных, соответственно предоставляя библиотеки адаптера для кодирования и декодирования данных. Для CORBA транспорта можно представить закодированную последовательность байтов как неинтерпретируемую последовательность байтов в виде sequence<octet> с тем, что бы эти данные прозрачно проходили через слой GIOP. (рис 4).

6. Статическая оптимизация кодирования часто встречающихся типов данных

Другой способ использования схемы, приведенной на рис. 4 и уменьшения применение статического кодирования часто встречающихся типов данных или данных, специфических для приложения. Он должен быть реализован на уровне ORB. Заметим, что статическое кодирование не уменьшает объем передаваемых данных, следовательно оно применимо тогда, когда время кодирования/декодирования сравнимо с временем передачи данных - т. е. в высокоскоростных сетях при маломощных процессорах типа встроенных устройств.

7. Элиминация метаинформации

Протокол CORBA предоставляет богатые возможности для применения общих схем типа Factory. Но применять их следует с осторожностью, так как передача метаинформации связана с довольно большими накладными расходами. Поэтому в критических по производительности точках системы следует создавать специализации общих схем, в которых вся информация о типах является статической, с заменой DII-вызовов на DSI, общих типов Any на конкретные типы или объединения из конкретных типов, обращений к репозитарию интерфейсов на статический анализ.

Элиминация метаинформации также может быть произведена и на уровне ORB. GIOP протокол передает в запросе полное имя метода и полный тип объекта. Эта информация необходима для возможности динамических вызовов интерфейса клиента и сервера. Когда все интерфейсы и вызываемые методы известны на этапе компиляции, их можно заменить на более короткие идентификаторы, чем уменьшить размер запросов.

8. Сжатие GIOP

В случае, когда стоимость передачи данных, намного большей стоимости их сериализации, имеет смысл преобразование, обратное к (6), т. е. уменьшение за счет увеличения . В работе [9] одним из протоколов может быть т. н. "zipped GIOP", т. е. в процессе сериализации данных, после стандартного GIOP кодирования, к его результату применяется алгоритм компрессии.

9. Применение широковещательной асинхронной передачи данных

Теперь обратим внимание на такую особенность серверных приложений, как взаимодействие в одно и то же время с несколькими клиентами. Пусть несколько клиентов регистрируют обратный вызов (callback) на одно и то же событие. Тогда можно воспользоваться особенностями протоколов транспортного уровня, выделить класс событий, при наступлении которых необходимо уведомить всех зарезервированных клиентов. (широковещательных событий) и не информировать в сервере каждого клиента отдельно, а организовать отсылку сетевых пакетов по широковещательному (broadcast) адресу.

10. Выбор режима работы с потоками исполнения

Теперь вернемся к способам уменьшения . Рассмотрим подробнее механизм вызова серверного объекта, после того, как ORB декодировал запрос и локализовал объект и метод. После этого вызывается собственно сам процесс выполнения запроса. Потоки выполнения ORB и серванта не обязательно должны быть одними и теми же. Так мы приходим к понятию режимов работы с потоками исполнения (thread mode). Рассмотрим самые распространенные модели:

  1. Блокирующий режим. В самом простом случае ORB исполняет сервант в своем потоке выполнения. В этом случае работа ORB блокируется до момента возвращения из выполняемого метода серванта, поэтому в серванте невозможно выполнять другие запросы к той же ORB. С другой стороны - при вызове метода отсутствуют накладные расходы на переключение контекста. Этот режим следует применять только при взаимодействии типа точка-точка.
  2. Реактор. В этом случае есть поток исполнения, который управляем событиями. Обработка запроса ORB сводится к интерпретации контекста и записи в очередь событий тройки , поток исполнения извлекает их из очереди и исполняет. Заметим, что накладные расходы на переключение контекста также отсутствуют, но вызовы не блокируются; с другой стороны выполнение всех вызовов происходит строго последовательно. Этот режим можно применять, когда время обработки всех запросов очень небольшое.
  3. Один поток на один вызов (thread per request). В этом случае ORB порождает новый поток исполнения при каждом обращении, и утилизирует его после окончания исполнения метода серванта. Это самый медленный метод, но только с его помощью можно добиться гарантированного выполнения метода без ожидания.
  4. Пул потоков (Thread Pool). В начале работы ORB инициализируется фиксированное количество потоков исполнения. При вызове метода ORB либо выбирает свободный поток исполнения, либо ставит запись о вызове метода в очередь ожидания, как в модели реактора. Это хорошее промежуточное решение, которое следует применять в том случае, если известна приблизительная оценка загрузки сервера.

Подробное описание реализации этих моделей можно найти в [10]-[12]

11. Оптимизация совместного расположения (сollocation optimization [18])

Это оптимизация взаимодействия процессов, выполняющихся в одном адресном пространстве. В этом случае мы можем обойтись без процесса кодирования и передачи запроса. С другой стороны, заметим, что мы не можем заменить вызов метода объекта прямым вызовом, так как это может нарушить режим организации потоков исполнения. Подробное описание этих процессов на уровне построения ORB можно найти в [18], на уровне проектирования приложений можно использовать наличие оптимизация совместного расположения сервисов путем поддержки схемы совместной компиляции различных частей подсистемы, иногда бывает полезной включить копию некоторого критически используемого сервиса в каждую отдельно компилируемую подсистему программного комплекса.

Анализ оптимизаций, примененных в семействе программных комплексов GradDOC.

В качестве примера проведения анализа производительности CORBA-приложений и применения вышеописанных приемов повышения эффективности рассмотрим развитие комплекса программ GradDOC. [14].

Первоначально, для работы с Базой Данных в GRadDOC предполагалось использовать стандартные интерфейсы CORBA Query Service [15],[17] . В процессе реализации и внедрения был обнаружен ряд недостатков в оригинальном дизайне Query Service; был построен производный набор интерфейсов (UAKGQueryService) в котором применены следующие техники оптимизации:

Результаты применения оптимизирующих техник могут быть проиллюстрированны следующими фрагментами преобразований и результатами тестирования:

Эффект от элиминация метаниформации и замены обращения к репозитарию интерфейсов на статический анализ проследим на примере функции определения запроса. В CORBA Query Service она выглядит, как:

| struct { string name; any value} NVLPair;
| typedef sequence<NVLPair> ParameterList;
| typedef CORBA::InterfaceDef QLType
|interface QueryManager : QueryEvaluator {
|
| Query create (in string query, in QLType ql_type, in ParameterList params)
| raises(QueryTypeInvalid, QueryInvalid);
| :::..
| };

Назначение функции QueryManager::create заключается в том, что бы найти обработчик запроса определенного типа и проинициализировать запрос (т.е. создать сервант, соответствующий запросу Query).

В GradDOC, в результате оптимизирующих преобразований соответствующий запрос выглядит следующим образом:

| interface UAKGQueryManager: QueryManager, UAKGQueryEvaluator
| {
|
| UAKGQuery create_query(in string query, in string type, in unsigned long mode)
| raises(QueryTypeInvalid,QueryInvalid);
| ::
|
| };

Как видим, QLType, определенный ранее как динамическое определение интерфейса, что требовало обращения к интерфейс репозитарию во время его обработки, заменен на строку, а тип ParameterList заменен на целое. Элиминация вложенных удаленных вызовов привела к 10-кратному увеличению скорости создания ординарного запроса.

Еще более интересным представляются результаты применеия композитивных операций в совокупности с элиминацией информации на примере извлечения записей из БД и применение собственного формата кодирования:

В CosQuery Service записи извлекаются с помошью интерфейса Iterator:

| interface Iterator {
| any next () raises(IteratorInvalid, PositionInvalid);
| boolean more ();
| :..
| };

Типичный цикл извлечения записей в упрощенной форме выглядит следующим образом:

| while(!iterator->more()) {
| any_element = iterator->next();
| any_element >>= record;
| };

Эти вызовы заменяются на следующее обращение:

| interface UAKGQuery {
| :.
| RecordSeq fetch_records(in unsigned long numberOfRecords, out boolean more)
| raises(QueryProcessingError);
| OctSeq fetch_rc(in unsigned long numberOfRecords, out boolean more)
| raises(QueryProcessingError);
| :
| };

Как видим, тут за один вызов мы принимаем последовательность элементов и признак окончания записи. В первом методе мы принимаем последовательность записей, определенную в структуре типов CORBA, во втором - бинарную последовательность данных в собственном кодировании.

Интересно также рассмотреть зависимость скорости извлечения от количества записей, передаваемых за один раз.

Были проведен эксперимент по определению эффективности методов оптимизации: обработка одного и того же запроса к БД, на чтение 10000 записей была произведена разными способами, подробно описанными ниже, при этом в каждом случае анализировалось время передачи всей данных в зависимости от объема пакета данных, передаваемых при одном удаленном вызове.

Были протестированы следующие комбинации:

  1. Сервер(С++), клиент (С++), вызовы осуществляются в одном адресном пространстве, на одном компьютере последовательность записей читается с помошью стандартного CORBA типа.
  2. Сервер(С++), клиент (С++), вызовы осуществляются в одном адресном пространстве, последовательность записей читается с помошью применения собственного кодирования.
  3. Сервер(С++), клиент (С++), вызовы осуществляются между двумя разными процессами на одном компьютере посредством локального сетевого интерфейса, чтение последовательность записей с использованием CDR кодирования.
  4. Сервер(С++), клиент (С++), вызовы осуществляются между двумя разными процессами на одном компьютере посредством локального сетевого интерфейса, чтение последовательность записей с использованием собственного кодирования.
  5. Сервер(С++), клиент (С++), вызовы осуществляются в локальной сети (10Мб), чтение последовательность записей с использованием CDR кодирования.
  6. Сервер(С++), клиент (С++), вызовы осуществляются в локальной сети (10Мб), чтение последовательность записей с использованием собственного кодирования.
  7. Сервер(С++), клиент (Java), вызовы осуществляются в локальной сети (10Мб), чтение последовательность записей с использованием CDR кодирования.
  8. Сервер(С++), клиент (Java), вызовы осуществляются в локальной сети (10Мб), чтение последовательность записей с использованием собственного кодирования.

В качестве сервера использовался однопроцессорный Sun Enterprise 450 с процессором Ultra Spark II , под управлением операционной системы SunOS 2.6, в качестве клиента - PC совместимый компьютер с процессором Pentium 300 под управлением Windows NT.

Результаты экспериментов показаны на диаграмме 1

Здесь по оси X показано количество передаваемых записей за один удаленный вызов, по оси Y - время, необходимое для обработки запроса и передачи 10000 записей в миллисекундах.

Как видим, в случае межпроцессного взаимодействия только регулировка количества передаваемых данных в одном запросе ведет в четырехкратной кратной разнице в производительности. Также можно оценить эффективность применения собственного кодирования - как видно из диаграммы его эффективность сильно зависит от языка реализации. (от 20% в случае С++ до 80% в случае с Java). По-видимому, это связанно с особенностями автоматического распределения памяти в языке Java: GIOP значительно увеличивает размер передаваемых данных; в языке с отуствием контроля за распределением памяти, подсистема обработки сетевых запросов не может использовать собственный буфер для временного хранения, а должна при обработке каждого запроса запрашивать память у виртуальной машине, оставляя предыдущий пул сборщику мусора.

Выводы

Таким образом при проектировании распределенных объектных приложений можно и необходимо учитывать соображения эффективности программы в среде ее применения. При этом дизайн межобъектного интерфейса в распределенном приложении довольно сильно отличается от локального случая. В зависимости от избранных критериев можно выделить ряд методов повышения эффективности CORBA-комплексов, основанные на нескольких фундаментальных идеях: минимизация времени межобъектных вызовов для повышения скорости взаимодействия и применение асинхронного взаимодействия для повышения интерактивности.

Рассмотренные методы были применены на практике в системе обработки документооборота GradDOC и показали свою эффективность.

Литература

  1. Object Management Group. formal/98-12-01 The Common Object request Broker: Architecture & Specifications. CORBA/IIOP 2.3.1 , 712p. (ftp://ftp.omg.org/pub/formal/98-12-01.pdf)
  2. Object Management Group. OmaA Discussion of the Object Management Architecture January 1997, 44p (www.omg.org/library/oma/oma-all.pdf)
  3. Douglas C. Schmidt, Tim Harrison . Evaluating the Performance of OO Network Programming Toolkits, C++ Report, SIGS Vol. 8, No. 7, July/August, 1996, 8p (http://www.cs.wustl.edu/~schmidt/C++-report-doc-perf.ps.gz)
  4. Kristofer Maad. Efficient Bulk Transfers over CORBA. Uppsala University, Sveden, 1997 (http://www.docs.uu.se/~kmaad/streams.ps)
  5. Object Management Group. formal/98-06-06 CORBA Telecoms: Audio/Video Streams. 304p.
  6. Andreas Vogel. Effecient Data Transfer with CORBA. Java Report vol. 8 1998. (http://archive.javareport.com/9808/html/features/archive9806/corbatalk.html)
  7. Raphael C. Malveau and Thomas J. Mowbray CORBA Design Patterns. ISBN 0471158828, Wiley, 1997
  8. Steve Vinoski. Distributed Callbacks and Decoupled Communication in CORBA. SIGS C++ Report, Vol. 8, No. 10, October 1996.
  9. Bill Janssen, Mike Spreitzer, Dan Larner, Chris Jacobi. ILU Reference Manual. Park Xerox labs. 104p
  10. Steve Vinoski. Comparing Alternative Programming Techniques for Multi-threaded Servers -- the Thread-per-Session Concurrency Model, SIGS C++ Report, Vol 8. No 6. June 1996. (http://www.iona.com/hyplan/vinoski/col6.pdf)
  11. Steve Vinoski. Comparing Alternative Programming Techniques for Multi-threaded Servers -- the Thread-Pool Concurrency Model, SIGS C++ Report, Vol 8. No 4. April 1996. (http://www.iona.com/hyplan/vinoski/col5.pdf)
  12. Steve Vinoski. Comparing Alternative Programming Techniques for Multi-threaded Servers SIGS C++ Report, Vol 8. No 2. February 1996. (http://www.iona.com/hyplan/vinoski/col5.pdf)
  13. Douglas C. Schmidt, Chris Cleeland Applying Patterns to Develop Extensible ORB Middleware. Appeared in the IEEE Communications Magazine Special Issue on Design Patterns. 1999.
  14. Руслан Шевченко, Юлия Понятовская. Система управления документооборотом GradDOC: руководство пользователя. ГлавАПУ, 1998-2000.
  15. Object Management Group. formal/98-12-09. CORBA Services:Common Object Services Specification. (ftp://ftp.omg.org/pub/formal/98-12-09.pdf) 1312p
  16. Object Management Group. formal/97-12-24. CORBA Services: Collection Service Specification (ftp://ftp.omg.org/pub/formal/97-12-09.pdf)
  17. Object Management Group. formal/97-12-18. CORBA Services: Query Service Specification 24p (ftp://ftp.omg.org/pub/formal/97-12-18.pdf)
  18. Steve Vinoski. Collocation Optimizations for CORBA, C++ Report, SIGS, Vol. 11, No. 9, October, 1999